From 72a5cbbe81da15e65490b24182907afcbf208aa3 Mon Sep 17 00:00:00 2001 From: Gray Olson Date: Mon, 21 Sep 2020 13:07:48 -0700 Subject: [PATCH 001/719] Edit documentation for `std::{f32,f64}::mul_add`. Makes it more clear that a performance improvement is not guaranteed when using FMA, even when the target architecture supports it natively. --- library/std/src/f32.rs | 7 +++++-- library/std/src/f64.rs | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 59c2da5273bd..c97dac69634d 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -206,8 +206,11 @@ impl f32 { /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// 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. + /// Using `mul_add` *can* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and care must be taken not to overload the + /// architecture's available FMA units when using many FMA instructions + /// in a row, which can cause a stall and performance degradation. /// /// # Examples /// diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index bd094bdb55dc..1ef34409437f 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -206,8 +206,11 @@ impl f64 { /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// 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. + /// Using `mul_add` *can* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and care must be taken not to overload the + /// architecture's available FMA units when using many FMA instructions + /// in a row, which can cause a stall and performance degradation. /// /// # Examples /// From 92f7ba8446d397bb92f68ea1b45fd893d9410b86 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Oct 2020 00:34:15 +0200 Subject: [PATCH 002/719] Add WaitOnAddress/WakeByAddress API to sys::windows::c. --- library/std/src/sys/windows/c.rs | 15 +++++++++++++++ library/std/src/sys/windows/compat.rs | 1 + 2 files changed, 16 insertions(+) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 559c4dc9c7cd..6a088b91b514 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -1096,3 +1096,18 @@ compat_fn! { panic!("rwlocks not available") } } +compat_fn! { + "api-ms-win-core-synch-l1-2-0": + pub fn WaitOnAddress( + Address: LPVOID, + CompareAddress: LPVOID, + AddressSize: SIZE_T, + dwMilliseconds: DWORD + ) -> BOOL { + panic!("WaitOnAddress not available") + } + pub fn WakeByAddressSingle(Address: LPVOID) -> () { + // If this api is unavailable, there cannot be anything waiting, because + // WaitOnAddress would've panicked. So it's fine to do nothing here. + } +} diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index 3f25f05e1b9a..a5151ab620c0 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -34,6 +34,7 @@ macro_rules! compat_fn { )*) => ($( $(#[$meta])* pub mod $symbol { + #[allow(unused_imports)] use super::*; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::mem; From 7bfde778a419e0bd34c708ebe0c7eebab42f8637 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Oct 2020 00:34:15 +0200 Subject: [PATCH 003/719] Add Keyed Events API to sys::windows::c. --- library/std/src/sys/windows/c.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 6a088b91b514..33de486c309b 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -31,6 +31,8 @@ pub type WORD = u16; pub type CHAR = c_char; pub type ULONG_PTR = usize; pub type ULONG = c_ulong; +pub type NTSTATUS = LONG; +pub type ACCESS_MASK = DWORD; pub type LPBOOL = *mut BOOL; pub type LPBYTE = *mut BYTE; @@ -286,6 +288,8 @@ pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008; +pub const STATUS_SUCCESS: NTSTATUS = 0x00000000; + #[repr(C)] #[cfg(not(target_pointer_width = "64"))] pub struct WSADATA { @@ -1111,3 +1115,31 @@ compat_fn! { // WaitOnAddress would've panicked. So it's fine to do nothing here. } } + +compat_fn! { + "ntdll": + pub fn NtCreateKeyedEvent( + KeyedEventHandle: LPHANDLE, + DesiredAccess: ACCESS_MASK, + ObjectAttributes: LPVOID, + Flags: ULONG + ) -> NTSTATUS { + panic!("keyed events not available") + } + pub fn NtReleaseKeyedEvent( + EventHandle: HANDLE, + Key: LPVOID, + Alertable: BOOLEAN, + Timeout: PLARGE_INTEGER + ) -> NTSTATUS { + panic!("keyed events not available") + } + pub fn NtWaitForKeyedEvent( + EventHandle: HANDLE, + Key: LPVOID, + Alertable: BOOLEAN, + Timeout: PLARGE_INTEGER + ) -> NTSTATUS { + panic!("keyed events not available") + } +} From e9904342eb407209d6150d9df0cdf02e49069a8b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Oct 2020 00:34:59 +0200 Subject: [PATCH 004/719] Add fast futex-based thread parker for Windows. --- library/std/src/sys/windows/mod.rs | 1 + library/std/src/sys/windows/thread_parker.rs | 178 ++++++++++++++++++ .../std/src/sys_common/thread_parker/mod.rs | 2 + 3 files changed, 181 insertions(+) create mode 100644 library/std/src/sys/windows/thread_parker.rs diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 8178e6806b9b..1aece8632868 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -36,6 +36,7 @@ pub mod rwlock; pub mod thread; pub mod thread_local_dtor; pub mod thread_local_key; +pub mod thread_parker; pub mod time; cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs new file mode 100644 index 000000000000..68a060ba32d0 --- /dev/null +++ b/library/std/src/sys/windows/thread_parker.rs @@ -0,0 +1,178 @@ +use crate::convert::TryFrom; +use crate::ptr; +use crate::sync::atomic::{ + AtomicI8, AtomicUsize, + Ordering::{Acquire, Relaxed, Release}, +}; +use crate::sys::{c, dur2timeout}; +use crate::time::Duration; + +pub struct Parker { + state: AtomicI8, +} + +const PARKED: i8 = -1; +const EMPTY: i8 = 0; +const NOTIFIED: i8 = 1; + +// Notes about memory ordering: +// +// Memory ordering is only relevant for the relative ordering of operations +// between different variables. Even Ordering::Relaxed guarantees a +// monotonic/consistent order when looking at just a single atomic variable. +// +// So, since this parker is just a single atomic variable, we only need to look +// at the ordering guarantees we need to provide to the 'outside world'. +// +// The only memory ordering guarantee that parking and unparking provide, is +// that things which happened before unpark() are visible on the thread +// returning from park() afterwards. Otherwise, it was effectively unparked +// before unpark() was called while still consuming the 'token'. +// +// In other words, unpark() needs to synchronize with the part of park() that +// consumes the token and returns. +// +// This is done with a release-acquire synchronization, by using +// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using +// Ordering::Acquire when checking for this state in park(). +impl Parker { + pub fn new() -> Self { + Self { state: AtomicI8::new(EMPTY) } + } + + // Assumes this is only called by the thread that owns the Parker, + // which means that `self.state != PARKED`. + pub unsafe fn park(&self) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + loop { + // Wait for something to happen. + if c::WaitOnAddress::is_available() { + c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE); + } else { + c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); + } + // Change NOTIFIED=>EMPTY and return in that case. + if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED { + return; + } else { + // Spurious wake up. We loop to try again. + } + } + } + + // Assumes this is only called by the thread that owns the Parker, + // which means that `self.state != PARKED`. + pub unsafe fn park_timeout(&self, timeout: Duration) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + if c::WaitOnAddress::is_available() { + // Wait for something to happen, assuming it's still set to PARKED. + c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout)); + // Change NOTIFIED=>EMPTY and return in that case. + if self.state.swap(EMPTY, Acquire) == NOTIFIED { + return; + } else { + // Timeout or spurious wake up. + // We return either way, because we can't easily tell if it was the + // timeout or not. + } + } else { + // Need to wait for unpark() using NtWaitForKeyedEvent. + let handle = keyed_event_handle(); + + // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative values + // to indicate the monotonic clock. + let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) { + Ok(t) => -t, + Err(_) => i64::MIN, + }; + + // Wait for unpark() to produce this event. + if c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS { + // Awoken by another thread. + self.state.swap(EMPTY, Acquire); + } else { + // Not awoken by another thread (spurious or timeout). + if self.state.swap(EMPTY, Acquire) == NOTIFIED { + // If the state is NOTIFIED, we *just* missed an unpark(), + // which is now waiting for us to wait for it. + // Wait for it to consume the event and unblock it. + c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut()); + } + } + } + } + + pub fn unpark(&self) { + // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and + // wake the thread in the first case. + // + // Note that even NOTIFIED=>NOTIFIED results in a write. This is on + // purpose, to make sure every unpark() has a release-acquire ordering + // with park(). + if self.state.swap(NOTIFIED, Release) == PARKED { + if c::WakeByAddressSingle::is_available() { + unsafe { + c::WakeByAddressSingle(self.ptr()); + } + } else { + // If we run NtReleaseKeyedEvent before the waiting thread runs + // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up. + // If the waiting thread wakes up before we run NtReleaseKeyedEvent + // (e.g. due to a timeout), this blocks until we do wake up a thread. + // To prevent this thread from blocking indefinitely in that case, + // park_impl() will, after seeing the state set to NOTIFIED after + // waking up, call NtWaitForKeyedEvent again to unblock us. + unsafe { + c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); + } + } + } + } + + fn ptr(&self) -> c::LPVOID { + &self.state as *const _ as c::LPVOID + } +} + +fn keyed_event_handle() -> c::HANDLE { + const INVALID: usize = !0; + static HANDLE: AtomicUsize = AtomicUsize::new(INVALID); + match HANDLE.load(Relaxed) { + INVALID => { + let mut handle = c::INVALID_HANDLE_VALUE; + unsafe { + match c::NtCreateKeyedEvent( + &mut handle, + c::GENERIC_READ | c::GENERIC_WRITE, + ptr::null_mut(), + 0, + ) { + c::STATUS_SUCCESS => {} + r => panic!("Unable to create keyed event handle: error {}", r), + } + } + match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) { + Ok(_) => handle, + Err(h) => { + // Lost the race to another thread initializing HANDLE before we did. + // Closing our handle and using theirs instead. + unsafe { + c::CloseHandle(handle); + } + h as c::HANDLE + } + } + } + handle => handle as c::HANDLE, + } +} diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index 23c17c8e2cf2..92b17ef44309 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -2,6 +2,8 @@ cfg_if::cfg_if! { if #[cfg(any(target_os = "linux", target_os = "android"))] { mod futex; pub use futex::Parker; + } else if #[cfg(windows)] { + pub use crate::sys::thread_parker::Parker; } else { mod generic; pub use generic::Parker; From f47480b8acb41ff84b9069f689f64af7e3ce900d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Oct 2020 12:40:55 +0200 Subject: [PATCH 005/719] Improve windows thread parker. - Clarify memory ordering and spurious wakeups. --- library/std/src/sys/windows/thread_parker.rs | 58 ++++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index 68a060ba32d0..7697e6bb3be0 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -49,19 +49,26 @@ impl Parker { return; } - loop { - // Wait for something to happen. - if c::WaitOnAddress::is_available() { + if c::WaitOnAddress::is_available() { + loop { + // Wait for something to happen, assuming it's still set to PARKED. c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE); - } else { - c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); - } - // Change NOTIFIED=>EMPTY and return in that case. - if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED { - return; - } else { - // Spurious wake up. We loop to try again. + // Change NOTIFIED=>EMPTY but leave PARKED alone. + if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED { + // Actually woken up by unpark(). + return; + } else { + // Spurious wake up. We loop to try again. + } } + } else { + // Wait for unpark() to produce this event. + c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + // Note that we don't just write EMPTY, but use swap() to also + // include a acquire-ordered read to synchronize with unpark()'s + // release-ordered write. + self.state.swap(EMPTY, Acquire); } } @@ -77,9 +84,12 @@ impl Parker { if c::WaitOnAddress::is_available() { // Wait for something to happen, assuming it's still set to PARKED. c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout)); - // Change NOTIFIED=>EMPTY and return in that case. + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + // Note that we don't just write EMPTY, but use swap() to also + // include a acquire-ordered read to synchronize with unpark()'s + // release-ordered write. if self.state.swap(EMPTY, Acquire) == NOTIFIED { - return; + // Actually woken up by unpark(). } else { // Timeout or spurious wake up. // We return either way, because we can't easily tell if it was the @@ -97,17 +107,17 @@ impl Parker { }; // Wait for unpark() to produce this event. - if c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS { - // Awoken by another thread. - self.state.swap(EMPTY, Acquire); - } else { - // Not awoken by another thread (spurious or timeout). - if self.state.swap(EMPTY, Acquire) == NOTIFIED { - // If the state is NOTIFIED, we *just* missed an unpark(), - // which is now waiting for us to wait for it. - // Wait for it to consume the event and unblock it. - c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut()); - } + let unparked = c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS; + + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + let prev_state = self.state.swap(EMPTY, Acquire); + + if !unparked && prev_state == NOTIFIED { + // We were awoken by a timeout, not by unpark(), but the state + // was set to NOTIFIED, which means we *just* missed an + // unpark(), which is now blocked on us to wait for it. + // Wait for it to consume the event and unblock that thread. + c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut()); } } } From d1c139360ba7658532b80bb08c26c64c578b0cc7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Oct 2020 12:42:52 +0200 Subject: [PATCH 006/719] Fix typos in comments. --- library/std/src/sys/windows/thread_parker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index 7697e6bb3be0..c49b041c0255 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -66,7 +66,7 @@ impl Parker { c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); // Set the state back to EMPTY (from either PARKED or NOTIFIED). // Note that we don't just write EMPTY, but use swap() to also - // include a acquire-ordered read to synchronize with unpark()'s + // include an acquire-ordered read to synchronize with unpark()'s // release-ordered write. self.state.swap(EMPTY, Acquire); } @@ -86,7 +86,7 @@ impl Parker { c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout)); // Set the state back to EMPTY (from either PARKED or NOTIFIED). // Note that we don't just write EMPTY, but use swap() to also - // include a acquire-ordered read to synchronize with unpark()'s + // include an acquire-ordered read to synchronize with unpark()'s // release-ordered write. if self.state.swap(EMPTY, Acquire) == NOTIFIED { // Actually woken up by unpark(). From 43f844b84d1463907e9050fb3cd7f571f43e5e89 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Oct 2020 18:11:07 +0200 Subject: [PATCH 007/719] Add documentation to Windows thread parker implementation. --- library/std/src/sys/windows/thread_parker.rs | 61 +++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index c49b041c0255..8f45db78d2f5 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -1,3 +1,62 @@ +// Thread parker implementation for Windows. +// +// This uses WaitOnAddress and WakeByAddressSingle if available (Windows 8+). +// This modern API is exactly the same as the futex syscalls the Linux thread +// parker uses. When These APIs are available, the implementation of this +// thread parker matches the Linux thread parker exactly. +// +// However, when the modern API is not available, this implementation falls +// back to NT Keyed Events, which are similar, but have some important +// differences. These are available since Windows XP. +// +// WaitOnAddress first checks the state of the thread parker to make sure it no +// WakeByAddressSingle calls can be missed between updating the parker state +// and calling the function. +// +// NtWaitForKeyedEvent does not have this option, and unconditionally blocks +// without checking the parker state first. Instead, NtReleaseKeyedEvent +// (unlike WakeByAddressSingle) *blocks* until it woke up a thread waiting for +// it by NtWaitForKeyedEvent. This way, we can be sure no events are missed, +// but we need to be careful not to block unpark() if park_timeout() was woken +// up by a timeout instead of unpark(). +// +// Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a +// HANDLE (created with NtCreateKeyedEvent). This means that we can be sure +// a succesfully awoken park() was awoken by unpark() and not a +// NtReleaseKeyedEvent call from some other code, as these events are not only +// matched by the key (address of the parker (state)), but also by this HANDLE. +// We lazily allocate this handle the first time it is needed. +// +// The fast path (calling park() after unpark() was already called) and the +// possible states are the same for both implementations. This is used here to +// make sure the fast path does not even check which API to use, but can return +// right away, independent of the used API. Only the slow paths (which will +// actually block/wake a thread) check which API is available and have +// different implementations. +// +// Unfortunately, NT Keyed Events are an undocumented Windows API. However: +// - This API is relatively simple with obvious behaviour, and there are +// several (unofficial) articles documenting the details. [1] +// - `parking_lot` has been using this API for years (on Windows versions +// before Windows 8). [2] Many big projects extensively use parking_lot, +// such as servo and the Rust compiler itself. +// - It is the underlying API used by Windows SRW locks and Windows critical +// sections. [3] [4] +// - The source code of the implementations of Wine, ReactOs, and Windows XP +// are available and match the expected behaviour. +// - The main risk with an undocumented API is that it might change in the +// future. But since we only use it for older versions of Windows, that's not +// a problem. +// - Even if these functions do not block or wake as we expect (which is +// unlikely, see all previous points), this implementation would still be +// memory safe. The NT Keyed Events API is only used to sleep/block in the +// right place. +// +// [1]: http://www.locklessinc.com/articles/keyed_events/ +// [2]: https://github.com/Amanieu/parking_lot/commit/43abbc964e +// [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c +// [4]: Windows Internals, Part 1, ISBN 9780735671300 + use crate::convert::TryFrom; use crate::ptr; use crate::sync::atomic::{ @@ -34,7 +93,7 @@ const NOTIFIED: i8 = 1; // // This is done with a release-acquire synchronization, by using // Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using -// Ordering::Acquire when checking for this state in park(). +// Ordering::Acquire when reading this state in park() after waking up. impl Parker { pub fn new() -> Self { Self { state: AtomicI8::new(EMPTY) } From 13f166a9e63547689f866bdfdb2147f86fba915c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Oct 2020 18:40:06 +0200 Subject: [PATCH 008/719] Add comment documenting NtWaitForKeyedEvent's timeout interpretation. --- library/std/src/sys/windows/thread_parker.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index 8f45db78d2f5..3311627f1702 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -158,8 +158,10 @@ impl Parker { // Need to wait for unpark() using NtWaitForKeyedEvent. let handle = keyed_event_handle(); - // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative values - // to indicate the monotonic clock. + // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative + // values to indicate a relative time on the monotonic clock. + // This is documented here for the underlying KeWaitForSingleObject function: + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) { Ok(t) => -t, Err(_) => i64::MIN, From 03fb61cfefc1436ac9dc50d3fa7d7e60146beadd Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Oct 2020 18:46:57 +0200 Subject: [PATCH 009/719] Formatting. --- library/std/src/sys/windows/thread_parker.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index 3311627f1702..701c6e2e9bec 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -168,7 +168,8 @@ impl Parker { }; // Wait for unpark() to produce this event. - let unparked = c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS; + let unparked = + c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS; // Set the state back to EMPTY (from either PARKED or NOTIFIED). let prev_state = self.state.swap(EMPTY, Acquire); From a6d98d8ec918c7aa2b0712f1ff2c9b1db5924275 Mon Sep 17 00:00:00 2001 From: Gray Olson Date: Tue, 13 Oct 2020 11:03:31 -0700 Subject: [PATCH 010/719] generalize warning --- library/std/src/f32.rs | 7 +++---- library/std/src/f64.rs | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index c97dac69634d..9bebf68cf3d2 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -206,11 +206,10 @@ impl f32 { /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// - /// Using `mul_add` *can* be more performant than an unfused multiply-add if + /// Using `mul_add` *may* be more performant than an unfused multiply-add if /// the target architecture has a dedicated `fma` CPU instruction. However, - /// this is not always true, and care must be taken not to overload the - /// architecture's available FMA units when using many FMA instructions - /// in a row, which can cause a stall and performance degradation. + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. /// /// # Examples /// diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 1ef34409437f..860e461ec70a 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -206,11 +206,10 @@ impl f64 { /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// - /// Using `mul_add` *can* be more performant than an unfused multiply-add if + /// Using `mul_add` *may* be more performant than an unfused multiply-add if /// the target architecture has a dedicated `fma` CPU instruction. However, - /// this is not always true, and care must be taken not to overload the - /// architecture's available FMA units when using many FMA instructions - /// in a row, which can cause a stall and performance degradation. + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. /// /// # Examples /// From c2de8fe29443d8c9c70da66dee2c99d4c8d04930 Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Sun, 18 Oct 2020 15:45:09 -0400 Subject: [PATCH 011/719] Stabilize or_insert_with_key --- compiler/rustc_data_structures/src/sso/map.rs | 2 +- library/alloc/src/collections/btree/map/entry.rs | 3 +-- library/std/src/collections/hash/map.rs | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index fa510e58314a..7aca6fd93f2a 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -40,7 +40,7 @@ const SSO_ARRAY_SIZE: usize = 8; // into_keys/into_values (unstable) // all raw_entry-related // PartialEq/Eq (requires sorting the array) -// Entry::or_insert_with_key (unstable) +// Entry::or_insert_with_key // Vacant/Occupied entries and related // // FIXME: In HashMap most methods accepting key reference diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 73a0ca21f673..3ff648fe24cf 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -116,7 +116,6 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } } - #[unstable(feature = "or_insert_with_key", issue = "71024")] /// Ensures a value is in the entry by inserting, if empty, the result of the default function, /// which takes the key as its argument, and returns a mutable reference to the value in the /// entry. @@ -124,7 +123,6 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(or_insert_with_key)] /// use std::collections::BTreeMap; /// /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); @@ -134,6 +132,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 9); /// ``` #[inline] + #[stable(feature = "or_insert_with_key", since = "1.49.0")] pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 114707b639bc..3d130c1628e0 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2229,7 +2229,6 @@ impl<'a, K, V> Entry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(or_insert_with_key)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, usize> = HashMap::new(); @@ -2239,7 +2238,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 9); /// ``` #[inline] - #[unstable(feature = "or_insert_with_key", issue = "71024")] + #[stable(feature = "or_insert_with_key", since = "1.49.0")] pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), From 94d73d4403ef98b3b38b8e3035c2eac87fb900f9 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Tue, 3 Nov 2020 19:26:31 +0100 Subject: [PATCH 012/719] Refactor `parse_prefix` on Windows Refactor `get_first_two_components` to `get_next_component`. Fixes the following behaviour of `parse_prefix`: - series of separator bytes in a prefix are correctly parsed as a single separator - device namespace prefixes correctly recognize both `\\` and `/` as separators --- library/std/src/ffi/os_str.rs | 4 +- library/std/src/path/tests.rs | 8 +- library/std/src/sys/windows/path.rs | 172 +++++++++++++--------- library/std/src/sys/windows/path/tests.rs | 39 ++++- 4 files changed, 140 insertions(+), 83 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 7e7a28be2b0e..5d93016cadb3 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -667,10 +667,10 @@ impl OsStr { /// Gets the underlying byte representation. /// - /// Note: it is *crucial* that this API is private, to avoid + /// Note: it is *crucial* that this API is not externally public, to avoid /// revealing the internal, platform-specific encodings. #[inline] - fn bytes(&self) -> &[u8] { + pub(crate) fn bytes(&self) -> &[u8] { unsafe { &*(&self.inner as *const _ as *const [u8]) } } diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index ff94fda5a227..896d6c2a64c6 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -873,12 +873,12 @@ pub fn test_decompositions_windows() { ); t!("\\\\.\\foo/bar", - iter: ["\\\\.\\foo/bar", "\\"], + iter: ["\\\\.\\foo", "\\", "bar"], has_root: true, is_absolute: true, - parent: None, - file_name: None, - file_stem: None, + parent: Some("\\\\.\\foo/"), + file_name: Some("bar"), + file_stem: Some("bar"), extension: None ); diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index dda3ed68cfc9..c10c0df4a3a9 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -8,15 +8,12 @@ mod tests; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; -// The unsafety here stems from converting between `&OsStr` and `&[u8]` -// and back. This is safe to do because (1) we only look at ASCII -// contents of the encoding and (2) new &OsStr values are produced -// only from ASCII-bounded slices of existing &OsStr values. -fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { - unsafe { mem::transmute(s) } -} -unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - mem::transmute(s) +// Safety: `bytes` must be a valid wtf8 encoded slice +#[inline] +unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr { + // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8, + // which is compatible with &[u8]. + mem::transmute(bytes) } #[inline] @@ -29,79 +26,116 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'\\' } -// In most DOS systems, it is not possible to have more than 26 drive letters. -// See . -pub fn is_valid_drive_letter(disk: u8) -> bool { - disk.is_ascii_alphabetic() -} - pub fn parse_prefix(path: &OsStr) -> Option> { use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC}; - let path = os_str_as_u8_slice(path); + if let Some(path) = strip_prefix(path, r"\\") { + // \\ + if let Some(path) = strip_prefix(path, r"?\") { + // \\?\ + if let Some(path) = strip_prefix(path, r"UNC\") { + // \\?\UNC\server\share - // \\ - if let Some(path) = path.strip_prefix(br"\\") { - // \\?\ - if let Some(path) = path.strip_prefix(br"?\") { - // \\?\UNC\server\share - if let Some(path) = path.strip_prefix(br"UNC\") { - let (server, share) = match get_first_two_components(path, is_verbatim_sep) { - Some((server, share)) => unsafe { - (u8_slice_as_os_str(server), u8_slice_as_os_str(share)) - }, - None => (unsafe { u8_slice_as_os_str(path) }, OsStr::new("")), - }; - return Some(VerbatimUNC(server, share)); + let (server, path) = parse_next_component(path, true); + let (share, _) = parse_next_component(path, true); + + Some(VerbatimUNC(server, share)) } else { - // \\?\path - match path { - // \\?\C:\path - [c, b':', b'\\', ..] if is_valid_drive_letter(*c) => { - return Some(VerbatimDisk(c.to_ascii_uppercase())); - } - // \\?\cat_pics - _ => { - let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len()); - let slice = &path[..idx]; - return Some(Verbatim(unsafe { u8_slice_as_os_str(slice) })); - } + let (prefix, _) = parse_next_component(path, true); + + // in verbatim paths only recognize an exact drive prefix + if let Some(drive) = parse_drive_exact(prefix) { + // \\?\C: + Some(VerbatimDisk(drive)) + } else { + // \\?\prefix + Some(Verbatim(prefix)) } } - } else if let Some(path) = path.strip_prefix(b".\\") { + } else if let Some(path) = strip_prefix(path, r".\") { // \\.\COM42 - let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len()); - let slice = &path[..idx]; - return Some(DeviceNS(unsafe { u8_slice_as_os_str(slice) })); - } - match get_first_two_components(path, is_sep_byte) { - Some((server, share)) if !server.is_empty() && !share.is_empty() => { + let (prefix, _) = parse_next_component(path, false); + Some(DeviceNS(prefix)) + } else { + let (server, path) = parse_next_component(path, false); + let (share, _) = parse_next_component(path, false); + + if !server.is_empty() && !share.is_empty() { // \\server\share - return Some(unsafe { UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)) }); + Some(UNC(server, share)) + } else { + // no valid prefix beginning with "\\" recognized + None } - _ => {} } - } else if let [c, b':', ..] = path { + } else if let Some(drive) = parse_drive(path) { // C: - if is_valid_drive_letter(*c) { - return Some(Disk(c.to_ascii_uppercase())); - } + Some(Disk(drive)) + } else { + // no prefix + None } - None } -/// Returns the first two path components with predicate `f`. -/// -/// The two components returned will be use by caller -/// to construct `VerbatimUNC` or `UNC` Windows path prefix. -/// -/// Returns [`None`] if there are no separators in path. -fn get_first_two_components(path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { - let idx = path.iter().position(|&x| f(x))?; - // Panic safe - // The max `idx+1` is `path.len()` and `path[path.len()..]` is a valid index. - let (first, path) = (&path[..idx], &path[idx + 1..]); - let idx = path.iter().position(|&x| f(x)).unwrap_or(path.len()); - let second = &path[..idx]; - Some((first, second)) +// Parses a drive prefix, e.g. "C:" and "C:\whatever" +fn parse_drive(prefix: &OsStr) -> Option { + // In most DOS systems, it is not possible to have more than 26 drive letters. + // See . + fn is_valid_drive_letter(drive: &u8) -> bool { + drive.is_ascii_alphabetic() + } + + match prefix.bytes() { + [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()), + _ => None, + } +} + +// Parses a drive prefix exactly, e.g. "C:" +fn parse_drive_exact(prefix: &OsStr) -> Option { + // only parse two bytes: the drive letter and the drive separator + if prefix.len() == 2 { parse_drive(prefix) } else { None } +} + +fn strip_prefix<'a>(path: &'a OsStr, prefix: &str) -> Option<&'a OsStr> { + // `path` and `prefix` are valid wtf8 and utf8 encoded slices respectively, `path[prefix.len()]` + // is thus a code point boundary and `path[prefix.len()..]` is a valid wtf8 encoded slice. + match path.bytes().strip_prefix(prefix.as_bytes()) { + Some(path) => unsafe { Some(bytes_as_os_str(path)) }, + None => None, + } +} + +// Parse the next path component. +// +// Returns the next component and the rest of the path excluding the component and separator. +// Does not recognize `/` as a separator character if `verbatim` is true. +fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { + let separator = if verbatim { is_verbatim_sep } else { is_sep_byte }; + + match path.bytes().iter().position(|&x| separator(x)) { + Some(separator_start) => { + let mut separator_end = separator_start + 1; + + // a series of multiple separator characters is treated as a single separator, + // except in verbatim paths + while !verbatim && separator_end < path.len() && separator(path.bytes()[separator_end]) + { + separator_end += 1; + } + + let component = &path.bytes()[..separator_start]; + + // Panic safe + // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index. + let path = &path.bytes()[separator_end..]; + + // Safety: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') + // is encoded in a single byte, therefore `bytes[separator_start]` and + // `bytes[separator_end]` must be code point boundaries and thus + // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices. + unsafe { (bytes_as_os_str(component), bytes_as_os_str(path)) } + } + None => (path, OsStr::new("")), + } } diff --git a/library/std/src/sys/windows/path/tests.rs b/library/std/src/sys/windows/path/tests.rs index fbac1dc1ca17..9675da6ff883 100644 --- a/library/std/src/sys/windows/path/tests.rs +++ b/library/std/src/sys/windows/path/tests.rs @@ -1,21 +1,44 @@ use super::*; #[test] -fn test_get_first_two_components() { +fn test_parse_next_component() { assert_eq!( - get_first_two_components(br"server\share", is_verbatim_sep), - Some((&b"server"[..], &b"share"[..])), + parse_next_component(OsStr::new(r"server\share"), true), + (OsStr::new(r"server"), OsStr::new(r"share")) ); assert_eq!( - get_first_two_components(br"server\", is_verbatim_sep), - Some((&b"server"[..], &b""[..])) + parse_next_component(OsStr::new(r"server/share"), true), + (OsStr::new(r"server/share"), OsStr::new(r"")) ); assert_eq!( - get_first_two_components(br"\server\", is_verbatim_sep), - Some((&b""[..], &b"server"[..])) + parse_next_component(OsStr::new(r"server/share"), false), + (OsStr::new(r"server"), OsStr::new(r"share")) ); - assert_eq!(get_first_two_components(br"there are no separators here", is_verbatim_sep), None,); + assert_eq!( + parse_next_component(OsStr::new(r"server\"), false), + (OsStr::new(r"server"), OsStr::new(r"")) + ); + + assert_eq!( + parse_next_component(OsStr::new(r"\server\"), false), + (OsStr::new(r""), OsStr::new(r"server\")) + ); + + assert_eq!( + parse_next_component(OsStr::new(r"servershare"), false), + (OsStr::new(r"servershare"), OsStr::new("")) + ); + + assert_eq!( + parse_next_component(OsStr::new(r"server/\//\/\\\\/////\/share"), false), + (OsStr::new(r"server"), OsStr::new(r"share")) + ); + + assert_eq!( + parse_next_component(OsStr::new(r"server\\\\\\\\\\\\\\share"), true), + (OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share")) + ); } From ea1460773f1be2d0d717f6ab7609727e52ffa226 Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Mon, 26 Oct 2020 19:04:29 +0530 Subject: [PATCH 013/719] make MIR graphviz generation use gsgdt gsgdt [https://crates.io/crates/gsgdt] is a crate which provides an interface for stringly typed graphs. It also provides generation of graphviz dot format from said graph. --- Cargo.lock | 12 +- compiler/rustc_mir/Cargo.toml | 1 + compiler/rustc_mir/src/util/generic_graph.rs | 70 ++++++++ compiler/rustc_mir/src/util/graphviz.rs | 168 +++---------------- compiler/rustc_mir/src/util/mod.rs | 5 +- src/tools/tidy/src/deps.rs | 1 + 6 files changed, 109 insertions(+), 148 deletions(-) create mode 100644 compiler/rustc_mir/src/util/generic_graph.rs diff --git a/Cargo.lock b/Cargo.lock index 30b7628120bd..fb52f4201c06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1340,6 +1340,15 @@ dependencies = [ "regex", ] +[[package]] +name = "gsgdt" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cb4a3313cdc3c65906272ddd8987c7291ff6df4b5c9997c1232b6acd1ceab24" +dependencies = [ + "serde", +] + [[package]] name = "handlebars" version = "3.4.0" @@ -3923,6 +3932,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "either", + "gsgdt", "itertools 0.9.0", "polonius-engine", "regex", @@ -5252,7 +5262,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.9.0", + "parking_lot 0.11.0", "regex", "serde", "serde_json", diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml index 487668cfa110..28ba089d0622 100644 --- a/compiler/rustc_mir/Cargo.toml +++ b/compiler/rustc_mir/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [dependencies] either = "1.5.0" rustc_graphviz = { path = "../rustc_graphviz" } +gsgdt = "0.1.1" itertools = "0.9" tracing = "0.1" polonius-engine = "0.12.0" diff --git a/compiler/rustc_mir/src/util/generic_graph.rs b/compiler/rustc_mir/src/util/generic_graph.rs new file mode 100644 index 000000000000..df9f94016c8e --- /dev/null +++ b/compiler/rustc_mir/src/util/generic_graph.rs @@ -0,0 +1,70 @@ +use gsgdt::{Edge, Graph, GraphKind, Node, NodeStyle}; +use rustc_hir::def_id::DefId; +use rustc_index::vec::Idx; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +/// Convert an MIR function into a gsgdt Graph +pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>, subgraph: bool) -> Graph { + let def_id = body.source.def_id(); + let kind = if subgraph { GraphKind::Subgraph } else { GraphKind::Digraph }; + let def_name = graphviz_safe_def_name(def_id); + let graph_name = format!("Mir_{}", def_name); + let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + + // Nodes + let nodes: Vec = body + .basic_blocks() + .iter_enumerated() + .map(|(block, _)| bb_to_graph_node(block, body, dark_mode)) + .collect(); + + // Edges + let mut edges = Vec::new(); + for (source, _) in body.basic_blocks().iter_enumerated() { + let def_id = body.source.def_id(); + let terminator = body[source].terminator(); + let labels = terminator.kind.fmt_successor_labels(); + + for (&target, label) in terminator.successors().zip(labels) { + let src = node(def_id, source); + let trg = node(def_id, target); + edges.push(Edge::new(src, trg, label.to_string())); + } + } + + Graph::new(graph_name, kind, nodes, edges) +} + +fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node { + let def_id = body.source.def_id(); + let data = &body[block]; + let label = node(def_id, block); + + let (title, bgcolor) = if data.is_cleanup { + (format!("{} (cleanup)", block.index()), "lightblue") + } else { + let color = if dark_mode { "dimgray" } else { "gray" }; + (format!("{}", block.index()), color) + }; + + let style = NodeStyle { title_bg: Some(bgcolor.to_owned()), ..Default::default() }; + let mut stmts: Vec = data.statements.iter().map(|x| format!("{:?}", x)).collect(); + + // add the terminator to the stmts, gsgdt can print it out seperately + let mut terminator_head = String::new(); + data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); + stmts.push(terminator_head); + + Node::new(stmts, label, title, style) +} + +// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so +// it does not have to be user friendly. +pub fn graphviz_safe_def_name(def_id: DefId) -> String { + format!("{}_{}", def_id.krate.index(), def_id.index.index(),) +} + +fn node(def_id: DefId, block: BasicBlock) -> String { + format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id)) +} diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index 625f1a3e6844..c83a56c22aeb 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -1,11 +1,12 @@ +use gsgdt::GraphvizSettings; use rustc_graphviz as dot; use rustc_hir::def_id::DefId; -use rustc_index::vec::Idx; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use std::fmt::Debug; use std::io::{self, Write}; +use super::generic_graph::mir_fn_to_generic_graph; use super::pretty::dump_mir_def_ids; /// Write a graphviz DOT graph of a list of MIRs. @@ -32,12 +33,6 @@ where Ok(()) } -// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so -// it does not have to be user friendly. -pub fn graphviz_safe_def_name(def_id: DefId) -> String { - format!("{}_{}", def_id.krate.index(), def_id.index.index(),) -} - /// Write a graphviz DOT graph of the MIR. pub fn write_mir_fn_graphviz<'tcx, W>( tcx: TyCtxt<'tcx>, @@ -48,12 +43,6 @@ pub fn write_mir_fn_graphviz<'tcx, W>( where W: Write, { - let def_id = body.source.def_id(); - let kind = if subgraph { "subgraph" } else { "digraph" }; - let cluster = if subgraph { "cluster_" } else { "" }; // Prints a border around MIR - let def_name = graphviz_safe_def_name(def_id); - writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?; - // Global graph properties let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); let mut graph_attrs = vec![&font[..]]; @@ -67,168 +56,57 @@ where content_attrs.push(r#"fontcolor="white""#); } - writeln!(w, r#" graph [{}];"#, graph_attrs.join(" "))?; - let content_attrs_str = content_attrs.join(" "); - writeln!(w, r#" node [{}];"#, content_attrs_str)?; - writeln!(w, r#" edge [{}];"#, content_attrs_str)?; - // Graph label - write_graph_label(tcx, body, w)?; - - // Nodes - for (block, _) in body.basic_blocks().iter_enumerated() { - write_node(block, body, dark_mode, w)?; - } - - // Edges - for (source, _) in body.basic_blocks().iter_enumerated() { - write_edges(source, body, w)?; - } - writeln!(w, "}}") -} - -/// Write a graphviz HTML-styled label for the given basic block, with -/// all necessary escaping already performed. (This is suitable for -/// emitting directly, as is done in this module, or for use with the -/// LabelText::HtmlStr from librustc_graphviz.) -/// -/// `init` and `fini` are callbacks for emitting additional rows of -/// data (using HTML enclosed with `` in the emitted text). -pub fn write_node_label( - block: BasicBlock, - body: &Body<'_>, - dark_mode: bool, - w: &mut W, - num_cols: u32, - init: INIT, - fini: FINI, -) -> io::Result<()> -where - INIT: Fn(&mut W) -> io::Result<()>, - FINI: Fn(&mut W) -> io::Result<()>, -{ - let data = &body[block]; - - write!(w, r#""#)?; - - // Basic block number at the top. - let (blk, bgcolor) = if data.is_cleanup { - let color = if dark_mode { "royalblue" } else { "lightblue" }; - (format!("{} (cleanup)", block.index()), color) - } else { - let color = if dark_mode { "dimgray" } else { "gray" }; - (format!("{}", block.index()), color) + let label = get_graph_label(tcx, body); + let g = mir_fn_to_generic_graph(tcx, body, subgraph); + let settings = GraphvizSettings { + graph_attrs: Some(graph_attrs.join(" ")), + node_attrs: Some(content_attrs.join(" ")), + edge_attrs: Some(content_attrs.join(" ")), + graph_label: Some(label), }; - write!( - w, - r#""#, - attrs = r#"align="center""#, - colspan = num_cols, - blk = blk, - bgcolor = bgcolor - )?; - - init(w)?; - - // List of statements in the middle. - if !data.statements.is_empty() { - write!(w, r#"")?; - } - - // Terminator head at the bottom, not including the list of successor blocks. Those will be - // displayed as labels on the edges between blocks. - let mut terminator_head = String::new(); - data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); - write!(w, r#""#, dot::escape_html(&terminator_head))?; - - fini(w)?; - - // Close the table - write!(w, "
{blk}
"#)?; - for statement in &data.statements { - write!(w, "{}
", escape(statement))?; - } - write!(w, "
{}
") -} - -/// Write a graphviz DOT node for the given basic block. -fn write_node( - block: BasicBlock, - body: &Body<'_>, - dark_mode: bool, - w: &mut W, -) -> io::Result<()> { - let def_id = body.source.def_id(); - // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables. - write!(w, r#" {} [shape="none", label=<"#, node(def_id, block))?; - write_node_label(block, body, dark_mode, w, 1, |_| Ok(()), |_| Ok(()))?; - // Close the node label and the node itself. - writeln!(w, ">];") -} - -/// Write graphviz DOT edges with labels between the given basic block and all of its successors. -fn write_edges(source: BasicBlock, body: &Body<'_>, w: &mut W) -> io::Result<()> { - let def_id = body.source.def_id(); - let terminator = body[source].terminator(); - let labels = terminator.kind.fmt_successor_labels(); - - for (&target, label) in terminator.successors().zip(labels) { - let src = node(def_id, source); - let trg = node(def_id, target); - writeln!(w, r#" {} -> {} [label="{}"];"#, src, trg, label)?; - } - - Ok(()) + g.to_dot(w, &settings) } /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of /// all the variables and temporaries. -fn write_graph_label<'tcx, W: Write>( - tcx: TyCtxt<'tcx>, - body: &Body<'_>, - w: &mut W, -) -> io::Result<()> { +fn get_graph_label<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> String { let def_id = body.source.def_id(); + let mut label: Vec = Vec::new(); - write!(w, " label= 0 { - write!(w, ", ")?; + label.push(", ".to_owned()); } - write!(w, "{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))?; + label.push(format!("{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))); } - write!(w, ") -> {}", escape(&body.return_ty()))?; - write!(w, r#"
"#)?; + label.push(format!(") -> {}", escape(&body.return_ty()))); + label.push(r#"
"#.to_owned()); for local in body.vars_and_temps_iter() { let decl = &body.local_decls[local]; - write!(w, "let ")?; + label.push("let ".to_owned()); if decl.mutability == Mutability::Mut { - write!(w, "mut ")?; + label.push("mut ".to_owned()); } - write!(w, r#"{:?}: {};
"#, Place::from(local), escape(&decl.ty))?; + label.push(format!(r#"{:?}: {};
"#, Place::from(local), escape(&decl.ty))); } for var_debug_info in &body.var_debug_info { - write!( - w, + label.push(format!( r#"debug {} => {};
"#, var_debug_info.name, escape(&var_debug_info.place) - )?; + )); } - - writeln!(w, ">;") -} - -fn node(def_id: DefId, block: BasicBlock) -> String { - format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id)) + label.join("") } fn escape(t: &T) -> String { diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs index aaee0bc526db..58e0f908108e 100644 --- a/compiler/rustc_mir/src/util/mod.rs +++ b/compiler/rustc_mir/src/util/mod.rs @@ -8,6 +8,7 @@ mod alignment; pub mod collect_writes; mod find_self_call; pub(crate) mod generic_graphviz; +mod generic_graph; mod graphviz; pub(crate) mod pretty; pub(crate) mod spanview; @@ -15,6 +16,6 @@ pub(crate) mod spanview; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; pub use self::find_self_call::find_self_call; -pub use self::graphviz::write_node_label as write_graphviz_node_label; -pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz}; +pub use self::generic_graph::graphviz_safe_def_name; +pub use self::graphviz::write_mir_graphviz; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 057b0884e287..3aeb0b8c5b35 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -104,6 +104,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "getopts", "getrandom", "gimli", + "gsgdt", "hashbrown", "hermit-abi", "humantime", From 5b049e107bec04210b1ff0d48e3c66e25de1a598 Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Mon, 26 Oct 2020 23:03:23 +0530 Subject: [PATCH 014/719] write to a String instead to reduce churn --- compiler/rustc_mir/src/util/graphviz.rs | 35 +++++++++++++++---------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index c83a56c22aeb..8060eaab874a 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -57,7 +57,9 @@ where } // Graph label - let label = get_graph_label(tcx, body); + let mut label = String::from(""); + // FIXME: remove this unwrap + write_graph_label(tcx, body, &mut label).unwrap(); let g = mir_fn_to_generic_graph(tcx, body, subgraph); let settings = GraphvizSettings { graph_attrs: Some(graph_attrs.join(" ")), @@ -71,42 +73,47 @@ where /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of /// all the variables and temporaries. -fn get_graph_label<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> String { +fn write_graph_label<'tcx, W: std::fmt::Write>( + tcx: TyCtxt<'tcx>, + body: &Body<'_>, + w: &mut W, +) -> std::fmt::Result { let def_id = body.source.def_id(); - let mut label: Vec = Vec::new(); - label.push(format!("fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))); + write!(w, "fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?; // fn argument types. for (i, arg) in body.args_iter().enumerate() { if i > 0 { - label.push(", ".to_owned()); + write!(w, ", ")?; } - label.push(format!("{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))); + write!(w, "{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))?; } - label.push(format!(") -> {}", escape(&body.return_ty()))); - label.push(r#"
"#.to_owned()); + write!(w, ") -> {}", escape(&body.return_ty()))?; + write!(w, r#"
"#)?; for local in body.vars_and_temps_iter() { let decl = &body.local_decls[local]; - label.push("let ".to_owned()); + write!(w, "let ")?; if decl.mutability == Mutability::Mut { - label.push("mut ".to_owned()); + write!(w, "mut ")?; } - label.push(format!(r#"{:?}: {};
"#, Place::from(local), escape(&decl.ty))); + write!(w, r#"{:?}: {};
"#, Place::from(local), escape(&decl.ty))?; } for var_debug_info in &body.var_debug_info { - label.push(format!( + write!( + w, r#"debug {} => {};
"#, var_debug_info.name, escape(&var_debug_info.place) - )); + )?; } - label.join("") + + Ok(()) } fn escape(t: &T) -> String { From a4e94ec9b81c4d4c4c30103952804538e2a96acc Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Tue, 27 Oct 2020 20:14:38 +0530 Subject: [PATCH 015/719] update gsgdt --- Cargo.lock | 4 ++-- compiler/rustc_mir/Cargo.toml | 2 +- compiler/rustc_mir/src/util/generic_graph.rs | 7 +++---- compiler/rustc_mir/src/util/graphviz.rs | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb52f4201c06..e4b566e6690b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1342,9 +1342,9 @@ dependencies = [ [[package]] name = "gsgdt" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cb4a3313cdc3c65906272ddd8987c7291ff6df4b5c9997c1232b6acd1ceab24" +checksum = "a0d876ce7262df96262a2a19531da6ff9a86048224d49580a585fc5c04617825" dependencies = [ "serde", ] diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml index 28ba089d0622..b2af26575f1e 100644 --- a/compiler/rustc_mir/Cargo.toml +++ b/compiler/rustc_mir/Cargo.toml @@ -10,7 +10,7 @@ doctest = false [dependencies] either = "1.5.0" rustc_graphviz = { path = "../rustc_graphviz" } -gsgdt = "0.1.1" +gsgdt = "0.1.2" itertools = "0.9" tracing = "0.1" polonius-engine = "0.12.0" diff --git a/compiler/rustc_mir/src/util/generic_graph.rs b/compiler/rustc_mir/src/util/generic_graph.rs index df9f94016c8e..acaca435aa1d 100644 --- a/compiler/rustc_mir/src/util/generic_graph.rs +++ b/compiler/rustc_mir/src/util/generic_graph.rs @@ -1,13 +1,12 @@ -use gsgdt::{Edge, Graph, GraphKind, Node, NodeStyle}; +use gsgdt::{Edge, Graph, Node, NodeStyle}; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; /// Convert an MIR function into a gsgdt Graph -pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>, subgraph: bool) -> Graph { +pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph { let def_id = body.source.def_id(); - let kind = if subgraph { GraphKind::Subgraph } else { GraphKind::Digraph }; let def_name = graphviz_safe_def_name(def_id); let graph_name = format!("Mir_{}", def_name); let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; @@ -33,7 +32,7 @@ pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>, subgrap } } - Graph::new(graph_name, kind, nodes, edges) + Graph::new(graph_name, nodes, edges) } fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node { diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index 8060eaab874a..d81759267b25 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -60,14 +60,14 @@ where let mut label = String::from(""); // FIXME: remove this unwrap write_graph_label(tcx, body, &mut label).unwrap(); - let g = mir_fn_to_generic_graph(tcx, body, subgraph); + let g = mir_fn_to_generic_graph(tcx, body); let settings = GraphvizSettings { graph_attrs: Some(graph_attrs.join(" ")), node_attrs: Some(content_attrs.join(" ")), edge_attrs: Some(content_attrs.join(" ")), graph_label: Some(label), }; - g.to_dot(w, &settings) + g.to_dot(w, &settings, subgraph) } /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that From 86a7831f0b522e624574b440bc09b40a713dacbb Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Mon, 9 Nov 2020 23:32:08 +0530 Subject: [PATCH 016/719] formatting --- Cargo.lock | 2 +- compiler/rustc_mir/src/util/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4b566e6690b..4c4931676aad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5262,7 +5262,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.11.0", + "parking_lot 0.9.0", "regex", "serde", "serde_json", diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs index 58e0f908108e..b7b702431bc2 100644 --- a/compiler/rustc_mir/src/util/mod.rs +++ b/compiler/rustc_mir/src/util/mod.rs @@ -7,8 +7,8 @@ pub mod storage; mod alignment; pub mod collect_writes; mod find_self_call; -pub(crate) mod generic_graphviz; mod generic_graph; +pub(crate) mod generic_graphviz; mod graphviz; pub(crate) mod pretty; pub(crate) mod spanview; From 51ecb96252bbce159e70617da611017afb30eba8 Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Thu, 12 Nov 2020 13:17:43 +0530 Subject: [PATCH 017/719] add different color for cleanup nodes in dark mode --- compiler/rustc_mir/src/util/generic_graph.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/util/generic_graph.rs b/compiler/rustc_mir/src/util/generic_graph.rs index acaca435aa1d..6ce305a48211 100644 --- a/compiler/rustc_mir/src/util/generic_graph.rs +++ b/compiler/rustc_mir/src/util/generic_graph.rs @@ -41,7 +41,8 @@ fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node let label = node(def_id, block); let (title, bgcolor) = if data.is_cleanup { - (format!("{} (cleanup)", block.index()), "lightblue") + let color = if dark_mode { "royalblue" } else { "lightblue" }; + (format!("{} (cleanup)", block.index()), color) } else { let color = if dark_mode { "dimgray" } else { "gray" }; (format!("{}", block.index()), color) From 161300d41e7910b50db55b4025c66bc79c716ccd Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Fri, 13 Nov 2020 18:54:23 +0200 Subject: [PATCH 018/719] stabilize deque_range --- library/alloc/src/collections/vec_deque/mod.rs | 8 ++------ library/alloc/tests/lib.rs | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 1c183858e7a5..154746060542 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1080,8 +1080,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(deque_range)] - /// /// use std::collections::VecDeque; /// /// let v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); @@ -1093,7 +1091,7 @@ impl VecDeque { /// assert_eq!(all.len(), 3); /// ``` #[inline] - #[unstable(feature = "deque_range", issue = "74217")] + #[stable(feature = "deque_range", since = "1.50.0")] pub fn range(&self, range: R) -> Iter<'_, T> where R: RangeBounds, @@ -1117,8 +1115,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(deque_range)] - /// /// use std::collections::VecDeque; /// /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); @@ -1134,7 +1130,7 @@ impl VecDeque { /// assert_eq!(v, vec![2, 4, 12]); /// ``` #[inline] - #[unstable(feature = "deque_range", issue = "74217")] + #[stable(feature = "deque_range", since = "1.50.0")] pub fn range_mut(&mut self, range: R) -> IterMut<'_, T> where R: RangeBounds, diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index b7cc03f8eb99..b56437bd188f 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -16,7 +16,6 @@ #![feature(slice_ptr_get)] #![feature(split_inclusive)] #![feature(binary_heap_retain)] -#![feature(deque_range)] #![feature(inplace_iteration)] #![feature(iter_map_while)] #![feature(int_bits_const)] From 307c60843ce853cf6883f5330e71cde35838d78b Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 15 Nov 2020 22:34:23 +0100 Subject: [PATCH 019/719] Do not call super_rvalue if not needed --- compiler/rustc_mir/src/transform/instcombine.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index 59b7db243190..b36633fbfb32 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -81,7 +81,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { *rvalue = Rvalue::Use(Operand::Copy(place)); } - self.super_rvalue(rvalue, location) + // We do not call super_rvalue as we are not interested in any other parts of the tree } } @@ -285,7 +285,7 @@ impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { self.find_unneeded_equality_comparison(rvalue, location); - self.super_rvalue(rvalue, location) + // We do not call super_rvalue as we are not interested in any other parts of the tree } } From 3d5a1e330fb48c5f64b078cf755cbb44ee73343e Mon Sep 17 00:00:00 2001 From: Simon Vandel Sillesen Date: Sun, 15 Nov 2020 22:34:50 +0100 Subject: [PATCH 020/719] Only go through the body if something can be optimized --- compiler/rustc_mir/src/transform/instcombine.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index b36633fbfb32..04ea2bb542e8 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -29,8 +29,10 @@ impl<'tcx> MirPass<'tcx> for InstCombine { optimization_finder.optimizations }; - // Then carry out those optimizations. - MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body); + if !optimizations.is_empty() { + // Then carry out those optimizations. + MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body); + } } } @@ -296,3 +298,12 @@ struct OptimizationList<'tcx> { unneeded_equality_comparison: FxHashMap>, unneeded_deref: FxHashMap>, } + +impl<'tcx> OptimizationList<'tcx> { + fn is_empty(&self) -> bool { + self.and_stars.is_empty() + && self.arrays_lengths.is_empty() + && self.unneeded_equality_comparison.is_empty() + && self.unneeded_deref.is_empty() + } +} From a2f938ac52d8d1b3ee1cf94f18705e95f28ca0b8 Mon Sep 17 00:00:00 2001 From: oli Date: Thu, 19 Nov 2020 11:05:15 +0000 Subject: [PATCH 021/719] Document that heap allocations are not guaranteed to happen, even if explicitly performed in the code --- library/core/src/alloc/global.rs | 13 +++++++++++++ library/core/src/alloc/mod.rs | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index c198797e650f..65406125a3db 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -53,6 +53,19 @@ use crate::ptr; /// * `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. +/// +/// * You may not rely on allocations actually happening, even if there are explicit +/// heap allocations in the source. The optimizer may detect allocation/deallocation +/// pairs that it can instead move to stack allocations/deallocations and thus never +/// invoke the allocator here. +/// More concretely, the following code example is unsound, irrespective of whether your +/// custom allocator allows counting how many allocations have happened. +/// +/// ```rust,ignore +/// drop(Box::new(42)); +/// let number_of_heap_allocs = /* call private allocator API */; +/// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } +/// ``` #[stable(feature = "global_alloc", since = "1.28.0")] pub unsafe trait GlobalAlloc { /// Allocate memory as described by the given `layout`. diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index c61c19cc7d1d..47d5ad9ad560 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -94,6 +94,18 @@ pub unsafe trait AllocRef { /// The returned block may have a larger size than specified by `layout.size()`, and may or may /// not have its contents initialized. /// + /// Note that you may not rely on this method actually getting called, even if there are calls + /// to it in the source. The optimizer may detect allocation/deallocation pairs that it can + /// instead move to stack allocations/deallocations and thus never invoke the allocator here. + /// More concretely, the following code example is unsound, irrespective of whether your + /// custom allocator allows counting how many allocations have happened. + /// + /// ```rust,ignore + /// Global::dealloc(Global::alloc(some_layout)); + /// let number_of_heap_allocs = /* call private allocator API */; + /// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } + /// ``` + /// /// # Errors /// /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet From 173892c7765365ca47f920771ee7f743e2c4dfaa Mon Sep 17 00:00:00 2001 From: oli Date: Thu, 19 Nov 2020 11:09:10 +0000 Subject: [PATCH 022/719] Note that there are other optimizations than the one showcased --- library/core/src/alloc/global.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 65406125a3db..e6fe1e89c107 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -66,6 +66,12 @@ use crate::ptr; /// let number_of_heap_allocs = /* call private allocator API */; /// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } /// ``` +/// +/// Note that allocation/deallocation pairs being moved to the stack is not the only +/// optimization that can be applied. You may generally not rely on heap allocations +/// happening, if they can be removed without changing program behaviour. +/// Whether allocations happen or not is not part of the program behaviour, even if it +/// could be detected via an allocator that tracks allocations. #[stable(feature = "global_alloc", since = "1.28.0")] pub unsafe trait GlobalAlloc { /// Allocate memory as described by the given `layout`. From 3d1f6769066978946d381ca77e82e48b652bad65 Mon Sep 17 00:00:00 2001 From: oli Date: Thu, 19 Nov 2020 11:41:47 +0000 Subject: [PATCH 023/719] Fix tidy --- library/core/src/alloc/global.rs | 2 +- library/core/src/alloc/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index e6fe1e89c107..4922028eee2f 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -61,7 +61,7 @@ use crate::ptr; /// More concretely, the following code example is unsound, irrespective of whether your /// custom allocator allows counting how many allocations have happened. /// -/// ```rust,ignore +/// ```text /// drop(Box::new(42)); /// let number_of_heap_allocs = /* call private allocator API */; /// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 47d5ad9ad560..d174842bcbf0 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -100,7 +100,7 @@ pub unsafe trait AllocRef { /// More concretely, the following code example is unsound, irrespective of whether your /// custom allocator allows counting how many allocations have happened. /// - /// ```rust,ignore + /// ```text /// Global::dealloc(Global::alloc(some_layout)); /// let number_of_heap_allocs = /* call private allocator API */; /// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } From dfca61a4c22d3cd1bc6b7a493de6f6763223b71f Mon Sep 17 00:00:00 2001 From: oli Date: Thu, 19 Nov 2020 14:28:28 +0000 Subject: [PATCH 024/719] Elaborate on side effects --- library/core/src/alloc/global.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 4922028eee2f..89d85bf291e0 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -71,7 +71,8 @@ use crate::ptr; /// optimization that can be applied. You may generally not rely on heap allocations /// happening, if they can be removed without changing program behaviour. /// Whether allocations happen or not is not part of the program behaviour, even if it -/// could be detected via an allocator that tracks allocations. +/// could be detected via an allocator that tracks allocations by printing or otherwise +/// having side effects. #[stable(feature = "global_alloc", since = "1.28.0")] pub unsafe trait GlobalAlloc { /// Allocate memory as described by the given `layout`. From 58d62b83711b5f1401509b97a1340495f9907134 Mon Sep 17 00:00:00 2001 From: oli Date: Thu, 19 Nov 2020 14:57:30 +0000 Subject: [PATCH 025/719] Inform tidy about the reason for the ignored rust code --- library/core/src/alloc/global.rs | 2 +- library/core/src/alloc/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 89d85bf291e0..1ecf6abc7546 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -61,7 +61,7 @@ use crate::ptr; /// More concretely, the following code example is unsound, irrespective of whether your /// custom allocator allows counting how many allocations have happened. /// -/// ```text +/// ```rust,ignore (unsound and has placeholders) /// drop(Box::new(42)); /// let number_of_heap_allocs = /* call private allocator API */; /// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index d174842bcbf0..1616d8fab212 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -100,7 +100,7 @@ pub unsafe trait AllocRef { /// More concretely, the following code example is unsound, irrespective of whether your /// custom allocator allows counting how many allocations have happened. /// - /// ```text + /// ```rust,ignore (unsound and has placeholders) /// Global::dealloc(Global::alloc(some_layout)); /// let number_of_heap_allocs = /* call private allocator API */; /// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } From 3ac1df8b99341fa781aead2f3eeef955309a12f3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Oct 2020 13:53:54 +0200 Subject: [PATCH 026/719] consider assignments of union field of ManuallyDrop type safe --- compiler/rustc_middle/src/mir/query.rs | 6 +-- .../rustc_mir/src/transform/check_unsafety.rs | 53 ++++++++++--------- src/test/ui/union/union-unsafe.rs | 6 +-- src/test/ui/union/union-unsafe.stderr | 26 +-------- 4 files changed, 35 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index db0056e482be..03faef4d9fa2 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -46,7 +46,7 @@ pub enum UnsafetyViolationDetails { UseOfMutableStatic, UseOfExternStatic, DerefOfRawPointer, - AssignToNonCopyUnionField, + AssignToDroppingUnionField, AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, @@ -94,8 +94,8 @@ impl UnsafetyViolationDetails { "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \ and cause data races: all of these are undefined behavior", ), - AssignToNonCopyUnionField => ( - "assignment to non-`Copy` union field", + AssignToDroppingUnionField => ( + "assignment to union field that needs dropping", "the previous content of the field will be dropped, which causes undefined \ behavior if the field was not properly initialized", ), diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index acec3e8f82f4..fdc033f9eb3f 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -235,37 +235,40 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { UnsafetyViolationKind::GeneralAndConstFn, UnsafetyViolationDetails::DerefOfRawPointer, ), - ty::Adt(adt, _) => { - if adt.is_union() { - if context == PlaceContext::MutatingUse(MutatingUseContext::Store) - || context == PlaceContext::MutatingUse(MutatingUseContext::Drop) - || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) - { - let elem_ty = match elem { - ProjectionElem::Field(_, ty) => ty, - _ => span_bug!( - self.source_info.span, - "non-field projection {:?} from union?", - place - ), - }; - if !elem_ty.is_copy_modulo_regions( + ty::Adt(adt, _) if adt.is_union() => { + if context == PlaceContext::MutatingUse(MutatingUseContext::Store) + || context == PlaceContext::MutatingUse(MutatingUseContext::Drop) + || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) + { + let elem_ty = match elem { + ProjectionElem::Field(_, ty) => ty, + _ => span_bug!( + self.source_info.span, + "non-field projection {:?} from union?", + place + ), + }; + let manually_drop = elem_ty + .ty_adt_def() + .map_or(false, |adt_def| adt_def.is_manually_drop()); + let nodrop = manually_drop + || elem_ty.is_copy_modulo_regions( self.tcx.at(self.source_info.span), self.param_env, - ) { - self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, - UnsafetyViolationDetails::AssignToNonCopyUnionField, - ) - } else { - // write to non-move union, safe - } - } else { + ); + if !nodrop { self.require_unsafe( UnsafetyViolationKind::GeneralAndConstFn, - UnsafetyViolationDetails::AccessToUnionField, + UnsafetyViolationDetails::AssignToDroppingUnionField, ) + } else { + // write to non-drop union field, safe } + } else { + self.require_unsafe( + UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationDetails::AccessToUnionField, + ) } } _ => {} diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 10f0c467560f..9810ed75d591 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -18,7 +18,7 @@ union U4 { fn generic_noncopy() { let mut u3 = U3 { a: ManuallyDrop::new(T::default()) }; - u3.a = ManuallyDrop::new(T::default()); //~ ERROR assignment to non-`Copy` union field is unsafe + u3.a = ManuallyDrop::new(T::default()); // OK (assignment does not drop) *u3.a = T::default(); //~ ERROR access to union field is unsafe } @@ -41,7 +41,7 @@ fn main() { // let U1 { .. } = u1; // OK let mut u2 = U2 { a: ManuallyDrop::new(String::from("old")) }; // OK - u2.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union + u2.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop) *u2.a = String::from("new"); //~ ERROR access to union field is unsafe let mut u3 = U3 { a: ManuallyDrop::new(0) }; // OK @@ -49,6 +49,6 @@ fn main() { *u3.a = 1; //~ ERROR access to union field is unsafe let mut u3 = U3 { a: ManuallyDrop::new(String::from("old")) }; // OK - u3.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union + u3.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop) *u3.a = String::from("new"); //~ ERROR access to union field is unsafe } diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr index b50d9e175065..5b3a58814a93 100644 --- a/src/test/ui/union/union-unsafe.stderr +++ b/src/test/ui/union/union-unsafe.stderr @@ -1,11 +1,3 @@ -error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:21:5 - | -LL | u3.a = ManuallyDrop::new(T::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:22:6 | @@ -46,14 +38,6 @@ LL | if let U1 { a: 12 } = u1 {} | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:44:5 - | -LL | u2.a = ManuallyDrop::new(String::from("new")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:45:6 | @@ -70,14 +54,6 @@ LL | *u3.a = 1; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:52:5 - | -LL | u3.a = ManuallyDrop::new(String::from("new")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:53:6 | @@ -86,6 +62,6 @@ LL | *u3.a = String::from("new"); | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 11 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0133`. From 64856e29c1c780117348c196e05902476251bc92 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 Oct 2020 21:12:32 +0200 Subject: [PATCH 027/719] adjust union access unsafety check logic to take into account Deref and the actual type of the assignment --- .../rustc_mir/src/transform/check_unsafety.rs | 35 +++--- src/test/ui/union/union-unsafe.rs | 21 ++++ src/test/ui/union/union-unsafe.stderr | 110 +++++++++++------- 3 files changed, 108 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index fdc033f9eb3f..e78f8d4c901d 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -190,7 +190,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } - for (i, elem) in place.projection.iter().enumerate() { + for (i, _elem) in place.projection.iter().enumerate() { let proj_base = &place.projection[..i]; if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { @@ -236,23 +236,28 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { UnsafetyViolationDetails::DerefOfRawPointer, ), ty::Adt(adt, _) if adt.is_union() => { - if context == PlaceContext::MutatingUse(MutatingUseContext::Store) + let assign_to_field = context + == PlaceContext::MutatingUse(MutatingUseContext::Store) || context == PlaceContext::MutatingUse(MutatingUseContext::Drop) - || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) - { - let elem_ty = match elem { - ProjectionElem::Field(_, ty) => ty, - _ => span_bug!( - self.source_info.span, - "non-field projection {:?} from union?", - place - ), - }; - let manually_drop = elem_ty + || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput); + // If there is a `Deref` further along the projection chain, this is *not* an + // assignment to a union field. In that case the union field is just read to + // obtain the pointer/reference. + let assign_to_field = assign_to_field + && !place.projection[i..] + .iter() + .any(|elem| matches!(elem, ProjectionElem::Deref)); + // If this is just an assignment, determine if the assigned type needs dropping. + if assign_to_field { + // We have to check the actual type of the assignment, as that determines if the + // old value is being dropped. + let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; + // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. + let manually_drop = assigned_ty .ty_adt_def() .map_or(false, |adt_def| adt_def.is_manually_drop()); let nodrop = manually_drop - || elem_ty.is_copy_modulo_regions( + || assigned_ty.is_copy_modulo_regions( self.tcx.at(self.source_info.span), self.param_env, ); @@ -260,7 +265,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.require_unsafe( UnsafetyViolationKind::GeneralAndConstFn, UnsafetyViolationDetails::AssignToDroppingUnionField, - ) + ); } else { // write to non-drop union field, safe } diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 9810ed75d591..9c7ed1f7bfc3 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -1,4 +1,6 @@ +#![feature(untagged_unions)] use std::mem::ManuallyDrop; +use std::cell::RefCell; union U1 { a: u8 @@ -16,6 +18,25 @@ union U4 { a: T } +union URef { + p: &'static mut i32, +} + +union URefCell { // field that does not drop but is not `Copy`, either + a: (RefCell, i32), +} + +fn deref_union_field(mut u: URef) { + // Not an assignment but an access to the union field! + *(u.p) = 13; //~ ERROR access to union field is unsafe +} + +fn assign_noncopy_union_field(mut u: URefCell) { + u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that needs dropping + u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that needs dropping + u.a.1 = 1; // OK +} + fn generic_noncopy() { let mut u3 = U3 { a: ManuallyDrop::new(T::default()) }; u3.a = ManuallyDrop::new(T::default()); // OK (assignment does not drop) diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr index 5b3a58814a93..f80d4394f842 100644 --- a/src/test/ui/union/union-unsafe.stderr +++ b/src/test/ui/union/union-unsafe.stderr @@ -1,67 +1,91 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:22:6 + --> $DIR/union-unsafe.rs:31:5 + | +LL | *(u.p) = 13; + | ^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: assignment to union field that needs dropping is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:35:5 + | +LL | u.a = (RefCell::new(0), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that needs dropping + | + = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized + +error[E0133]: assignment to union field that needs dropping is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:36:5 + | +LL | u.a.0 = RefCell::new(0); + | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that needs dropping + | + = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:43:6 | LL | *u3.a = T::default(); | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:28:6 - | -LL | *u3.a = T::default(); - | ^^^^ access to union field - | - = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior - -error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:36:13 - | -LL | let a = u1.a; - | ^^^^ access to union field - | - = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior - -error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:39:14 - | -LL | let U1 { a } = u1; - | ^ access to union field - | - = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior - -error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:20 - | -LL | if let U1 { a: 12 } = u1 {} - | ^^ access to union field - | - = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior - -error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:45:6 - | -LL | *u2.a = String::from("new"); - | ^^^^ access to union field - | - = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:49:6 | +LL | *u3.a = T::default(); + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:57:13 + | +LL | let a = u1.a; + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:60:14 + | +LL | let U1 { a } = u1; + | ^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:61:20 + | +LL | if let U1 { a: 12 } = u1 {} + | ^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:66:6 + | +LL | *u2.a = String::from("new"); + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:70:6 + | LL | *u3.a = 1; | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:53:6 + --> $DIR/union-unsafe.rs:74:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 8 previous errors +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0133`. From 63bdb3ac0948683fe7548680d3b78bb5d8b32076 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Oct 2020 19:35:01 +0100 Subject: [PATCH 028/719] improve formatting --- compiler/rustc_mir/src/transform/check_unsafety.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index e78f8d4c901d..e90d5149c2f1 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -236,10 +236,14 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { UnsafetyViolationDetails::DerefOfRawPointer, ), ty::Adt(adt, _) if adt.is_union() => { - let assign_to_field = context - == PlaceContext::MutatingUse(MutatingUseContext::Store) - || context == PlaceContext::MutatingUse(MutatingUseContext::Drop) - || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput); + let assign_to_field = matches!( + context, + PlaceContext::MutatingUse( + MutatingUseContext::Store + | MutatingUseContext::Drop + | MutatingUseContext::AsmOutput + ) + ); // If there is a `Deref` further along the projection chain, this is *not* an // assignment to a union field. In that case the union field is just read to // obtain the pointer/reference. From af309cc2d93ce1e8e57cedffbfc35f9df040376a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 08:57:57 +0100 Subject: [PATCH 029/719] needs -> might need --- compiler/rustc_middle/src/mir/query.rs | 2 +- src/test/ui/union/union-unsafe.rs | 4 ++-- src/test/ui/union/union-unsafe.stderr | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 03faef4d9fa2..89a93096f1c2 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -95,7 +95,7 @@ impl UnsafetyViolationDetails { and cause data races: all of these are undefined behavior", ), AssignToDroppingUnionField => ( - "assignment to union field that needs dropping", + "assignment to union field that might need dropping", "the previous content of the field will be dropped, which causes undefined \ behavior if the field was not properly initialized", ), diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 9c7ed1f7bfc3..6adf0ac59b93 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -32,8 +32,8 @@ fn deref_union_field(mut u: URef) { } fn assign_noncopy_union_field(mut u: URefCell) { - u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that needs dropping - u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that needs dropping + u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that might need dropping + u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that might need dropping u.a.1 = 1; // OK } diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr index f80d4394f842..a25c09144f74 100644 --- a/src/test/ui/union/union-unsafe.stderr +++ b/src/test/ui/union/union-unsafe.stderr @@ -6,19 +6,19 @@ LL | *(u.p) = 13; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that needs dropping is unsafe and requires unsafe function or block +error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:35:5 | LL | u.a = (RefCell::new(0), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that needs dropping + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized -error[E0133]: assignment to union field that needs dropping is unsafe and requires unsafe function or block +error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:36:5 | LL | u.a.0 = RefCell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that needs dropping + | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized From df1c55a47434b2d79dea43673a3a97b9e955ce82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Nov 2020 11:50:15 +0100 Subject: [PATCH 030/719] add function to iterate through all sub-places, and add PlaceRef::ty --- compiler/rustc_middle/src/mir/mod.rs | 9 +++++++++ compiler/rustc_middle/src/mir/tcx.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 9289d4708de1..4a7d4dab5079 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1741,6 +1741,15 @@ impl<'tcx> Place<'tcx> { pub fn as_ref(&self) -> PlaceRef<'tcx> { PlaceRef { local: self.local, projection: &self.projection } } + + /// Iterate over the projections in evaluation order, i.e., the first element is the base with + /// its projection and then subsequently more projections are added. + pub fn iter_projections(self) -> impl Iterator, PlaceElem<'tcx>)> + DoubleEndedIterator { + self.projection.iter().enumerate().map(move |(i, proj)| { + let base = PlaceRef { local: self.local, projection: &self.projection[..i] }; + (base, proj) + }) + } } impl From for Place<'_> { diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index f0bfdae261c6..1b2c1076a688 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -136,6 +136,15 @@ impl<'tcx> Place<'tcx> { } } +impl<'tcx> PlaceRef<'tcx> { + pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> + where + D: HasLocalDecls<'tcx>, + { + Place::ty_from(self.local, &self.projection, local_decls, tcx) + } +} + pub enum RvalueInitializationState { Shallow, Deep, From 571da2c62d0ac6360b78796e764ad5fe0753f553 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Nov 2020 13:20:34 +0100 Subject: [PATCH 031/719] refactor unsafety checking of places --- compiler/rustc_middle/src/mir/mod.rs | 4 +- .../rustc_mir/src/transform/check_unsafety.rs | 159 +++++++++--------- 2 files changed, 87 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4a7d4dab5079..2bd30001a915 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1744,7 +1744,9 @@ impl<'tcx> Place<'tcx> { /// Iterate over the projections in evaluation order, i.e., the first element is the base with /// its projection and then subsequently more projections are added. - pub fn iter_projections(self) -> impl Iterator, PlaceElem<'tcx>)> + DoubleEndedIterator { + pub fn iter_projections( + self, + ) -> impl Iterator, PlaceElem<'tcx>)> + DoubleEndedIterator { self.projection.iter().enumerate().map(move |(i, proj)| { let base = PlaceRef { local: self.local, projection: &self.projection[..i] }; (base, proj) diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index e90d5149c2f1..e64955c4986c 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -181,6 +181,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use()); } + // Check for borrows to packed fields. + // `is_disaligned` already traverses the place to consider all projections after the last + // `Deref`, so this only needs to be called once at the top level. if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { self.require_unsafe( @@ -190,53 +193,69 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } - for (i, _elem) in place.projection.iter().enumerate() { - let proj_base = &place.projection[..i]; - if context.is_borrow() { - if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { + // Some checks below need the extra metainfo of the local declaration. + let decl = &self.body.local_decls[place.local]; + + // Check the base local: it might be an unsafe-to-access static. We only check derefs of the + // temporary holding the static pointer to avoid duplicate errors + // . + if decl.internal && place.projection.first() == Some(&ProjectionElem::Deref) { + // If the projection root is an artifical local that we introduced when + // desugaring `static`, give a more specific error message + // (avoid the general "raw pointer" clause below, that would only be confusing). + if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { + if self.tcx.is_mutable_static(def_id) { self.require_unsafe( - UnsafetyViolationKind::BorrowPacked, - UnsafetyViolationDetails::BorrowOfPackedField, + UnsafetyViolationKind::General, + UnsafetyViolationDetails::UseOfMutableStatic, ); + return; + } else if self.tcx.is_foreign_item(def_id) { + self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::UseOfExternStatic, + ); + return; } } - let source_info = self.source_info; - if let [] = proj_base { - let decl = &self.body.local_decls[place.local]; - if decl.internal { - // If the projection root is an artifical local that we introduced when - // desugaring `static`, give a more specific error message - // (avoid the general "raw pointer" clause below, that would only be confusing). - if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { - if self.tcx.is_mutable_static(def_id) { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfMutableStatic, - ); - return; - } else if self.tcx.is_foreign_item(def_id) { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfExternStatic, - ); - return; - } - } else { - // Internal locals are used in the `move_val_init` desugaring. - // We want to check unsafety against the source info of the - // desugaring, rather than the source info of the RHS. - self.source_info = self.body.local_decls[place.local].source_info; - } + } + + // Check for raw pointer `Deref`. + for (base, proj) in place.iter_projections() { + if proj == ProjectionElem::Deref { + let source_info = self.source_info; // Backup source_info so we can restore it later. + if base.projection.is_empty() && decl.internal { + // Internal locals are used in the `move_val_init` desugaring. + // We want to check unsafety against the source info of the + // desugaring, rather than the source info of the RHS. + self.source_info = self.body.local_decls[place.local].source_info; } + let base_ty = base.ty(self.body, self.tcx).ty; + if base_ty.is_unsafe_ptr() { + self.require_unsafe( + UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationDetails::DerefOfRawPointer, + ) + } + self.source_info = source_info; // Restore backed-up source_info. } - let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; - match base_ty.kind() { - ty::RawPtr(..) => self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, - UnsafetyViolationDetails::DerefOfRawPointer, - ), - ty::Adt(adt, _) if adt.is_union() => { - let assign_to_field = matches!( + } + + // Check for union fields. For this we traverse right-to-left, as the last `Deref` changes + // whether we *read* the union field or potentially *write* to it (if this place is being assigned to). + let mut saw_deref = false; + for (base, proj) in place.iter_projections().rev() { + if proj == ProjectionElem::Deref { + saw_deref = true; + continue; + } + + let base_ty = base.ty(self.body, self.tcx).ty; + if base_ty.ty_adt_def().map_or(false, |adt| adt.is_union()) { + // If we did not hit a `Deref` yet and the overall place use is an assignment, the + // rules are different. + let assign_to_field = !saw_deref + && matches!( context, PlaceContext::MutatingUse( MutatingUseContext::Store @@ -244,45 +263,35 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { | MutatingUseContext::AsmOutput ) ); - // If there is a `Deref` further along the projection chain, this is *not* an - // assignment to a union field. In that case the union field is just read to - // obtain the pointer/reference. - let assign_to_field = assign_to_field - && !place.projection[i..] - .iter() - .any(|elem| matches!(elem, ProjectionElem::Deref)); - // If this is just an assignment, determine if the assigned type needs dropping. - if assign_to_field { - // We have to check the actual type of the assignment, as that determines if the - // old value is being dropped. - let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; - // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. - let manually_drop = assigned_ty - .ty_adt_def() - .map_or(false, |adt_def| adt_def.is_manually_drop()); - let nodrop = manually_drop - || assigned_ty.is_copy_modulo_regions( - self.tcx.at(self.source_info.span), - self.param_env, - ); - if !nodrop { - self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, - UnsafetyViolationDetails::AssignToDroppingUnionField, - ); - } else { - // write to non-drop union field, safe - } - } else { + // If this is just an assignment, determine if the assigned type needs dropping. + if assign_to_field { + // We have to check the actual type of the assignment, as that determines if the + // old value is being dropped. + let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; + // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. + let manually_drop = assigned_ty + .ty_adt_def() + .map_or(false, |adt_def| adt_def.is_manually_drop()); + let nodrop = manually_drop + || assigned_ty.is_copy_modulo_regions( + self.tcx.at(self.source_info.span), + self.param_env, + ); + if !nodrop { self.require_unsafe( UnsafetyViolationKind::GeneralAndConstFn, - UnsafetyViolationDetails::AccessToUnionField, - ) + UnsafetyViolationDetails::AssignToDroppingUnionField, + ); + } else { + // write to non-drop union field, safe } + } else { + self.require_unsafe( + UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationDetails::AccessToUnionField, + ) } - _ => {} } - self.source_info = source_info; } } } From a8c47440b4ac59239f11838cfc7426b2adef3685 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 10 Nov 2020 09:19:30 -0600 Subject: [PATCH 032/719] Use article_and_description for missing docs --- clippy_lints/src/missing_doc.rs | 64 ++++++++++++----------- tests/ui/missing-doc-crate-missing.stderr | 2 +- tests/ui/missing-doc-impl.stderr | 12 ++--- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 009e3d8937e0..f2c0ab1222cb 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -2,7 +2,7 @@ // *rustc*'s // [`missing_doc`]. // -// [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246 +// [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415 // use crate::utils::span_lint; @@ -70,7 +70,14 @@ impl MissingDoc { } } - fn check_missing_docs_attrs(&self, cx: &LateContext<'_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) { + fn check_missing_docs_attrs( + &self, + cx: &LateContext<'_>, + attrs: &[ast::Attribute], + sp: Span, + article: &'static str, + desc: &'static str, + ) { // If we're building a test harness, then warning about // documentation is probably not really relevant right now. if cx.sess().opts.test { @@ -94,7 +101,7 @@ impl MissingDoc { cx, MISSING_DOCS_IN_PRIVATE_ITEMS, sp, - &format!("missing documentation for {}", desc), + &format!("missing documentation for {} {}", article, desc), ); } } @@ -120,13 +127,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) { - self.check_missing_docs_attrs(cx, &krate.item.attrs, krate.item.span, "crate"); + self.check_missing_docs_attrs(cx, &krate.item.attrs, krate.item.span, "the", "crate"); } fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { - let desc = match it.kind { - hir::ItemKind::Const(..) => "a constant", - hir::ItemKind::Enum(..) => "an enum", + match it.kind { hir::ItemKind::Fn(..) => { // ignore main() if it.ident.name == sym::main { @@ -136,16 +141,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { return; } } - "a function" }, - hir::ItemKind::Mod(..) => "a module", - hir::ItemKind::Static(..) => "a static", - hir::ItemKind::Struct(..) => "a struct", - hir::ItemKind::Trait(..) => "a trait", - hir::ItemKind::TraitAlias(..) => "a trait alias", - hir::ItemKind::TyAlias(..) => "a type alias", - hir::ItemKind::Union(..) => "a union", - hir::ItemKind::OpaqueTy(..) => "an existential type", + hir::ItemKind::Const(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Mod(..) + | hir::ItemKind::Static(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Trait(..) + | hir::ItemKind::TraitAlias(..) + | hir::ItemKind::TyAlias(..) + | hir::ItemKind::Union(..) + | hir::ItemKind::OpaqueTy(..) => {}, hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod(..) | hir::ItemKind::GlobalAsm(..) @@ -153,17 +159,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { | hir::ItemKind::Use(..) => return, }; - self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc); + let def_id = cx.tcx.hir().local_def_id(it.hir_id); + let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id()); + + self.check_missing_docs_attrs(cx, &it.attrs, it.span, article, desc); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) { - let desc = match trait_item.kind { - hir::TraitItemKind::Const(..) => "an associated constant", - hir::TraitItemKind::Fn(..) => "a trait method", - hir::TraitItemKind::Type(..) => "an associated type", - }; + let def_id = cx.tcx.hir().local_def_id(trait_item.hir_id); + let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id()); - self.check_missing_docs_attrs(cx, &trait_item.attrs, trait_item.span, desc); + self.check_missing_docs_attrs(cx, &trait_item.attrs, trait_item.span, article, desc); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { @@ -178,21 +184,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { }, } - let desc = match impl_item.kind { - hir::ImplItemKind::Const(..) => "an associated constant", - hir::ImplItemKind::Fn(..) => "a method", - hir::ImplItemKind::TyAlias(_) => "an associated type", - }; - self.check_missing_docs_attrs(cx, &impl_item.attrs, impl_item.span, desc); + let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id()); + self.check_missing_docs_attrs(cx, &impl_item.attrs, impl_item.span, article, desc); } fn check_struct_field(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::StructField<'_>) { if !sf.is_positional() { - self.check_missing_docs_attrs(cx, &sf.attrs, sf.span, "a struct field"); + self.check_missing_docs_attrs(cx, &sf.attrs, sf.span, "a", "struct field"); } } fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) { - self.check_missing_docs_attrs(cx, &v.attrs, v.span, "a variant"); + self.check_missing_docs_attrs(cx, &v.attrs, v.span, "a", "variant"); } } diff --git a/tests/ui/missing-doc-crate-missing.stderr b/tests/ui/missing-doc-crate-missing.stderr index da46f9886366..d56c5cc4c3ae 100644 --- a/tests/ui/missing-doc-crate-missing.stderr +++ b/tests/ui/missing-doc-crate-missing.stderr @@ -1,4 +1,4 @@ -error: missing documentation for crate +error: missing documentation for the crate --> $DIR/missing-doc-crate-missing.rs:1:1 | LL | / #![warn(clippy::missing_docs_in_private_items)] diff --git a/tests/ui/missing-doc-impl.stderr b/tests/ui/missing-doc-impl.stderr index 9656a39abceb..7e10404ca005 100644 --- a/tests/ui/missing-doc-impl.stderr +++ b/tests/ui/missing-doc-impl.stderr @@ -51,13 +51,13 @@ LL | | fn foo_with_impl(&self) {} LL | | } | |_^ -error: missing documentation for a trait method +error: missing documentation for an associated function --> $DIR/missing-doc-impl.rs:39:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ -error: missing documentation for a trait method +error: missing documentation for an associated function --> $DIR/missing-doc-impl.rs:40:5 | LL | fn foo_with_impl(&self) {} @@ -75,25 +75,25 @@ error: missing documentation for an associated type LL | type AssociatedTypeDef = Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: missing documentation for a method +error: missing documentation for an associated function --> $DIR/missing-doc-impl.rs:62:5 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ -error: missing documentation for a method +error: missing documentation for an associated function --> $DIR/missing-doc-impl.rs:63:5 | LL | fn bar() {} | ^^^^^^^^^^^ -error: missing documentation for a method +error: missing documentation for an associated function --> $DIR/missing-doc-impl.rs:67:5 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ -error: missing documentation for a method +error: missing documentation for an associated function --> $DIR/missing-doc-impl.rs:70:5 | LL | fn foo2() {} From 3d11e96569861f2df3254af65bd8065dc70474bf Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Mon, 23 Nov 2020 15:51:01 +0100 Subject: [PATCH 033/719] Fix order of diff when rustdoc tests fail --- src/tools/compiletest/src/runtest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 4ca0b2aba0ad..57926fedfd47 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2436,7 +2436,7 @@ impl<'test> TestCx<'test> { }) }; let mut diff = Command::new("diff"); - diff.args(&["-u", "-r"]).args(&[out_dir, &compare_dir]); + diff.args(&["-u", "-r"]).args(&[&compare_dir, out_dir]); let output = if let Some(pager) = pager { let diff_pid = diff.stdout(Stdio::piped()).spawn().expect("failed to run `diff`"); From d93f1d6c04fab017a24d868dd766a290321e636c Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Mon, 23 Nov 2020 13:22:56 +0100 Subject: [PATCH 034/719] Apply `doc(cfg)` from parent items while collecting trait impls Because trait impls bypass the standard `clean` hierarchy they do not participate in the `propagate_doc_cfg` pass, so instead we need to pre-collect all possible `doc(cfg)` attributes that will apply to them when cleaning. --- src/librustdoc/clean/inline.rs | 10 ++--- src/librustdoc/passes/collect_trait_impls.rs | 28 ++++++++++++- src/test/rustdoc/doc-cfg.rs | 3 +- src/test/rustdoc/issue-79201.rs | 41 ++++++++++++++++++++ 4 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 src/test/rustdoc/issue-79201.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cc3e8707e527..17963e44a01f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -339,9 +339,6 @@ crate fn build_impl( return; } - let attrs = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs); - debug!("merged_attrs={:?}", attrs); - let tcx = cx.tcx; let associated_trait = tcx.impl_trait_ref(did); @@ -435,7 +432,7 @@ crate fn build_impl( debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); - ret.push(clean::Item::from_def_id_and_parts( + let mut item = clean::Item::from_def_id_and_parts( did, None, clean::ImplItem(clean::Impl { @@ -450,7 +447,10 @@ crate fn build_impl( blanket_impl: None, }), cx, - )); + ); + item.attrs = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs); + debug!("merged_attrs={:?}", item.attrs); + ret.push(item); } fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet) -> clean::Module { diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 2946db1f4620..62eb7d4d11f3 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -5,6 +5,7 @@ use crate::fold::DocFolder; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_middle::ty::DefIdTree; use rustc_span::symbol::sym; crate const COLLECT_TRAIT_IMPLS: Pass = Pass { @@ -90,7 +91,32 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { for &impl_node in cx.tcx.hir().trait_impls(trait_did) { let impl_did = cx.tcx.hir().local_def_id(impl_node); cx.tcx.sess.time("build_local_trait_impl", || { - inline::build_impl(cx, None, impl_did.to_def_id(), None, &mut new_items); + let mut extra_attrs = Vec::new(); + let mut parent = cx.tcx.parent(impl_did.to_def_id()); + while let Some(did) = parent { + extra_attrs.extend( + cx.tcx + .get_attrs(did) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .filter(|attr| { + if let Some([attr]) = attr.meta_item_list().as_deref() { + attr.has_name(sym::cfg) + } else { + false + } + }) + .cloned(), + ); + parent = cx.tcx.parent(did); + } + inline::build_impl( + cx, + None, + impl_did.to_def_id(), + Some(&extra_attrs), + &mut new_items, + ); }); } } diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs index d7041ee2f1af..471dd3a9d182 100644 --- a/src/test/rustdoc/doc-cfg.rs +++ b/src/test/rustdoc/doc-cfg.rs @@ -25,12 +25,13 @@ pub mod unix_only { // @has doc_cfg/unix_only/trait.ArmOnly.html \ // '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ // 'This is supported on Unix and ARM only.' - // @count - '//*[@class="stab portability"]' 2 + // @count - '//*[@class="stab portability"]' 1 #[doc(cfg(target_arch = "arm"))] pub trait ArmOnly { fn unix_and_arm_only_function(); } + #[doc(cfg(target_arch = "arm"))] impl ArmOnly for super::Portable { fn unix_and_arm_only_function() {} } diff --git a/src/test/rustdoc/issue-79201.rs b/src/test/rustdoc/issue-79201.rs new file mode 100644 index 000000000000..f95d79cd493e --- /dev/null +++ b/src/test/rustdoc/issue-79201.rs @@ -0,0 +1,41 @@ +#![feature(doc_cfg)] + +// @has 'issue_79201/trait.Foo.html' +// @count - '//*[@class="stab portability"]' 6 +// @matches - '//*[@class="stab portability"]' 'crate feature foo-root' +// @matches - '//*[@class="stab portability"]' 'crate feature foo-public-mod' +// @matches - '//*[@class="stab portability"]' 'crate feature foo-private-mod' +// @matches - '//*[@class="stab portability"]' 'crate feature foo-fn' +// @matches - '//*[@class="stab portability"]' 'crate feature foo-method' + +pub trait Foo {} + +#[doc(cfg(feature = "foo-root"))] +impl crate::Foo for usize {} + +#[doc(cfg(feature = "foo-public-mod"))] +pub mod public { + impl crate::Foo for u8 {} +} + +#[doc(cfg(feature = "foo-private-mod"))] +mod private { + impl crate::Foo for u16 {} +} + +#[doc(cfg(feature = "foo-const"))] +const _: () = { + impl crate::Foo for u32 {} +}; + +#[doc(cfg(feature = "foo-fn"))] +fn __() { + impl crate::Foo for u64 {} +} + +#[doc(cfg(feature = "foo-method"))] +impl dyn Foo { + fn __() { + impl crate::Foo for u128 {} + } +} From ce3d60476a9f307e71c2928ab575cfced6831187 Mon Sep 17 00:00:00 2001 From: William Chargin Date: Mon, 23 Nov 2020 11:59:42 -0800 Subject: [PATCH 035/719] std::iter: document iteration over `&T` and `&mut T` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A colleague of mine is new to Rust, and mentioned that it was “slightly confusing” to figure out what `&mut` does in iterating over `&mut foo`: ```rust for value in &mut self.my_vec { // ... } ``` My colleague had read the `std::iter` docs and not found the answer there. There is a brief section at the top about “the three forms of iteration”, which mentions `iter_mut`, but it doesn’t cover the purpose of `&mut coll` for a collection `coll`. This patch adds an explanatory section to the docs. I opted to create a new section so that it can appear after the note that `impl IntoIterator for I`, and it’s nice for the existing “three forms of iteration” to appear near the top. Implementation note: I haven’t linkified the references to `HashSet` and `HashMap`, since those are in `std` and these docs are in `core`; linkifying them gave an “unresolved link” rustdoc error. Test Plan: Ran `./x.py doc library/core`, and the result looked good. Manually copy-pasted the two doctests into the playground and ran them. wchargin-branch: doc-iter-by-reference wchargin-source: 0f35369a8a735868621166608797744e97536792 --- library/core/src/iter/mod.rs | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 072373c00f67..2ace734fb0c7 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -206,6 +206,49 @@ //! 2. If you're creating a collection, implementing [`IntoIterator`] for it //! will allow your collection to be used with the `for` loop. //! +//! # Iterating by reference +//! +//! Since [`into_iter()`] takes `self` by value, using a `for` loop to iterate +//! over a collection consumes that collection. Often, you may want to iterate +//! over a collection without consuming it. Many collections offer methods that +//! provide iterators over references, conventionally called `iter()` and +//! `iter_mut()` respectively: +//! +//! ``` +//! let mut values = vec![41]; +//! for x in values.iter_mut() { +//! *x += 1; +//! } +//! for x in values.iter() { +//! assert_eq!(*x, 42); +//! } +//! assert_eq!(values.len(), 1); // `values` is still owned by this function. +//! ``` +//! +//! If a collection type `C` provides `iter()`, it usually also implements +//! `IntoIterator` for `&C`, with an implementation that just calls `iter()`. +//! Likewise, a collection `C` that provides `iter_mut()` generally implements +//! `IntoIterator` for `&mut C` by delegating to `iter_mut()`. This enables a +//! convenient shorthand: +//! +//! ``` +//! let mut values = vec![41]; +//! for x in &mut values { // same as `values.iter_mut()` +//! *x += 1; +//! } +//! for x in &values { // same as `values.iter()` +//! assert_eq!(*x, 42); +//! } +//! assert_eq!(values.len(), 1); +//! ``` +//! +//! While many collections offer `iter()`, not all offer `iter_mut()`. For +//! example, mutating the keys of a `HashSet` or `HashMap` could put +//! the collection into an inconsistent state if the key hashes change, so these +//! collections only offer `iter()`. +//! +//! [`into_iter()`]: IntoIterator::into_iter +//! //! # Adapters //! //! Functions which take an [`Iterator`] and return another [`Iterator`] are From 6edc90a3e21a786bfe1e0a6bca28e8e687064554 Mon Sep 17 00:00:00 2001 From: William Chargin Date: Mon, 23 Nov 2020 15:46:13 -0800 Subject: [PATCH 036/719] [update patch] wchargin-branch: doc-iter-by-reference wchargin-source: e4069ac9a9d73860467cea74cf3ae1605af37d74 --- library/core/src/iter/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 2ace734fb0c7..3e74637b49f1 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -243,11 +243,13 @@ //! ``` //! //! While many collections offer `iter()`, not all offer `iter_mut()`. For -//! example, mutating the keys of a `HashSet` or `HashMap` could put -//! the collection into an inconsistent state if the key hashes change, so these -//! collections only offer `iter()`. +//! example, mutating the keys of a [`HashSet`] or [`HashMap`] could +//! put the collection into an inconsistent state if the key hashes change, so +//! these collections only offer `iter()`. //! //! [`into_iter()`]: IntoIterator::into_iter +//! [`HashSet`]: ../../std/collections/struct.HashSet.html +//! [`HashMap`]: ../../std/collections/struct.HashMap.html //! //! # Adapters //! From 9b09dc05794faf13f580bc7cc57788dfa32e28de Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Nov 2020 14:13:04 +0100 Subject: [PATCH 037/719] Show hidden elements by default when JS is disabled --- src/librustdoc/html/static/noscript.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/librustdoc/html/static/noscript.css b/src/librustdoc/html/static/noscript.css index 832bd9ba2d62..ffa1a7639abb 100644 --- a/src/librustdoc/html/static/noscript.css +++ b/src/librustdoc/html/static/noscript.css @@ -1,3 +1,9 @@ +/* +This whole CSS file is used only in case rustdoc is rendered with javascript disabled. Since a lot +of content is hidden by default (depending on the settings too), we have to overwrite some of the +rules. +*/ + #main > h2 + div, #main > h2 + h3, #main > h3 + div { display: block; } @@ -13,3 +19,7 @@ #main > h2 + h3 { display: flex; } + +#main .impl-items .hidden { + display: block !important; +} From 872b5cd80a38eb6c6c5a513c676818abcb0916b9 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 25 Nov 2020 11:00:40 +0800 Subject: [PATCH 038/719] Link loop/for keyword --- library/std/src/keyword_docs.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 80b74a9ba9b0..e05e72d9a89b 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -554,8 +554,11 @@ mod fn_keyword {} /// /// For more information on for-loops, see the [Rust book] or the [Reference]. /// +/// See also, [`loop`]. +/// /// [`in`]: keyword.in.html /// [`impl`]: keyword.impl.html +/// [`loop`]: keyword.loop.html /// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds /// [Rust book]: /// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for @@ -879,6 +882,9 @@ mod while_keyword {} /// /// For more information on `loop` and loops in general, see the [Reference]. /// +/// See also, [`for`]. +/// +/// [`for`]: keyword.loop.html /// [Reference]: ../reference/expressions/loop-expr.html mod loop_keyword {} From 6b272e0231f02fcf5e6d9f2f42fcf232b43476ef Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 25 Nov 2020 11:11:25 +0800 Subject: [PATCH 039/719] Fix typo in keyword link Co-authored-by: Camelid --- library/std/src/keyword_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index e05e72d9a89b..5f7f519560a6 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -884,7 +884,7 @@ mod while_keyword {} /// /// See also, [`for`]. /// -/// [`for`]: keyword.loop.html +/// [`for`]: keyword.for.html /// [Reference]: ../reference/expressions/loop-expr.html mod loop_keyword {} From 2d4cfd0779ad8b732dd5fc27fb6a3939f799060f Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Thu, 26 Nov 2020 01:05:20 +0800 Subject: [PATCH 040/719] Add while loop keyword to see also Suggested by withoutboats --- library/std/src/keyword_docs.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 5f7f519560a6..adebfd330771 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -554,11 +554,12 @@ mod fn_keyword {} /// /// For more information on for-loops, see the [Rust book] or the [Reference]. /// -/// See also, [`loop`]. +/// See also, [`loop`], [`while`]. /// /// [`in`]: keyword.in.html /// [`impl`]: keyword.impl.html /// [`loop`]: keyword.loop.html +/// [`while`]: keyword.while.html /// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds /// [Rust book]: /// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for @@ -834,6 +835,8 @@ mod let_keyword {} /// /// For more information on `while` and loops in general, see the [reference]. /// +/// See also, [`for`], [`loop`]. +/// /// [`for`]: keyword.for.html /// [`loop`]: keyword.loop.html /// [reference]: ../reference/expressions/loop-expr.html#predicate-loops @@ -882,9 +885,10 @@ mod while_keyword {} /// /// For more information on `loop` and loops in general, see the [Reference]. /// -/// See also, [`for`]. +/// See also, [`for`], [`while`]. /// /// [`for`]: keyword.for.html +/// [`while`]: keyword.while.html /// [Reference]: ../reference/expressions/loop-expr.html mod loop_keyword {} From 3b8617b9b6718f04d412ffae52337053e79c3c6b Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 26 Nov 2020 23:22:36 +0100 Subject: [PATCH 041/719] Added [T; N]::zip() --- library/core/src/array/mod.rs | 28 ++++++++++++++++++++++++++++ library/core/tests/array.rs | 8 ++++++++ library/core/tests/lib.rs | 1 + 3 files changed, 37 insertions(+) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index a7cb1023229b..02b771863e92 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -463,6 +463,34 @@ impl [T; N] { unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) } } + /// 'Zips up' two arrays into a single array of pairs. + /// `zip()` returns a new array where every element is a tuple where the first element comes from the first array, and the second element comes from the second array. + /// In other words, it zips two arrays together, into a single one. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_zip)] + /// let x = [1, 2, 3]; + /// let y = [4, 5, 6]; + /// let z = x.zip(y); + /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]); + /// ``` + #[unstable(feature = "array_zip", issue = "none")] + pub fn zip(self, rhs: [U; N]) -> [(T, U); N] { + use crate::mem::MaybeUninit; + + let mut dst = MaybeUninit::uninit_array::(); + for ((lhs, rhs), dst) in IntoIter::new(self).zip(IntoIter::new(rhs)).zip(&mut dst) { + dst.write((lhs, rhs)); + } + // FIXME: Convert to crate::mem::transmute once it works with generics. + // unsafe { crate::mem::transmute::<[MaybeUninit; N], [U; N]>(dst) } + // SAFETY: At this point we've properly initialized the whole array + // and we just need to cast it to the correct type. + unsafe { crate::mem::transmute_copy::<_, [(T, U); N]>(&dst) } + } + /// Returns a slice containing the entire array. Equivalent to `&s[..]`. #[unstable(feature = "array_methods", issue = "76118")] pub fn as_slice(&self) -> &[T] { diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 89c2a969c28b..9005e3d8f43e 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -317,6 +317,14 @@ fn array_map() { assert_eq!(b, [1, 2, 3]); } +#[test] +fn array_zip() { + let a = [1, 2, 3]; + let b = [4, 5, 6]; + let c = a.zip(b); + assert_eq!(c, [(1, 4), (2, 5), (3, 6)]); +} + // See note on above test for why `should_panic` is used. #[test] #[should_panic(expected = "test succeeded")] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 1efb3b741189..2daf2650b582 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -3,6 +3,7 @@ #![feature(array_from_ref)] #![feature(array_methods)] #![feature(array_map)] +#![feature(array_zip)] #![feature(array_windows)] #![feature(bool_to_option)] #![feature(bound_cloned)] From 2f35fb1e116d5da9e851c1a298390078ea7089ed Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 27 Nov 2020 11:46:49 +0100 Subject: [PATCH 042/719] Remove redundant tests --- library/core/tests/array.rs | 8 -------- library/core/tests/lib.rs | 1 - 2 files changed, 9 deletions(-) diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 9005e3d8f43e..89c2a969c28b 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -317,14 +317,6 @@ fn array_map() { assert_eq!(b, [1, 2, 3]); } -#[test] -fn array_zip() { - let a = [1, 2, 3]; - let b = [4, 5, 6]; - let c = a.zip(b); - assert_eq!(c, [(1, 4), (2, 5), (3, 6)]); -} - // See note on above test for why `should_panic` is used. #[test] #[should_panic(expected = "test succeeded")] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 2daf2650b582..1efb3b741189 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -3,7 +3,6 @@ #![feature(array_from_ref)] #![feature(array_methods)] #![feature(array_map)] -#![feature(array_zip)] #![feature(array_windows)] #![feature(bool_to_option)] #![feature(bound_cloned)] From 0387981f2b5e41c982ec4a1b102f0c54997361ff Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sat, 17 Oct 2020 19:48:40 +0200 Subject: [PATCH 043/719] Add --no-deps command-line argument --- clippy_workspace_tests/path_dep/Cargo.toml | 3 + clippy_workspace_tests/path_dep/src/lib.rs | 6 ++ clippy_workspace_tests/subcrate/Cargo.toml | 3 + src/driver.rs | 35 ++++++----- tests/dogfood.rs | 71 +++++++++++++++++++++- 5 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 clippy_workspace_tests/path_dep/Cargo.toml create mode 100644 clippy_workspace_tests/path_dep/src/lib.rs diff --git a/clippy_workspace_tests/path_dep/Cargo.toml b/clippy_workspace_tests/path_dep/Cargo.toml new file mode 100644 index 000000000000..85a91cd2decd --- /dev/null +++ b/clippy_workspace_tests/path_dep/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "path_dep" +version = "0.1.0" diff --git a/clippy_workspace_tests/path_dep/src/lib.rs b/clippy_workspace_tests/path_dep/src/lib.rs new file mode 100644 index 000000000000..35ce524f2b10 --- /dev/null +++ b/clippy_workspace_tests/path_dep/src/lib.rs @@ -0,0 +1,6 @@ +#![deny(clippy::empty_loop)] + +#[cfg(feature = "primary_package_test")] +pub fn lint_me() { + loop {} +} diff --git a/clippy_workspace_tests/subcrate/Cargo.toml b/clippy_workspace_tests/subcrate/Cargo.toml index 83ea5868160b..45362c11b856 100644 --- a/clippy_workspace_tests/subcrate/Cargo.toml +++ b/clippy_workspace_tests/subcrate/Cargo.toml @@ -1,3 +1,6 @@ [package] name = "subcrate" version = "0.1.0" + +[dependencies] +path_dep = { path = "../path_dep" } diff --git a/src/driver.rs b/src/driver.rs index ef31c72481a2..bbe9ce739368 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -277,27 +277,34 @@ pub fn main() { args.extend(vec!["--sysroot".into(), sys_root]); }; + let mut no_deps = false; + let clippy_args = env::var("CLIPPY_ARGS") + .unwrap_or_default() + .split("__CLIPPY_HACKERY__") + .filter_map(|s| match s { + "" => None, + "--no-deps" => { + no_deps = true; + None + }, + _ => Some(s.to_string()), + }) + .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]) + .collect::>(); + // this check ensures that dependencies are built but not linted and the final // crate is linted but not built - let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true") - || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none(); + let clippy_disabled = env::var("CLIPPY_TESTS").map_or(false, |val| val != "true") + || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some() + || no_deps && env::var("CARGO_PRIMARY_PACKAGE").is_err(); - if clippy_enabled { - args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]); - if let Ok(extra_args) = env::var("CLIPPY_ARGS") { - args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| { - if s.is_empty() { - None - } else { - Some(s.to_string()) - } - })); - } + if !clippy_disabled { + args.extend(clippy_args); } let mut clippy = ClippyCallbacks; let mut default = DefaultCallbacks; let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = - if clippy_enabled { &mut clippy } else { &mut default }; + if clippy_disabled { &mut default } else { &mut clippy }; rustc_driver::RunCompiler::new(&args, callbacks).run() })) } diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 48e0478f1699..b166a6b7c1ff 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -3,7 +3,7 @@ #![feature(once_cell)] use std::lazy::SyncLazy; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::Command; mod cargo; @@ -41,12 +41,77 @@ fn dogfood_clippy() { #[test] fn dogfood_subprojects() { + fn test_no_deps_ignores_path_deps_in_workspaces() { + fn clean(cwd: &Path, target_dir: &Path) { + Command::new("cargo") + .current_dir(cwd) + .env("CARGO_TARGET_DIR", target_dir) + .arg("clean") + .args(&["-p", "subcrate"]) + .args(&["-p", "path_dep"]) + .output() + .unwrap(); + } + + if cargo::is_rustc_test_suite() { + return; + } + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let target_dir = root.join("target").join("dogfood"); + let cwd = root.join("clippy_workspace_tests"); + + // Make sure we start with a clean state + clean(&cwd, &target_dir); + + // `path_dep` is a path dependency of `subcrate` that would trigger a denied lint. + // Make sure that with the `--no-deps` argument Clippy does not run on `path_dep`. + let output = Command::new(&*CLIPPY_PATH) + .current_dir(&cwd) + .env("CLIPPY_DOGFOOD", "1") + .env("CARGO_INCREMENTAL", "0") + .arg("clippy") + .args(&["-p", "subcrate"]) + .arg("--") + .arg("--no-deps") + .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir + .args(&["--cfg", r#"feature="primary_package_test""#]) + .output() + .unwrap(); + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + + assert!(output.status.success()); + + // Make sure we start with a clean state + clean(&cwd, &target_dir); + + // Test that without the `--no-deps` argument, `path_dep` is linted. + let output = Command::new(&*CLIPPY_PATH) + .current_dir(&cwd) + .env("CLIPPY_DOGFOOD", "1") + .env("CARGO_INCREMENTAL", "0") + .arg("clippy") + .args(&["-p", "subcrate"]) + .arg("--") + .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir + .args(&["--cfg", r#"feature="primary_package_test""#]) + .output() + .unwrap(); + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + + assert!(!output.status.success()); + } + // run clippy on remaining subprojects and fail the test if lint warnings are reported if cargo::is_rustc_test_suite() { return; } let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + // NOTE: `path_dep` crate is omitted on purpose here for d in &[ "clippy_workspace_tests", "clippy_workspace_tests/src", @@ -72,4 +137,8 @@ fn dogfood_subprojects() { assert!(output.status.success()); } + + // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the + // same time, so we test this immediately after the dogfood for workspaces. + test_no_deps_ignores_path_deps_in_workspaces(); } From 192ccfb4efc0a38378f4564b26e6033dec432bdb Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sat, 17 Oct 2020 19:55:03 +0200 Subject: [PATCH 044/719] Update README.md --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index fddf0614a0b8..aaa55e11c7db 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,22 @@ Note that this is still experimental and only supported on the nightly channel: cargo clippy --fix -Z unstable-options ``` +#### Workspaces + +All the usual workspace options should work with Clippy. For example the following command +will run Clippy on the `example` crate: + +```terminal +cargo clippy -p example +``` + +As with `cargo check`, this includes dependencies that are members of the workspace, like path dependencies. +If you want to run Clippy **only** on the given crate, use the `--no-deps` option like this: + +```terminal +cargo clippy -p example -- --no-deps +``` + ### Running Clippy from the command line without installing it To have cargo compile your crate with Clippy without Clippy installation From 7eda421e9629a717d31ec03d12b4befd03f5fb50 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Wed, 25 Nov 2020 15:02:47 +0100 Subject: [PATCH 045/719] Apply suggestion regarding clippy_enabled bool --- src/driver.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index bbe9ce739368..03381106de1a 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -182,6 +182,7 @@ fn toolchain_path(home: Option, toolchain: Option) -> Option Date: Fri, 27 Nov 2020 16:53:30 +0100 Subject: [PATCH 046/719] Make --fix imply --no-deps --- src/main.rs | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6739a4cf2245..ea06743394d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,7 +62,7 @@ struct ClippyCmd { unstable_options: bool, cargo_subcommand: &'static str, args: Vec, - clippy_args: String, + clippy_args: Vec, } impl ClippyCmd { @@ -99,7 +99,10 @@ impl ClippyCmd { args.insert(0, "+nightly".to_string()); } - let clippy_args: String = old_args.map(|arg| format!("{}__CLIPPY_HACKERY__", arg)).collect(); + let mut clippy_args: Vec = old_args.collect(); + if cargo_subcommand == "fix" && !clippy_args.iter().any(|arg| arg == "--no-deps") { + clippy_args.push("--no-deps".into()); + } ClippyCmd { unstable_options, @@ -147,10 +150,15 @@ impl ClippyCmd { fn into_std_cmd(self) -> Command { let mut cmd = Command::new("cargo"); + let clippy_args: String = self + .clippy_args + .iter() + .map(|arg| format!("{}__CLIPPY_HACKERY__", arg)) + .collect(); cmd.env(self.path_env(), Self::path()) .envs(ClippyCmd::target_dir()) - .env("CLIPPY_ARGS", self.clippy_args) + .env("CLIPPY_ARGS", clippy_args) .arg(self.cargo_subcommand) .args(&self.args); @@ -201,6 +209,24 @@ mod tests { assert!(cmd.args.iter().any(|arg| arg.ends_with("unstable-options"))); } + #[test] + fn fix_implies_no_deps() { + let args = "cargo clippy --fix -Zunstable-options" + .split_whitespace() + .map(ToString::to_string); + let cmd = ClippyCmd::new(args); + assert!(cmd.clippy_args.iter().any(|arg| arg == "--no-deps")); + } + + #[test] + fn no_deps_not_duplicated_with_fix() { + let args = "cargo clippy --fix -Zunstable-options -- --no-deps" + .split_whitespace() + .map(ToString::to_string); + let cmd = ClippyCmd::new(args); + assert_eq!(cmd.clippy_args.iter().filter(|arg| *arg == "--no-deps").count(), 1); + } + #[test] fn check() { let args = "cargo clippy".split_whitespace().map(ToString::to_string); From 952b731fb9134e44e4c99bae46e6a917c944e77e Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Fri, 27 Nov 2020 18:04:30 +0100 Subject: [PATCH 047/719] Reword bitrotten comment --- src/driver.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index 03381106de1a..e490ee54c0be 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -293,8 +293,11 @@ pub fn main() { .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]) .collect::>(); - // this check ensures that dependencies are built but not linted and the final - // crate is linted but not built + // We enable Clippy if one of the following conditions is met + // - IF Clippy is run on its test suite OR + // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN + // - IF `--no-deps` is not set (`!no_deps`) OR + // - IF `--no-deps` is set and Clippy is run on the specified primary package let clippy_tests_set = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true"); let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some(); let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); From 0523eeb8a38dbd6e6e6fd9283b27609fbf38859c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 27 Nov 2020 19:15:51 +0100 Subject: [PATCH 048/719] Move {f32,f64}::clamp to core. --- library/core/src/num/f32.rs | 35 +++++++++++++++++++++++++++++++++++ library/core/src/num/f64.rs | 35 +++++++++++++++++++++++++++++++++++ library/std/src/f32.rs | 35 ----------------------------------- library/std/src/f64.rs | 35 ----------------------------------- 4 files changed, 70 insertions(+), 70 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 33df175bfc54..4d876fd8c33e 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -961,4 +961,39 @@ impl f32 { left.cmp(&right) } + + /// Restrict a value to a certain interval unless it is NaN. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// Note that this function returns NaN if the initial value was NaN as + /// well. + /// + /// # Panics + /// + /// Panics if `min > max`, `min` is NaN, or `max` is NaN. + /// + /// # Examples + /// + /// ``` + /// assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0); + /// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0); + /// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0); + /// assert!((f32::NAN).clamp(-2.0, 1.0).is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[stable(feature = "clamp", since = "1.50.0")] + #[inline] + pub fn clamp(self, min: f32, max: f32) -> f32 { + assert!(min <= max); + let mut x = self; + if x < min { + x = min; + } + if x > max { + x = max; + } + x + } } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index b85e8deb6d22..3323b7d6774d 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -975,4 +975,39 @@ impl f64 { left.cmp(&right) } + + /// Restrict a value to a certain interval unless it is NaN. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// Note that this function returns NaN if the initial value was NaN as + /// well. + /// + /// # Panics + /// + /// Panics if `min > max`, `min` is NaN, or `max` is NaN. + /// + /// # Examples + /// + /// ``` + /// assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0); + /// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0); + /// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0); + /// assert!((f64::NAN).clamp(-2.0, 1.0).is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[stable(feature = "clamp", since = "1.50.0")] + #[inline] + pub fn clamp(self, min: f64, max: f64) -> f64 { + assert!(min <= max); + let mut x = self; + if x < min { + x = min; + } + if x > max { + x = max; + } + x + } } diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 09a9b184e3a4..453534b86912 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -877,39 +877,4 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - - /// Restrict a value to a certain interval unless it is NaN. - /// - /// Returns `max` if `self` is greater than `max`, and `min` if `self` is - /// less than `min`. Otherwise this returns `self`. - /// - /// Note that this function returns NaN if the initial value was NaN as - /// well. - /// - /// # Panics - /// - /// Panics if `min > max`, `min` is NaN, or `max` is NaN. - /// - /// # Examples - /// - /// ``` - /// assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0); - /// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0); - /// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0); - /// assert!((f32::NAN).clamp(-2.0, 1.0).is_nan()); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - #[stable(feature = "clamp", since = "1.50.0")] - #[inline] - pub fn clamp(self, min: f32, max: f32) -> f32 { - assert!(min <= max); - let mut x = self; - if x < min { - x = min; - } - if x > max { - x = max; - } - x - } } diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 64bb7cd9fd16..a1a9e9dac5fa 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -880,41 +880,6 @@ impl f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - /// Restrict a value to a certain interval unless it is NaN. - /// - /// Returns `max` if `self` is greater than `max`, and `min` if `self` is - /// less than `min`. Otherwise this returns `self`. - /// - /// Note that this function returns NaN if the initial value was NaN as - /// well. - /// - /// # Panics - /// - /// Panics if `min > max`, `min` is NaN, or `max` is NaN. - /// - /// # Examples - /// - /// ``` - /// assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0); - /// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0); - /// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0); - /// assert!((f64::NAN).clamp(-2.0, 1.0).is_nan()); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - #[stable(feature = "clamp", since = "1.50.0")] - #[inline] - pub fn clamp(self, min: f64, max: f64) -> f64 { - assert!(min <= max); - let mut x = self; - if x < min { - x = min; - } - if x > max { - x = max; - } - x - } - // Solaris/Illumos requires a wrapper around log, log2, and log10 functions // because of their non-standard behavior (e.g., log(-n) returns -Inf instead // of expected NaN). From 4fcef4b1571a4909041fb6e8f304d33df611b1dc Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Mon, 23 Nov 2020 13:09:00 +0100 Subject: [PATCH 049/719] Stabilize all stable methods of `Ipv4Addr`, `Ipv6Addr` and `IpAddr` as const `Ipv4Addr` - `octets` - `is_loopback` - `is_private` - `is_link_local` - `is_multicast` - `is_broadcast` - `is_docmentation` - `to_ipv6_compatible` - `to_ipv6_mapped` `Ipv6Addr` - `segments` - `is_unspecified` - `is_loopback` - `is_multicast` - `to_ipv4` `IpAddr` - `is_unspecified` - `is_loopback` - `is_multicast` --- library/std/src/net/ip.rs | 49 +++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 87bbd33bc014..d33b772633d2 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -148,7 +148,7 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ip_shared", since = "1.12.0")] pub const fn is_unspecified(&self) -> bool { match self { @@ -170,7 +170,7 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ip_shared", since = "1.12.0")] pub const fn is_loopback(&self) -> bool { match self { @@ -215,7 +215,7 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ip_shared", since = "1.12.0")] pub const fn is_multicast(&self) -> bool { match self { @@ -301,8 +301,8 @@ impl Ipv4Addr { /// /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")] + #[stable(feature = "rust1", since = "1.0.0")] pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { // `s_addr` is stored as BE on all machine and the array is in BE order. // So the native endian conversion method is used so that it's never swapped. @@ -358,7 +358,7 @@ impl Ipv4Addr { /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!(addr.octets(), [127, 0, 0, 1]); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn octets(&self) -> [u8; 4] { // This returns the order we want because s_addr is stored in big-endian. @@ -380,8 +380,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); /// ``` - #[stable(feature = "ip_shared", since = "1.12.0")] #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")] + #[stable(feature = "ip_shared", since = "1.12.0")] pub const fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 } @@ -400,7 +400,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_loopback(&self) -> bool { self.octets()[0] == 127 @@ -429,7 +429,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_private(&self) -> bool { match self.octets() { @@ -455,7 +455,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_link_local(&self) -> bool { matches!(self.octets(), [169, 254, ..]) @@ -675,7 +675,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_multicast(&self) -> bool { self.octets()[0] >= 224 && self.octets()[0] <= 239 @@ -695,7 +695,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_broadcast(&self) -> bool { u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) @@ -721,7 +721,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_documentation(&self) -> bool { match self.octets() { @@ -751,7 +751,7 @@ impl Ipv4Addr { /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) /// ); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); @@ -774,7 +774,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); @@ -1043,9 +1043,9 @@ impl Ipv6Addr { /// /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] + #[stable(feature = "rust1", since = "1.0.0")] pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { let addr16 = [ a.to_be(), @@ -1061,6 +1061,8 @@ impl Ipv6Addr { inner: c::in6_addr { // All elements in `addr16` are big endian. // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. + // rustc_allow_const_fn_unstable: the transmute could be written as stable const + // code, but that leads to worse code generation (#75085) s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) }, }, } @@ -1102,11 +1104,14 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn segments(&self) -> [u16; 8] { // All elements in `s6_addr` must be big endian. // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. + // rustc_allow_const_fn_unstable: the transmute could be written as stable const code, but + // that leads to worse code generation (#75085) let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) }; // We want native endian u16 [ @@ -1135,7 +1140,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_unspecified(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) @@ -1155,7 +1160,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_loopback(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) @@ -1465,7 +1470,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 @@ -1520,7 +1525,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), /// Some(Ipv4Addr::new(0, 0, 0, 1))); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn to_ipv4(&self) -> Option { if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { @@ -1540,8 +1545,8 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// ``` - #[stable(feature = "ipv6_to_octets", since = "1.12.0")] #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] + #[stable(feature = "ipv6_to_octets", since = "1.12.0")] pub const fn octets(&self) -> [u8; 16] { self.inner.s6_addr } From d4048407880212bb820f85d2e06e5fc262cce897 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 27 Nov 2020 20:48:53 +0100 Subject: [PATCH 050/719] Merge commit '5988bbd24aa87732bfa1d111ba00bcdaa22c481a' into sync_cg_clif-2020-11-27 --- .gitattributes | 1 + Cargo.lock | 104 +++++++++--------- Cargo.toml | 4 +- Readme.md | 6 +- build.sh | 25 ++++- build_sysroot/Cargo.lock | 20 ++-- build_sysroot/build_sysroot.sh | 13 ++- build_sysroot/prepare_sysroot_src.sh | 12 +- example/std_example.rs | 1 + ...022-core-Disable-not-compiling-tests.patch | 8 +- prepare.sh | 1 + rust-toolchain | 2 +- scripts/cargo.sh | 8 +- scripts/config.sh | 19 ++-- scripts/rustup.sh | 38 +++++-- scripts/test_bootstrap.sh | 6 +- scripts/tests.sh | 30 ++--- src/abi/mod.rs | 6 +- src/archive.rs | 6 +- src/atomic_shim.rs | 3 +- src/base.rs | 31 +++++- src/bin/cg_clif.rs | 18 +-- src/common.rs | 4 +- src/constant.rs | 9 +- src/debuginfo/emit.rs | 7 +- src/debuginfo/unwind.rs | 4 +- src/discriminant.rs | 31 +++++- src/driver/aot.rs | 6 +- src/driver/jit.rs | 16 ++- src/driver/mod.rs | 26 ++--- src/intrinsics/mod.rs | 80 +++++++++++--- src/intrinsics/simd.rs | 65 +++++++++-- src/trap.rs | 12 ++ 33 files changed, 400 insertions(+), 222 deletions(-) diff --git a/.gitattributes b/.gitattributes index 6313b56c5784..0ceb3fe646cc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ * text=auto eol=lf +*.rs diff=rust diff --git a/Cargo.lock b/Cargo.lock index 2889fac77f6a..67ed41e76523 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "anyhow" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c" +checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" [[package]] name = "ar" @@ -31,9 +31,9 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cc" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" +checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" [[package]] name = "cfg-if" @@ -41,18 +41,24 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "cranelift-bforest" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "byteorder", "cranelift-bforest", @@ -69,8 +75,8 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -78,18 +84,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" [[package]] name = "cranelift-entity" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" [[package]] name = "cranelift-frontend" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-codegen", "log", @@ -99,8 +105,8 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "anyhow", "cranelift-codegen", @@ -111,8 +117,8 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-codegen", "raw-cpuid", @@ -121,8 +127,8 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "anyhow", "cranelift-codegen", @@ -134,8 +140,8 @@ dependencies = [ [[package]] name = "cranelift-simplejit" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -151,18 +157,18 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] name = "errno" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eab5ee3df98a279d9b316b1af6ac95422127b1290317e6d18c1743c99418b01" +checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe" dependencies = [ "errno-dragonfly", "libc", @@ -187,9 +193,9 @@ checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" [[package]] name = "gimli" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" dependencies = [ "indexmap", ] @@ -212,17 +218,17 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" [[package]] name = "libloading" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3557c9384f7f757f6d139cd3a4c62ef4e850696c16bf27924a5538c8a09717a1" +checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "winapi", ] @@ -232,7 +238,7 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -246,9 +252,9 @@ dependencies = [ [[package]] name = "object" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" dependencies = [ "crc32fast", "indexmap", @@ -274,9 +280,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "7.0.3" +version = "8.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf" +checksum = "1fdf7d9dbd43f3d81d94a49c1c3df73cc2b3827995147e6cf7f89d4ec5483e73" dependencies = [ "bitflags", "cc", @@ -361,9 +367,9 @@ checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" [[package]] name = "syn" -version = "1.0.44" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd" +checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" dependencies = [ "proc-macro2", "quote", @@ -372,24 +378,24 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe2635952a442a01fd4cb53d98858b5e4bb461b02c0d111f22f31772e3e7a8b2" +checksum = "4ee5a98e506fb7231a304c3a1bd7c132a55016cf65001e0282480665870dfcb9" [[package]] name = "thiserror" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" +checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" +checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 1c8e350d2429..cbff06749d3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", bran cranelift-simplejit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true } cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } target-lexicon = "0.11.0" -gimli = { version = "0.22.0", default-features = false, features = ["write"]} -object = { version = "0.21.1", default-features = false, features = ["std", "read_core", "write", "coff", "elf", "macho", "pe"] } +gimli = { version = "0.23.0", default-features = false, features = ["write"]} +object = { version = "0.22.0", default-features = false, features = ["std", "read_core", "write", "coff", "elf", "macho", "pe"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } indexmap = "1.0.2" diff --git a/Readme.md b/Readme.md index f8a5e13ed54c..de54bf67f4a1 100644 --- a/Readme.md +++ b/Readme.md @@ -51,7 +51,7 @@ This should build and run your project with rustc_codegen_cranelift instead of t > You should prefer using the Cargo method. ```bash -$ $cg_clif_dir/build/cg_clif my_crate.rs +$ $cg_clif_dir/build/bin/cg_clif my_crate.rs ``` ### Jit mode @@ -68,7 +68,7 @@ $ $cg_clif_dir/build/cargo.sh jit or ```bash -$ $cg_clif_dir/build/cg_clif --jit my_crate.rs +$ $cg_clif_dir/build/bin/cg_clif --jit my_crate.rs ``` ### Shell @@ -77,7 +77,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/build/cg_clif - --jit + echo "$@" | $cg_clif_dir/build/bin/cg_clif - --jit } function jit() { diff --git a/build.sh b/build.sh index f9a87e68a046..26041b59cca1 100755 --- a/build.sh +++ b/build.sh @@ -26,22 +26,35 @@ while [[ $# != 0 ]]; do done # Build cg_clif +unset CARGO_TARGET_DIR export RUSTFLAGS="-Zrun_dsymutil=no" +unamestr=$(uname) +if [[ "$unamestr" == 'Linux' ]]; then + export RUSTFLAGS='-Clink-arg=-Wl,-rpath=$ORIGIN/../lib '$RUSTFLAGS +elif [[ "$unamestr" == 'Darwin' ]]; then + export RUSTFLAGS='-Clink-arg=-Wl,-rpath,@loader_path/../lib -Zosx-rpath-install-name '$RUSTFLAGS + dylib_ext='dylib' +else + echo "Unsupported os" + exit 1 +fi if [[ "$CHANNEL" == "release" ]]; then cargo build --release else cargo build fi -rm -rf $target_dir -mkdir $target_dir -cp -a target/$CHANNEL/cg_clif{,_build_sysroot} target/$CHANNEL/*rustc_codegen_cranelift* $target_dir/ -cp -a rust-toolchain scripts/config.sh scripts/cargo.sh $target_dir +rm -rf "$target_dir" +mkdir "$target_dir" +mkdir "$target_dir"/bin "$target_dir"/lib +ln target/$CHANNEL/cg_clif{,_build_sysroot} "$target_dir"/bin +ln target/$CHANNEL/*rustc_codegen_cranelift* "$target_dir"/lib +ln rust-toolchain scripts/config.sh scripts/cargo.sh "$target_dir" if [[ "$build_sysroot" == "1" ]]; then echo "[BUILD] sysroot" export CG_CLIF_INCR_CACHE_DISABLED=1 dir=$(pwd) - cd $target_dir - time $dir/build_sysroot/build_sysroot.sh + cd "$target_dir" + time "$dir/build_sysroot/build_sysroot.sh" fi diff --git a/build_sysroot/Cargo.lock b/build_sysroot/Cargo.lock index 03ba5b53d2e4..a2b8f449f00f 100644 --- a/build_sysroot/Cargo.lock +++ b/build_sysroot/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "addr2line" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" +checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" dependencies = [ "compiler_builtins", "gimli", @@ -47,9 +47,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "cc" -version = "1.0.61" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" +checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15" [[package]] name = "cfg-if" @@ -76,9 +76,9 @@ version = "0.0.0" [[package]] name = "dlmalloc" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35055b1021724f4eb5262eb49130eebff23fc59fc5a14160e05faad8eeb36673" +checksum = "332570860c2edf2d57914987bf9e24835425f75825086b6ba7d1e6a3e4f1f254" dependencies = [ "compiler_builtins", "libc", @@ -108,9 +108,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -163,9 +163,9 @@ dependencies = [ [[package]] name = "object" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh index eba15c0dd430..d7a72df2eb28 100755 --- a/build_sysroot/build_sysroot.sh +++ b/build_sysroot/build_sysroot.sh @@ -10,10 +10,10 @@ dir=$(pwd) # Use rustc with cg_clif as hotpluggable backend instead of the custom cg_clif driver so that # build scripts are still compiled using cg_llvm. -export RUSTC=$dir"/cg_clif_build_sysroot" +export RUSTC=$dir"/bin/cg_clif_build_sysroot" export RUSTFLAGS=$RUSTFLAGS" --clif" -cd $(dirname "$0") +cd "$(dirname "$0")" # Cleanup for previous run # v Clean target dir except for build scripts and incremental cache @@ -28,12 +28,13 @@ if [[ "$1" != "--debug" ]]; then sysroot_channel='release' # FIXME Enable incremental again once rust-lang/rust#74946 is fixed # FIXME Enable -Zmir-opt-level=2 again once it doesn't ice anymore - CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS" cargo build --target $TARGET_TRIPLE --release + CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS" cargo build --target "$TARGET_TRIPLE" --release else sysroot_channel='debug' - cargo build --target $TARGET_TRIPLE + cargo build --target "$TARGET_TRIPLE" fi # Copy files to sysroot -mkdir -p $dir/sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ -cp -a target/$TARGET_TRIPLE/$sysroot_channel/deps/* $dir/sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ +mkdir -p "$dir/lib/rustlib/$TARGET_TRIPLE/lib/" +ln "target/$TARGET_TRIPLE/$sysroot_channel/deps/"* "$dir/lib/rustlib/$TARGET_TRIPLE/lib/" +rm "$dir/lib/rustlib/$TARGET_TRIPLE/lib/"*.{rmeta,d} diff --git a/build_sysroot/prepare_sysroot_src.sh b/build_sysroot/prepare_sysroot_src.sh index d0fb09ce745d..40fbaf646a2f 100755 --- a/build_sysroot/prepare_sysroot_src.sh +++ b/build_sysroot/prepare_sysroot_src.sh @@ -1,18 +1,18 @@ #!/bin/bash set -e -cd $(dirname "$0") +cd "$(dirname "$0")" -SRC_DIR=$(dirname $(rustup which rustc))"/../lib/rustlib/src/rust/" +SRC_DIR="$(dirname "$(rustup which rustc)")/../lib/rustlib/src/rust/" DST_DIR="sysroot_src" -if [ ! -e $SRC_DIR ]; then +if [ ! -e "$SRC_DIR" ]; then echo "Please install rust-src component" exit 1 fi rm -rf $DST_DIR mkdir -p $DST_DIR/library -cp -a $SRC_DIR/library $DST_DIR/ +cp -a "$SRC_DIR/library" $DST_DIR/ pushd $DST_DIR echo "[GIT] init" @@ -22,8 +22,8 @@ git add . echo "[GIT] commit" git commit -m "Initial commit" -q for file in $(ls ../../patches/ | grep -v patcha); do -echo "[GIT] apply" $file -git apply ../../patches/$file +echo "[GIT] apply" "$file" +git apply ../../patches/"$file" git add -A git commit --no-gpg-sign -m "Patch $file" done diff --git a/example/std_example.rs b/example/std_example.rs index cb512a4aa335..b38e25328a4e 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -53,6 +53,7 @@ fn main() { assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26); assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7); + assert_eq!(core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128), 170141183460469231731687303715884105727i128); let _d = 0i128.checked_div(2i128); let _d = 0u128.checked_div(2u128); diff --git a/patches/0022-core-Disable-not-compiling-tests.patch b/patches/0022-core-Disable-not-compiling-tests.patch index ee8548783de6..8cfffe580a1f 100644 --- a/patches/0022-core-Disable-not-compiling-tests.patch +++ b/patches/0022-core-Disable-not-compiling-tests.patch @@ -52,8 +52,8 @@ index 0475aeb..9558198 100644 fn test_rotate() { assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); @@ -112,6 +113,7 @@ mod tests { - assert_eq!(B.rotate_left(64), B); - assert_eq!(C.rotate_left(64), C); + assert_eq!(B.rotate_left(128), B); + assert_eq!(C.rotate_left(128), C); } + */ @@ -72,8 +72,8 @@ index 04ed14f..a6e372e 100644 fn test_rotate() { assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); @@ -76,6 +77,7 @@ mod tests { - assert_eq!(B.rotate_left(64), B); - assert_eq!(C.rotate_left(64), C); + assert_eq!(B.rotate_left(128), B); + assert_eq!(C.rotate_left(128), C); } + */ diff --git a/prepare.sh b/prepare.sh index 87f96f5dcf41..08e7cb180299 100755 --- a/prepare.sh +++ b/prepare.sh @@ -24,6 +24,7 @@ git checkout -- . git checkout 804a7a21b9e673a482797aa289a18ed480e4d813 # build with cg_llvm for perf comparison +unset CARGO_TARGET_DIR cargo build mv target/debug/main raytracer_cg_llvm popd diff --git a/rust-toolchain b/rust-toolchain index 0ca96be9ae73..ed1e64f45db0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2020-10-31 +nightly-2020-11-27 diff --git a/scripts/cargo.sh b/scripts/cargo.sh index 947b4a28798f..dcd40acc02a5 100755 --- a/scripts/cargo.sh +++ b/scripts/cargo.sh @@ -1,16 +1,16 @@ #!/bin/bash dir=$(dirname "$0") -source $dir/config.sh +source "$dir/config.sh" # read nightly compiler from rust-toolchain file -TOOLCHAIN=$(cat $dir/rust-toolchain) +TOOLCHAIN=$(cat "$dir/rust-toolchain") cmd=$1 shift || true if [[ "$cmd" = "jit" ]]; then -cargo +${TOOLCHAIN} rustc "$@" -- --jit +cargo "+${TOOLCHAIN}" rustc "$@" -- --jit else -cargo +${TOOLCHAIN} $cmd "$@" +cargo "+${TOOLCHAIN}" "$cmd" "$@" fi diff --git a/scripts/config.sh b/scripts/config.sh index 6120a550a27a..dea037e2bc00 100644 --- a/scripts/config.sh +++ b/scripts/config.sh @@ -1,7 +1,8 @@ -#!/usr/bin/env bash +# Note to people running shellcheck: this file should only be sourced, not executed directly. + set -e -unamestr=`uname` +unamestr=$(uname) if [[ "$unamestr" == 'Linux' ]]; then dylib_ext='so' elif [[ "$unamestr" == 'Darwin' ]]; then @@ -40,19 +41,19 @@ echo export RUSTC_WRAPPER= fi -dir=$(cd $(dirname "$BASH_SOURCE"); pwd) +dir=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd) -export RUSTC=$dir"/cg_clif" -export RUSTFLAGS=$linker -export RUSTDOCFLAGS=$linker' -Ztrim-diagnostic-paths=no -Cpanic=abort -Zpanic-abort-tests '\ -'-Zcodegen-backend='$dir'/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$dir'/sysroot' +export RUSTC=$dir"/bin/cg_clif" +export RUSTFLAGS=$linker" "$RUSTFLAGS +export RUSTDOCFLAGS=$linker' -Cpanic=abort -Zpanic-abort-tests '\ +'-Zcodegen-backend='$dir'/lib/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$dir # FIXME remove once the atomic shim is gone -if [[ `uname` == 'Darwin' ]]; then +if [[ $(uname) == 'Darwin' ]]; then export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" fi -export LD_LIBRARY_PATH="$dir:$(rustc --print sysroot)/lib:$dir/target/out:$dir/sysroot/lib/rustlib/"$TARGET_TRIPLE"/lib" +export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib" export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH export CG_CLIF_DISPLAY_CG_TIME=1 diff --git a/scripts/rustup.sh b/scripts/rustup.sh index 541b3c6563ba..430f5c469b4b 100755 --- a/scripts/rustup.sh +++ b/scripts/rustup.sh @@ -7,13 +7,13 @@ case $1 in TOOLCHAIN=$(date +%Y-%m-%d) echo "=> Installing new nightly" - rustup toolchain install --profile minimal nightly-${TOOLCHAIN} # Sanity check to see if the nightly exists - echo nightly-${TOOLCHAIN} > rust-toolchain + rustup toolchain install --profile minimal "nightly-${TOOLCHAIN}" # Sanity check to see if the nightly exists + echo "nightly-${TOOLCHAIN}" > rust-toolchain rustup component add rustfmt || true echo "=> Uninstalling all old nighlies" - for nightly in $(rustup toolchain list | grep nightly | grep -v $TOOLCHAIN | grep -v nightly-x86_64); do - rustup toolchain uninstall $nightly + for nightly in $(rustup toolchain list | grep nightly | grep -v "$TOOLCHAIN" | grep -v nightly-x86_64); do + rustup toolchain uninstall "$nightly" done ./clean_all.sh @@ -27,14 +27,30 @@ case $1 in git commit -m "Rustup to $(rustc -V)" ;; "push") - cg_clif=$(pwd) - pushd ../rust - branch=update_cg_clif-$(date +%Y-%m-%d) - git checkout -b $branch - git subtree pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master - git push -u my $branch - popd + cg_clif=$(pwd) + pushd ../rust + git pull origin master + branch=sync_cg_clif-$(date +%Y-%m-%d) + git checkout -b "$branch" + git subtree pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master + git push -u my "$branch" + + # immediately merge the merge commit into cg_clif to prevent merge conflicts when syncing + # from rust-lang/rust later + git subtree push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust + popd + git merge sync_from_rust ;; + "pull") + cg_clif=$(pwd) + pushd ../rust + git pull origin master + rust_vers="$(git rev-parse HEAD)" + git subtree push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust + popd + git merge sync_from_rust -m "Sync from rust $rust_vers" + git branch -d sync_from_rust + ;; *) echo "Unknown command '$1'" echo "Usage: ./rustup.sh prepare|commit" diff --git a/scripts/test_bootstrap.sh b/scripts/test_bootstrap.sh index 7f43f81a6cdc..db69541b226c 100755 --- a/scripts/test_bootstrap.sh +++ b/scripts/test_bootstrap.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -cd $(dirname "$0")/../ +cd "$(dirname "$0")/../" ./build.sh source build/config.sh @@ -11,7 +11,7 @@ git clone https://github.com/rust-lang/rust.git || true pushd rust git fetch git checkout -- . -git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') +git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" git apply - < config.toml <( support_vararg: bool, ) -> (String, Signature) { assert!(!inst.substs.needs_infer()); - let fn_sig = tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - fn_sig_for_fn_abi(tcx, inst), - ); + let fn_sig = tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_sig_for_fn_abi(tcx, inst)); if fn_sig.c_variadic && !support_vararg { tcx.sess.span_fatal( tcx.def_span(inst.def_id()), diff --git a/src/archive.rs b/src/archive.rs index daf9fa6158f1..96579054389a 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -8,7 +8,7 @@ use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; use rustc_codegen_ssa::METADATA_FILENAME; use rustc_session::Session; -use object::{Object, SymbolKind}; +use object::{Object, ObjectSymbol, SymbolKind}; #[derive(Debug)] enum ArchiveEntry { @@ -184,7 +184,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { entry_name.as_bytes().to_vec(), object .symbols() - .filter_map(|(_index, symbol)| { + .filter_map(|symbol| { if symbol.is_undefined() || symbol.is_local() || symbol.kind() != SymbolKind::Data @@ -193,7 +193,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { { None } else { - symbol.name().map(|name| name.as_bytes().to_vec()) + symbol.name().map(|name| name.as_bytes().to_vec()).ok() } }) .collect::>(), diff --git a/src/atomic_shim.rs b/src/atomic_shim.rs index 2f0157c257b9..674e6d907510 100644 --- a/src/atomic_shim.rs +++ b/src/atomic_shim.rs @@ -7,8 +7,7 @@ use crate::prelude::*; #[cfg(all(feature = "jit", unix))] #[no_mangle] -static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t = - libc::PTHREAD_MUTEX_INITIALIZER; +static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; pub(crate) fn init_global_lock( module: &mut impl Module, diff --git a/src/base.rs b/src/base.rs index a4df371c88aa..72073896a723 100644 --- a/src/base.rs +++ b/src/base.rs @@ -12,6 +12,10 @@ pub(crate) fn codegen_fn<'tcx>( ) { let tcx = cx.tcx; + let _inst_guard = + crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name)); + debug_assert!(!instance.substs.needs_infer()); + let mir = tcx.instance_mir(instance.def); // Declare function @@ -499,7 +503,8 @@ fn codegen_stmt<'tcx>( UnOp::Neg => match layout.ty.kind() { ty::Int(IntTy::I128) => { // FIXME remove this case once ineg.i128 works - let zero = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size)); + let zero = + CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size)); crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand) } ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), @@ -509,7 +514,11 @@ fn codegen_stmt<'tcx>( }; lval.write_cvalue(fx, res); } - Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), ref operand, to_ty) => { + Rvalue::Cast( + CastKind::Pointer(PointerCast::ReifyFnPointer), + ref operand, + to_ty, + ) => { let from_ty = fx.monomorphize(operand.ty(&fx.mir.local_decls, fx.tcx)); let to_layout = fx.layout_of(fx.monomorphize(to_ty)); match *from_ty.kind() { @@ -530,9 +539,21 @@ fn codegen_stmt<'tcx>( _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", from_ty), } } - Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), ref operand, to_ty) - | Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), ref operand, to_ty) - | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), ref operand, to_ty) => { + Rvalue::Cast( + CastKind::Pointer(PointerCast::UnsafeFnPointer), + ref operand, + to_ty, + ) + | Rvalue::Cast( + CastKind::Pointer(PointerCast::MutToConstPointer), + ref operand, + to_ty, + ) + | Rvalue::Cast( + CastKind::Pointer(PointerCast::ArrayToPointer), + ref operand, + to_ty, + ) => { let to_layout = fx.layout_of(fx.monomorphize(to_ty)); let operand = codegen_operand(fx, operand); lval.write_cvalue(fx, operand.cast_pointer_to(to_layout)); diff --git a/src/bin/cg_clif.rs b/src/bin/cg_clif.rs index cd01acc9a832..f4d23ebcf4e4 100644 --- a/src/bin/cg_clif.rs +++ b/src/bin/cg_clif.rs @@ -26,15 +26,15 @@ impl rustc_driver::Callbacks for CraneliftPassesCallbacks { config.opts.cg.panic = Some(PanicStrategy::Abort); config.opts.debugging_opts.panic_abort_tests = true; - config.opts.maybe_sysroot = Some( - config.opts.maybe_sysroot.clone().unwrap_or_else( - || std::env::current_exe() - .unwrap() - .parent() - .unwrap() - .join("sysroot"), - ), - ); + config.opts.maybe_sysroot = Some(config.opts.maybe_sysroot.clone().unwrap_or_else(|| { + std::env::current_exe() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .to_owned() + })); } } diff --git a/src/common.rs b/src/common.rs index d7d6c3e16773..1485d4451b81 100644 --- a/src/common.rs +++ b/src/common.rs @@ -233,7 +233,7 @@ pub(crate) fn type_min_max_value( let min_msb = bcx.ins().iconst(types::I64, (min >> 64) as u64 as i64); let min = bcx.ins().iconcat(min_lsb, min_msb); - let max = i128::MIN as u128; + let max = i128::MAX as u128; let max_lsb = bcx.ins().iconst(types::I64, max as u64 as i64); let max_msb = bcx.ins().iconst(types::I64, (max >> 64) as u64 as i64); let max = bcx.ins().iconcat(max_lsb, max_msb); @@ -364,7 +364,7 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - value + value, ) } diff --git a/src/constant.rs b/src/constant.rs index 351bb6ecd238..544b020b7119 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -163,10 +163,7 @@ pub(crate) fn codegen_const_value<'tcx>( assert!(!layout.is_unsized(), "sized const value"); if layout.is_zst() { - return CValue::by_ref( - crate::Pointer::dangling(layout.align.pref), - layout, - ); + return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout); } match const_val { @@ -186,9 +183,7 @@ pub(crate) fn codegen_const_value<'tcx>( } match x { - Scalar::Int(int) => { - CValue::const_val(fx, layout, int) - } + Scalar::Int(int) => CValue::const_val(fx, layout, int), Scalar::Ptr(ptr) => { let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id); let base_addr = match alloc_kind { diff --git a/src/debuginfo/emit.rs b/src/debuginfo/emit.rs index f6f795e45615..c21835b1fc3a 100644 --- a/src/debuginfo/emit.rs +++ b/src/debuginfo/emit.rs @@ -76,7 +76,7 @@ impl WriterRelocate { #[cfg(feature = "jit")] pub(super) fn relocate_for_jit( mut self, - jit_product: &cranelift_simplejit::SimpleJITProduct, + jit_module: &cranelift_simplejit::SimpleJITModule, ) -> Vec { use std::convert::TryInto; @@ -84,8 +84,9 @@ impl WriterRelocate { match reloc.name { super::DebugRelocName::Section(_) => unreachable!(), super::DebugRelocName::Symbol(sym) => { - let addr = jit_product - .lookup_func(cranelift_module::FuncId::from_u32(sym.try_into().unwrap())); + let addr = jit_module.get_finalized_function( + cranelift_module::FuncId::from_u32(sym.try_into().unwrap()), + ); let val = (addr as u64 as i64 + reloc.addend) as u64; self.writer .write_udata_at(reloc.offset as usize, val, reloc.size) diff --git a/src/debuginfo/unwind.rs b/src/debuginfo/unwind.rs index 68138404c243..e0f62b64e6bb 100644 --- a/src/debuginfo/unwind.rs +++ b/src/debuginfo/unwind.rs @@ -80,7 +80,7 @@ impl<'tcx> UnwindContext<'tcx> { #[cfg(feature = "jit")] pub(crate) unsafe fn register_jit( self, - jit_product: &cranelift_simplejit::SimpleJITProduct, + jit_module: &cranelift_simplejit::SimpleJITModule, ) -> Option { let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(super::target_endian( self.tcx, @@ -91,7 +91,7 @@ impl<'tcx> UnwindContext<'tcx> { return None; } - let mut eh_frame = eh_frame.0.relocate_for_jit(jit_product); + let mut eh_frame = eh_frame.0.relocate_for_jit(jit_module); // GCC expects a terminating "empty" length, so write a 0 length at the end of the table. eh_frame.extend(&[0, 0, 0, 0]); diff --git a/src/discriminant.rs b/src/discriminant.rs index 1e8e86add1a5..ad635016a913 100644 --- a/src/discriminant.rs +++ b/src/discriminant.rs @@ -30,8 +30,16 @@ pub(crate) fn codegen_set_discriminant<'tcx>( .ty .discriminant_for_variant(fx.tcx, variant_index) .unwrap() - .val - .into(); + .val; + let to = if ptr.layout().abi.is_signed() { + ty::ScalarInt::try_from_int( + ptr.layout().size.sign_extend(to) as i128, + ptr.layout().size, + ) + .unwrap() + } else { + ty::ScalarInt::try_from_uint(to, ptr.layout().size).unwrap() + }; let discr = CValue::const_val(fx, ptr.layout(), to); ptr.write_cvalue(fx, discr); } @@ -49,8 +57,12 @@ pub(crate) fn codegen_set_discriminant<'tcx>( if variant_index != dataful_variant { let niche = place.place_field(fx, mir::Field::new(tag_field)); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); - let niche_value = u128::from(niche_value).wrapping_add(niche_start); - let niche_llval = CValue::const_val(fx, niche.layout(), niche_value.into()); + let niche_value = ty::ScalarInt::try_from_uint( + u128::from(niche_value).wrapping_add(niche_start), + niche.layout().size, + ) + .unwrap(); + let niche_llval = CValue::const_val(fx, niche.layout(), niche_value); niche.write_cvalue(fx, niche_llval); } } @@ -78,7 +90,16 @@ pub(crate) fn codegen_get_discriminant<'tcx>( .ty .discriminant_for_variant(fx.tcx, *index) .map_or(u128::from(index.as_u32()), |discr| discr.val); - return CValue::const_val(fx, dest_layout, discr_val.into()); + let discr_val = if dest_layout.abi.is_signed() { + ty::ScalarInt::try_from_int( + dest_layout.size.sign_extend(discr_val) as i128, + dest_layout.size, + ) + .unwrap() + } else { + ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap() + }; + return CValue::const_val(fx, dest_layout, discr_val); } Variants::Multiple { tag, diff --git a/src/driver/aot.rs b/src/driver/aot.rs index c0245aa1e021..491d6cbbf796 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -145,7 +145,11 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodege } let mut cx = crate::CodegenCx::new(tcx, module, tcx.sess.opts.debuginfo != DebugInfo::None); - super::codegen_mono_items(&mut cx, mono_items); + super::predefine_mono_items(&mut cx, &mono_items); + for (mono_item, (linkage, visibility)) in mono_items { + let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); + super::codegen_mono_item(&mut cx, mono_item, linkage); + } let (mut module, global_asm, debug, mut unwind_context) = tcx.sess.time("finalize CodegenCx", || cx.finalize()); crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context, false); diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 3f47df7d844b..5a844841c2ce 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -70,7 +70,11 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! { let (mut jit_module, global_asm, _debug, mut unwind_context) = super::time(tcx, "codegen mono items", || { - super::codegen_mono_items(&mut cx, mono_items); + super::predefine_mono_items(&mut cx, &mono_items); + for (mono_item, (linkage, visibility)) in mono_items { + let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); + super::codegen_mono_item(&mut cx, mono_item, linkage); + } tcx.sess.time("finalize CodegenCx", || cx.finalize()) }); if !global_asm.is_empty() { @@ -81,11 +85,11 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! { tcx.sess.abort_if_errors(); - let jit_product = jit_module.finish(); + jit_module.finalize_definitions(); - let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_product) }; + let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_module) }; - let finalized_main: *const u8 = jit_product.lookup_func(main_func_id); + let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id); println!("Rustc codegen cranelift will JIT run the executable, because --jit was passed"); @@ -140,11 +144,11 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { let mut imported_symbols = Vec::new(); for path in dylib_paths { - use object::Object; + use object::{Object, ObjectSymbol}; let lib = libloading::Library::new(&path).unwrap(); let obj = std::fs::read(path).unwrap(); let obj = object::File::parse(&obj).unwrap(); - imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| { + imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| { let name = symbol.name().unwrap().to_string(); if name.is_empty() || !symbol.is_global() || symbol.is_undefined() { return None; diff --git a/src/driver/mod.rs b/src/driver/mod.rs index a11dc57ee645..7b8cc2ddd48d 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -1,4 +1,4 @@ -//! Drivers are responsible for calling [`codegen_mono_items`] and performing any further actions +//! Drivers are responsible for calling [`codegen_mono_item`] and performing any further actions //! like JIT executing or writing object files. use std::any::Any; @@ -40,12 +40,12 @@ pub(crate) fn codegen_crate( aot::run_aot(tcx, metadata, need_metadata_module) } -fn codegen_mono_items<'tcx>( +fn predefine_mono_items<'tcx>( cx: &mut crate::CodegenCx<'tcx, impl Module>, - mono_items: Vec<(MonoItem<'tcx>, (RLinkage, Visibility))>, + mono_items: &[(MonoItem<'tcx>, (RLinkage, Visibility))], ) { cx.tcx.sess.time("predefine functions", || { - for &(mono_item, (linkage, visibility)) in &mono_items { + for &(mono_item, (linkage, visibility)) in mono_items { match mono_item { MonoItem::Fn(instance) => { let (name, sig) = get_function_name_and_sig( @@ -61,11 +61,6 @@ fn codegen_mono_items<'tcx>( } } }); - - for (mono_item, (linkage, visibility)) in mono_items { - let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); - codegen_mono_item(cx, mono_item, linkage); - } } fn codegen_mono_item<'tcx, M: Module>( @@ -73,20 +68,15 @@ fn codegen_mono_item<'tcx, M: Module>( mono_item: MonoItem<'tcx>, linkage: Linkage, ) { - let tcx = cx.tcx; match mono_item { MonoItem::Fn(inst) => { - let _inst_guard = - crate::PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name)); - debug_assert!(!inst.substs.needs_infer()); - tcx.sess + cx.tcx + .sess .time("codegen fn", || crate::base::codegen_fn(cx, inst, linkage)); } - MonoItem::Static(def_id) => { - crate::constant::codegen_static(&mut cx.constants_cx, def_id); - } + MonoItem::Static(def_id) => crate::constant::codegen_static(&mut cx.constants_cx, def_id), MonoItem::GlobalAsm(hir_id) => { - let item = tcx.hir().expect_item(hir_id); + let item = cx.tcx.hir().expect_item(hir_id); if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind { cx.global_asm.push_str(&*asm.as_str()); cx.global_asm.push_str("\n\n"); diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index ab16fabd348a..3563aa250a9b 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -263,6 +263,48 @@ fn simd_pair_for_each_lane<'tcx, M: Module>( } } +fn simd_reduce<'tcx, M: Module>( + fx: &mut FunctionCx<'_, 'tcx, M>, + val: CValue<'tcx>, + ret: CPlace<'tcx>, + f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, TyAndLayout<'tcx>, Value, Value) -> Value, +) { + let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout()); + assert_eq!(lane_layout, ret.layout()); + + let mut res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx); + for lane_idx in 1..lane_count { + let lane = val + .value_field(fx, mir::Field::new(lane_idx.into())) + .load_scalar(fx); + res_val = f(fx, lane_layout, res_val, lane); + } + let res = CValue::by_val(res_val, lane_layout); + ret.write_cvalue(fx, res); +} + +fn simd_reduce_bool<'tcx, M: Module>( + fx: &mut FunctionCx<'_, 'tcx, M>, + val: CValue<'tcx>, + ret: CPlace<'tcx>, + f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, Value, Value) -> Value, +) { + let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout()); + assert!(ret.layout().ty.is_bool()); + + let res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx); + let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean + for lane_idx in 1..lane_count { + let lane = val + .value_field(fx, mir::Field::new(lane_idx.into())) + .load_scalar(fx); + let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean + res_val = f(fx, res_val, lane); + } + let res = CValue::by_val(res_val, ret.layout()); + ret.write_cvalue(fx, res); +} + fn bool_to_zero_or_max_uint<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, layout: TyAndLayout<'tcx>, @@ -287,7 +329,7 @@ fn bool_to_zero_or_max_uint<'tcx>( } macro simd_cmp { - ($fx:expr, $cc:ident($x:ident, $y:ident) -> $ret:ident) => { + ($fx:expr, $cc:ident|$cc_f:ident($x:ident, $y:ident) -> $ret:ident) => { let vector_ty = clif_vector_type($fx.tcx, $x.layout()); if let Some(vector_ty) = vector_ty { @@ -308,6 +350,7 @@ macro simd_cmp { |fx, lane_layout, res_lane_layout, x_lane, y_lane| { let res_lane = match lane_layout.ty.kind() { ty::Uint(_) | ty::Int(_) => fx.bcx.ins().icmp(IntCC::$cc, x_lane, y_lane), + ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::$cc_f, x_lane, y_lane), _ => unreachable!("{:?}", lane_layout.ty), }; bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane) @@ -315,7 +358,7 @@ macro simd_cmp { ); } }, - ($fx:expr, $cc_u:ident|$cc_s:ident($x:ident, $y:ident) -> $ret:ident) => { + ($fx:expr, $cc_u:ident|$cc_s:ident|$cc_f:ident($x:ident, $y:ident) -> $ret:ident) => { // FIXME use vector icmp when possible simd_pair_for_each_lane( $fx, @@ -326,6 +369,7 @@ macro simd_cmp { let res_lane = match lane_layout.ty.kind() { ty::Uint(_) => fx.bcx.ins().icmp(IntCC::$cc_u, x_lane, y_lane), ty::Int(_) => fx.bcx.ins().icmp(IntCC::$cc_s, x_lane, y_lane), + ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::$cc_f, x_lane, y_lane), _ => unreachable!("{:?}", lane_layout.ty), }; bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane) @@ -497,12 +541,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( }; copy | copy_nonoverlapping, (v src, v dst, v count) { let elem_size: u64 = fx.layout_of(elem_ty).size.bytes(); - let elem_size = fx - .bcx - .ins() - .iconst(fx.pointer_type, elem_size as i64); assert_eq!(args.len(), 3); - let byte_amount = fx.bcx.ins().imul(count, elem_size); + let byte_amount = if elem_size != 1 { + fx.bcx.ins().imul_imm(count, elem_size as i64) + } else { + count + }; if intrinsic.contains("nonoverlapping") { // FIXME emit_small_memcpy @@ -515,12 +559,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( // NOTE: the volatile variants have src and dst swapped volatile_copy_memory | volatile_copy_nonoverlapping_memory, (v dst, v src, v count) { let elem_size: u64 = fx.layout_of(elem_ty).size.bytes(); - let elem_size = fx - .bcx - .ins() - .iconst(fx.pointer_type, elem_size as i64); assert_eq!(args.len(), 3); - let byte_amount = fx.bcx.ins().imul(count, elem_size); + let byte_amount = if elem_size != 1 { + fx.bcx.ins().imul_imm(count, elem_size as i64) + } else { + count + }; // FIXME make the copy actually volatile when using emit_small_mem{cpy,move} if intrinsic.contains("nonoverlapping") { @@ -676,7 +720,11 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( offset | arith_offset, (c base, v offset) { let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty; let pointee_size = fx.layout_of(pointee_ty).size.bytes(); - let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); + let ptr_diff = if pointee_size != 1 { + fx.bcx.ins().imul_imm(offset, pointee_size as i64) + } else { + offset + }; let base_val = base.load_scalar(fx); let res = fx.bcx.ins().iadd(base_val, ptr_diff); ret.write_cvalue(fx, CValue::by_val(res, base.layout())); @@ -688,7 +736,11 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( write_bytes | volatile_set_memory, (c dst, v val, v count) { let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty; let pointee_size = fx.layout_of(pointee_ty).size.bytes(); - let count = fx.bcx.ins().imul_imm(count, pointee_size as i64); + let count = if pointee_size != 1 { + fx.bcx.ins().imul_imm(count, pointee_size as i64) + } else { + count + }; let dst_ptr = dst.load_scalar(fx); // FIXME make the memset actually volatile when switching to emit_small_memset // FIXME use emit_small_memset diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 2e31c4669e25..2b32e866e5ef 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -35,30 +35,33 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); }; - // FIXME support float comparisons simd_eq, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, Equal(x, y) -> ret); + simd_cmp!(fx, Equal|Equal(x, y) -> ret); }; simd_ne, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, NotEqual(x, y) -> ret); + simd_cmp!(fx, NotEqual|NotEqual(x, y) -> ret); }; simd_lt, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, UnsignedLessThan|SignedLessThan(x, y) -> ret); + simd_cmp!(fx, UnsignedLessThan|SignedLessThan|LessThan(x, y) -> ret); }; simd_le, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, UnsignedLessThanOrEqual|SignedLessThanOrEqual(x, y) -> ret); + simd_cmp!(fx, UnsignedLessThanOrEqual|SignedLessThanOrEqual|LessThanOrEqual(x, y) -> ret); }; simd_gt, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, UnsignedGreaterThan|SignedGreaterThan(x, y) -> ret); + simd_cmp!(fx, UnsignedGreaterThan|SignedGreaterThan|GreaterThan(x, y) -> ret); }; simd_ge, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, UnsignedGreaterThanOrEqual|SignedGreaterThanOrEqual(x, y) -> ret); + simd_cmp!( + fx, + UnsignedGreaterThanOrEqual|SignedGreaterThanOrEqual|GreaterThanOrEqual + (x, y) -> ret + ); }; // simd_shuffle32(x: T, y: T, idx: [u32; 32]) -> U @@ -107,9 +110,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( for (out_idx, in_idx) in indexes.into_iter().enumerate() { let in_lane = if in_idx < lane_count { - x.value_field(fx, mir::Field::new(in_idx.try_into().unwrap())) + x.value_field(fx, mir::Field::new(in_idx.into())) } else { - y.value_field(fx, mir::Field::new((in_idx - lane_count).try_into().unwrap())) + y.value_field(fx, mir::Field::new((in_idx - lane_count).into())) }; let out_lane = ret.place_field(fx, mir::Field::new(out_idx)); out_lane.write_cvalue(fx, in_lane); @@ -143,10 +146,17 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) { idx_const } else { - fx.tcx.sess.span_fatal( + fx.tcx.sess.span_warn( span, "Index argument for `simd_extract` is not a constant", ); + let res = crate::trap::trap_unimplemented_ret_value( + fx, + ret.layout(), + "Index argument for `simd_extract` is not a constant", + ); + ret.write_cvalue(fx, res); + return; }; let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); @@ -207,7 +217,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( assert_eq!(lane_count, ret_lane_count); for lane in 0..lane_count { - let lane = mir::Field::new(lane.try_into().unwrap()); + let lane = mir::Field::new(lane.into()); let a_lane = a.value_field(fx, lane).load_scalar(fx); let b_lane = b.value_field(fx, lane).load_scalar(fx); let c_lane = c.value_field(fx, lane).load_scalar(fx); @@ -228,11 +238,42 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_flt_binop!(fx, fmax(x, y) -> ret); }; + simd_reduce_add_ordered | simd_reduce_add_unordered, (c v) { + validate_simd_type!(fx, intrinsic, span, v.layout().ty); + simd_reduce(fx, v, ret, |fx, lane_layout, a, b| { + if lane_layout.ty.is_floating_point() { + fx.bcx.ins().fadd(a, b) + } else { + fx.bcx.ins().iadd(a, b) + } + }); + }; + + simd_reduce_mul_ordered | simd_reduce_mul_unordered, (c v) { + validate_simd_type!(fx, intrinsic, span, v.layout().ty); + simd_reduce(fx, v, ret, |fx, lane_layout, a, b| { + if lane_layout.ty.is_floating_point() { + fx.bcx.ins().fmul(a, b) + } else { + fx.bcx.ins().imul(a, b) + } + }); + }; + + simd_reduce_all, (c v) { + validate_simd_type!(fx, intrinsic, span, v.layout().ty); + simd_reduce_bool(fx, v, ret, |fx, a, b| fx.bcx.ins().band(a, b)); + }; + + simd_reduce_any, (c v) { + validate_simd_type!(fx, intrinsic, span, v.layout().ty); + simd_reduce_bool(fx, v, ret, |fx, a, b| fx.bcx.ins().bor(a, b)); + }; + // simd_fabs // simd_saturating_add // simd_bitmask // simd_select - // simd_reduce_add_{,un}ordered // simd_rem } } diff --git a/src/trap.rs b/src/trap.rs index 690d96764a8f..67495c741484 100644 --- a/src/trap.rs +++ b/src/trap.rs @@ -67,3 +67,15 @@ pub(crate) fn trap_unimplemented(fx: &mut FunctionCx<'_, '_, impl Module>, msg: let true_ = fx.bcx.ins().iconst(types::I32, 1); fx.bcx.ins().trapnz(true_, TrapCode::User(!0)); } + +/// Like `trap_unimplemented` but returns a fake value of the specified type. +/// +/// Trap code: user65535 +pub(crate) fn trap_unimplemented_ret_value<'tcx>( + fx: &mut FunctionCx<'_, 'tcx, impl Module>, + dest_layout: TyAndLayout<'tcx>, + msg: impl AsRef, +) -> CValue<'tcx> { + trap_unimplemented(fx, msg); + CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout) +} From 9db1f42fa2ac096771ff956d89bcc148842859b6 Mon Sep 17 00:00:00 2001 From: Ellen Date: Sat, 28 Nov 2020 00:30:26 +0000 Subject: [PATCH 051/719] Stabilize unsafe_cell_get_mut --- library/core/src/cell.rs | 4 +--- library/std/src/lib.rs | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index e1b6307613b7..2d01a26df616 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1618,7 +1618,6 @@ impl fmt::Display for RefMut<'_, T> { /// implies exclusive access to its `T`: /// /// ```rust -/// #![feature(unsafe_cell_get_mut)] /// #![forbid(unsafe_code)] // with exclusive accesses, /// // `UnsafeCell` is a transparent no-op wrapper, /// // so no need for `unsafe` here. @@ -1722,7 +1721,6 @@ impl UnsafeCell { /// # Examples /// /// ``` - /// #![feature(unsafe_cell_get_mut)] /// use std::cell::UnsafeCell; /// /// let mut c = UnsafeCell::new(5); @@ -1731,7 +1729,7 @@ impl UnsafeCell { /// assert_eq!(*c.get_mut(), 6); /// ``` #[inline] - #[unstable(feature = "unsafe_cell_get_mut", issue = "76943")] + #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")] pub fn get_mut(&mut self) -> &mut T { &mut self.value } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f33804c988a1..5fcfee711ec7 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -320,7 +320,6 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unsafe_block_in_unsafe_fn)] -#![feature(unsafe_cell_get_mut)] #![feature(unsafe_cell_raw_get)] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] From 0bb82c4a059934f78a67ff0ff9e4517171ad1dab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Nov 2020 18:02:12 +0100 Subject: [PATCH 052/719] expand iter_projections comment --- compiler/rustc_middle/src/mir/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 2bd30001a915..62e5a1e18f88 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1744,6 +1744,10 @@ impl<'tcx> Place<'tcx> { /// Iterate over the projections in evaluation order, i.e., the first element is the base with /// its projection and then subsequently more projections are added. + /// As a concrete example, given the place a.b.c, this would yield: + /// - (a, .b) + /// - (a.b, .c) + /// Given a place without projections, the iterator is empty. pub fn iter_projections( self, ) -> impl Iterator, PlaceElem<'tcx>)> + DoubleEndedIterator { From 75eb72cc9c23d31f10bd7b4ec6331dd8383cf829 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 15 Nov 2020 13:03:30 +0000 Subject: [PATCH 053/719] passes: prohibit attrs on generic params This commit modifies the `check_attr` pass so that attribute placement on generic parameters is checked for validity. Signed-off-by: David Wood --- compiler/rustc_hir/src/target.rs | 23 +++++++ compiler/rustc_passes/src/check_attr.rs | 12 ++++ src/test/ui/issues/issue-78957.rs | 30 ++++++++ src/test/ui/issues/issue-78957.stderr | 69 +++++++++++++++++++ .../ui/proc-macro/ambiguous-builtin-attrs.rs | 4 +- .../proc-macro/ambiguous-builtin-attrs.stderr | 14 ++-- 6 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-78957.rs create mode 100644 src/test/ui/issues/issue-78957.stderr diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index b870e4c6ead8..2774cc9c08e1 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -9,6 +9,13 @@ use crate::{Item, ItemKind, TraitItem, TraitItemKind}; use std::fmt::{self, Display}; +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum GenericParamKind { + Type, + Lifetime, + Const, +} + #[derive(Copy, Clone, PartialEq, Debug)] pub enum MethodKind { Trait { body: bool }, @@ -43,6 +50,7 @@ pub enum Target { ForeignFn, ForeignStatic, ForeignTy, + GenericParam(GenericParamKind), } impl Display for Target { @@ -77,6 +85,11 @@ impl Display for Target { Target::ForeignFn => "foreign function", Target::ForeignStatic => "foreign static item", Target::ForeignTy => "foreign type", + Target::GenericParam(kind) => match kind { + GenericParamKind::Type => "type parameter", + GenericParamKind::Lifetime => "lifetime parameter", + GenericParamKind::Const => "const parameter", + }, } ) } @@ -124,4 +137,14 @@ impl Target { hir::ForeignItemKind::Type => Target::ForeignTy, } } + + pub fn from_generic_param(generic_param: &hir::GenericParam<'_>) -> Target { + match generic_param.kind { + hir::GenericParamKind::Type { .. } => Target::GenericParam(GenericParamKind::Type), + hir::GenericParamKind::Lifetime { .. } => { + Target::GenericParam(GenericParamKind::Lifetime) + } + hir::GenericParamKind::Const { .. } => Target::GenericParam(GenericParamKind::Const), + } + } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9c0234953bba..e0babd1885be 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -814,6 +814,18 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_item(self, item) } + fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) { + let target = Target::from_generic_param(generic_param); + self.check_attributes( + generic_param.hir_id, + generic_param.attrs, + &generic_param.span, + target, + None, + ); + intravisit::walk_generic_param(self, generic_param) + } + fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) { let target = Target::from_trait_item(trait_item); self.check_attributes(trait_item.hir_id, &trait_item.attrs, &trait_item.span, target, None); diff --git a/src/test/ui/issues/issue-78957.rs b/src/test/ui/issues/issue-78957.rs new file mode 100644 index 000000000000..263c69bbc0b6 --- /dev/null +++ b/src/test/ui/issues/issue-78957.rs @@ -0,0 +1,30 @@ +#![deny(unused_attributes)] +#![feature(min_const_generics)] + +use std::marker::PhantomData; + +pub struct Foo<#[inline] const N: usize>; +//~^ ERROR attribute should be applied to function or closure +pub struct Bar<#[cold] const N: usize>; +//~^ ERROR attribute should be applied to a function +//~| WARN this was previously accepted +pub struct Baz<#[repr(C)] const N: usize>; +//~^ ERROR attribute should be applied to a struct, enum, or union +// +pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); +//~^ ERROR attribute should be applied to function or closure +pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); +//~^ ERROR attribute should be applied to a function +//~| WARN this was previously accepted +pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>); +//~^ ERROR attribute should be applied to a struct, enum, or union +// +pub struct Foo3<#[inline] T>(PhantomData); +//~^ ERROR attribute should be applied to function or closure +pub struct Bar3<#[cold] T>(PhantomData); +//~^ ERROR attribute should be applied to a function +//~| WARN this was previously accepted +pub struct Baz3<#[repr(C)] T>(PhantomData); +//~^ ERROR attribute should be applied to a struct, enum, or union + +fn main() {} diff --git a/src/test/ui/issues/issue-78957.stderr b/src/test/ui/issues/issue-78957.stderr new file mode 100644 index 000000000000..26437ee4befd --- /dev/null +++ b/src/test/ui/issues/issue-78957.stderr @@ -0,0 +1,69 @@ +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-78957.rs:6:16 + | +LL | pub struct Foo<#[inline] const N: usize>; + | ^^^^^^^^^ - not a function or closure + +error: attribute should be applied to a function + --> $DIR/issue-78957.rs:8:16 + | +LL | pub struct Bar<#[cold] const N: usize>; + | ^^^^^^^ - not a function + | +note: the lint level is defined here + --> $DIR/issue-78957.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-78957.rs:11:23 + | +LL | pub struct Baz<#[repr(C)] const N: usize>; + | ^ - not a struct, enum, or union + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-78957.rs:14:17 + | +LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); + | ^^^^^^^^^ -- not a function or closure + +error: attribute should be applied to a function + --> $DIR/issue-78957.rs:16:17 + | +LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); + | ^^^^^^^ -- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-78957.rs:19:24 + | +LL | pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>); + | ^ -- not a struct, enum, or union + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-78957.rs:22:17 + | +LL | pub struct Foo3<#[inline] T>(PhantomData); + | ^^^^^^^^^ - not a function or closure + +error: attribute should be applied to a function + --> $DIR/issue-78957.rs:24:17 + | +LL | pub struct Bar3<#[cold] T>(PhantomData); + | ^^^^^^^ - not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-78957.rs:27:24 + | +LL | pub struct Baz3<#[repr(C)] T>(PhantomData); + | ^ - not a struct, enum, or union + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0517, E0518. +For more information about an error, try `rustc --explain E0517`. diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs index 9f4f0abf3248..142efb3c6cdc 100644 --- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs +++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs @@ -17,7 +17,9 @@ fn test() {} #[bench] // OK, shadowed fn bench() {} -fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous +fn non_macro_expanded_location<#[repr(C)] T>() { + //~^ ERROR `repr` is ambiguous + //~| ERROR attribute should be applied to a struct, enum, or union match 0u8 { #[repr(C)] //~ ERROR `repr` is ambiguous _ => {} diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr index 23310f6c6f52..276ee1cfd356 100644 --- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr +++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `NonExistent` in this scope - --> $DIR/ambiguous-builtin-attrs.rs:30:5 + --> $DIR/ambiguous-builtin-attrs.rs:32:5 | LL | NonExistent; | ^^^^^^^^^^^ not found in this scope @@ -47,7 +47,7 @@ LL | use builtin_attrs::*; = help: use `crate::repr` to refer to this attribute macro unambiguously error[E0659]: `repr` is ambiguous (built-in attribute vs any other name) - --> $DIR/ambiguous-builtin-attrs.rs:22:11 + --> $DIR/ambiguous-builtin-attrs.rs:24:11 | LL | #[repr(C)] | ^^^^ ambiguous name @@ -74,7 +74,13 @@ LL | use builtin_attrs::*; | ^^^^^^^^^^^^^^^^ = help: use `crate::feature` to refer to this attribute macro unambiguously -error: aborting due to 6 previous errors +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/ambiguous-builtin-attrs.rs:20:39 + | +LL | fn non_macro_expanded_location<#[repr(C)] T>() { + | ^ - not a struct, enum, or union -Some errors have detailed explanations: E0425, E0659. +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0425, E0517, E0659. For more information about an error, try `rustc --explain E0425`. From 7760894d3fcd2a1048e8f61d3e64124a94a726d0 Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 29 Nov 2020 14:56:19 +0000 Subject: [PATCH 054/719] Allow cranelift to handle atomic pointers --- src/intrinsics/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index ab16fabd348a..e5482187a731 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -146,12 +146,12 @@ macro atomic_minmax($fx:expr, $cc:expr, <$T:ident> ($ptr:ident, $src:ident) -> $ macro validate_atomic_type($fx:ident, $intrinsic:ident, $span:ident, $ty:expr) { match $ty.kind() { - ty::Uint(_) | ty::Int(_) => {} + ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { $fx.tcx.sess.span_err( $span, &format!( - "`{}` intrinsic: expected basic integer type, found `{:?}`", + "`{}` intrinsic: expected basic integer or raw pointer type, found `{:?}`", $intrinsic, $ty ), ); From 1a1a99ccb7be53c0a14d52ef825caf0fb9fa01a5 Mon Sep 17 00:00:00 2001 From: Ellen Date: Sun, 29 Nov 2020 20:27:01 +0000 Subject: [PATCH 055/719] Change "non-unsafe" to "safe" in UnsafeCell docs --- library/core/src/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 2d01a26df616..cec40aebd74f 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1580,7 +1580,7 @@ impl fmt::Display for RefMut<'_, T> { /// `&UnsafeCell<_>` reference); there is no magic whatsoever when dealing with _exclusive_ /// accesses (_e.g._, through an `&mut UnsafeCell<_>`): neither the cell nor the wrapped value /// may be aliased for the duration of that `&mut` borrow. -/// This is showcased by the [`.get_mut()`] accessor, which is a non-`unsafe` getter that yields +/// This is showcased by the [`.get_mut()`] accessor, which is a _safe_ getter that yields /// a `&mut T`. /// /// [`.get_mut()`]: `UnsafeCell::get_mut` From 06ca6bba8dd21fe3330b2212a34c6bf244300486 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 22 Nov 2020 21:58:41 +0000 Subject: [PATCH 056/719] Add tests --- .../overlapping_range_endpoints.rs | 6 ++++++ .../overlapping_range_endpoints.stderr | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs index af720a056932..2463d5cf4dc9 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs @@ -33,6 +33,12 @@ fn main() { m!(0u8, 25, 20..=30); m!(0u8, 30, 20..=30); //~ ERROR multiple patterns covering the same range + match 0u8 { + 0..=10 => {} + 20..=30 => {} + 10..=20 => {} //~ ERROR multiple patterns covering the same range + _ => {} + } match (0u8, true) { (0..=10, true) => {} (10..20, true) => {} // not detected diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr index 7bb747cdf6fc..5351a7e61c22 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr @@ -61,7 +61,17 @@ LL | m!(0u8, 30, 20..=30); | this range overlaps on `30_u8` error: multiple patterns covering the same range - --> $DIR/overlapping_range_endpoints.rs:44:16 + --> $DIR/overlapping_range_endpoints.rs:39:9 + | +LL | 0..=10 => {} + | ------ this range overlaps on `10_u8` +LL | 20..=30 => {} + | ------- this range overlaps on `20_u8` +LL | 10..=20 => {} + | ^^^^^^^ overlapping patterns + +error: multiple patterns covering the same range + --> $DIR/overlapping_range_endpoints.rs:50:16 | LL | (true, 0..=10) => {} | ------ this range overlaps on `10_u8` @@ -69,12 +79,12 @@ LL | (true, 10..20) => {} | ^^^^^^ overlapping patterns error: multiple patterns covering the same range - --> $DIR/overlapping_range_endpoints.rs:50:14 + --> $DIR/overlapping_range_endpoints.rs:56:14 | LL | Some(0..=10) => {} | ------ this range overlaps on `10_u8` LL | Some(10..20) => {} | ^^^^^^ overlapping patterns -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors From d1a50ffb7c332677f3c613540d507114c83e0f86 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 22 Oct 2020 18:34:00 +0100 Subject: [PATCH 057/719] Rename the `overlapping_patterns` lint to `overlapping_range_endpoints` --- compiler/rustc_lint/src/lib.rs | 3 +- compiler/rustc_lint_defs/src/builtin.rs | 17 ++++--- .../src/thir/pattern/deconstruct_pat.rs | 13 +++--- src/test/ui/issues/issue-21475.rs | 2 +- src/test/ui/issues/issue-26251.rs | 2 +- .../overlapping_range_endpoints.rs | 22 +++++----- .../overlapping_range_endpoints.stderr | 44 +++++++++---------- 7 files changed, 52 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 81549be4b091..d5e77843b92d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -283,7 +283,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { UNUSED_MUT, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, - OVERLAPPING_PATTERNS, + OVERLAPPING_RANGE_ENDPOINTS, UNUSED_MUST_USE, UNUSED_UNSAFE, PATH_STATEMENTS, @@ -335,6 +335,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { store.register_renamed("exceeding_bitshifts", "arithmetic_overflow"); store.register_renamed("redundant_semicolon", "redundant_semicolons"); store.register_renamed("intra_doc_link_resolution_failure", "broken_intra_doc_links"); + store.register_renamed("overlapping_patterns", "overlapping_range_endpoints"); store.register_removed("unknown_features", "replaced by an error"); store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); store.register_removed("negate_unsigned", "cast a signed value instead"); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index fa82dce0ae2e..20ea7377e3ff 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -588,8 +588,8 @@ declare_lint! { } declare_lint! { - /// The `overlapping_patterns` lint detects `match` arms that have - /// [range patterns] that overlap. + /// The `overlapping_range_endpoints` lint detects `match` arms that have [range patterns] that + /// overlap on their endpoints. /// /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns /// @@ -607,13 +607,12 @@ declare_lint! { /// /// ### Explanation /// - /// It is likely a mistake to have range patterns in a match expression - /// that overlap. Check that the beginning and end values are what you - /// expect, and keep in mind that with `..=` the left and right bounds are - /// inclusive. - pub OVERLAPPING_PATTERNS, + /// It is likely a mistake to have range patterns in a match expression that overlap in this + /// way. Check that the beginning and end values are what you expect, and keep in mind that + /// with `..=` the left and right bounds are inclusive. + pub OVERLAPPING_RANGE_ENDPOINTS, Warn, - "detects overlapping patterns" + "detects range patterns with overlapping endpoints" } declare_lint! { @@ -2765,7 +2764,7 @@ declare_lint_pass! { DEAD_CODE, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, - OVERLAPPING_PATTERNS, + OVERLAPPING_RANGE_ENDPOINTS, BINDINGS_WITH_VARIANT_NAME, UNUSED_MACROS, WARNINGS, diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 3b2eef5a905d..34cb9ff1cc5f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -273,7 +273,7 @@ impl IntRange { let mut borders: Vec<_> = row_borders.chain(self_borders).collect(); borders.sort_unstable(); - self.lint_overlapping_patterns(pcx, hir_id, overlaps); + self.lint_overlapping_range_endpoints(pcx, hir_id, overlaps); // We're going to iterate through every adjacent pair of borders, making sure that // each represents an interval of nonnegative length, and convert each such @@ -296,7 +296,7 @@ impl IntRange { .collect() } - fn lint_overlapping_patterns( + fn lint_overlapping_range_endpoints( &self, pcx: PatCtxt<'_, '_, '_>, hir_id: Option, @@ -304,22 +304,23 @@ impl IntRange { ) { if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) { pcx.cx.tcx.struct_span_lint_hir( - lint::builtin::OVERLAPPING_PATTERNS, + lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, hir_id, pcx.span, |lint| { - let mut err = lint.build("multiple patterns covering the same range"); - err.span_label(pcx.span, "overlapping patterns"); + let mut err = lint.build("multiple patterns overlap on their endpoints"); + err.span_label(pcx.span, "overlapping range endpoints"); for (int_range, span) in overlaps { // Use the real type for user display of the ranges: err.span_label( span, &format!( "this range overlaps on `{}`", - int_range.to_pat(pcx.cx.tcx, pcx.ty), + int_range.to_pat(pcx.cx.tcx, pcx.ty) ), ); } + // FIXME: add note err.emit(); }, ); diff --git a/src/test/ui/issues/issue-21475.rs b/src/test/ui/issues/issue-21475.rs index ab0a18869632..b028fcae0775 100644 --- a/src/test/ui/issues/issue-21475.rs +++ b/src/test/ui/issues/issue-21475.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(unused_imports, overlapping_patterns)] +#![allow(unused_imports, overlapping_range_endpoints)] // pretty-expanded FIXME #23616 use m::{START, END}; diff --git a/src/test/ui/issues/issue-26251.rs b/src/test/ui/issues/issue-26251.rs index edb06fea8ad5..a3e26a41232c 100644 --- a/src/test/ui/issues/issue-26251.rs +++ b/src/test/ui/issues/issue-26251.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(overlapping_patterns)] +#![allow(overlapping_range_endpoints)] fn main() { let x = 'a'; diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs index 2463d5cf4dc9..6ad87d873ee6 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs @@ -1,5 +1,5 @@ #![feature(exclusive_range_pattern)] -#![deny(overlapping_patterns)] +#![deny(overlapping_range_endpoints)] macro_rules! m { ($s:expr, $t1:pat, $t2:pat) => { @@ -12,31 +12,31 @@ macro_rules! m { } fn main() { - m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns covering the same range - m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns covering the same range + m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns overlap on their endpoints m!(0u8, 20..=30, 31..=40); m!(0u8, 20..=30, 29..=40); - m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns covering the same range + m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns overlap on their endpoints m!(0u8, 20.. 30, 28..=40); m!(0u8, 20.. 30, 30..=40); m!(0u8, 20..=30, 30..=30); - m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns covering the same range + m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns overlap on their endpoints m!(0u8, 20..=30, 29..=30); m!(0u8, 20..=30, 20..=20); m!(0u8, 20..=30, 20..=21); - m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns covering the same range + m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns overlap on their endpoints m!(0u8, 20..=30, 20); m!(0u8, 20..=30, 25); m!(0u8, 20..=30, 30); m!(0u8, 20.. 30, 29); - m!(0u8, 20, 20..=30); //~ ERROR multiple patterns covering the same range + m!(0u8, 20, 20..=30); //~ ERROR multiple patterns overlap on their endpoints m!(0u8, 25, 20..=30); - m!(0u8, 30, 20..=30); //~ ERROR multiple patterns covering the same range + m!(0u8, 30, 20..=30); //~ ERROR multiple patterns overlap on their endpoints match 0u8 { 0..=10 => {} 20..=30 => {} - 10..=20 => {} //~ ERROR multiple patterns covering the same range + 10..=20 => {} //~ ERROR multiple patterns overlap on their endpoints _ => {} } match (0u8, true) { @@ -47,13 +47,13 @@ fn main() { } match (true, 0u8) { (true, 0..=10) => {} - (true, 10..20) => {} //~ ERROR multiple patterns covering the same range + (true, 10..20) => {} //~ ERROR multiple patterns overlap on their endpoints (false, 10..20) => {} _ => {} } match Some(0u8) { Some(0..=10) => {} - Some(10..20) => {} //~ ERROR multiple patterns covering the same range + Some(10..20) => {} //~ ERROR multiple patterns overlap on their endpoints _ => {} } } diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr index 5351a7e61c22..56995421f2ba 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr @@ -1,66 +1,66 @@ -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:15:22 | LL | m!(0u8, 20..=30, 30..=40); - | ------- ^^^^^^^ overlapping patterns + | ------- ^^^^^^^ overlapping range endpoints | | | this range overlaps on `30_u8` | note: the lint level is defined here --> $DIR/overlapping_range_endpoints.rs:2:9 | -LL | #![deny(overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(overlapping_range_endpoints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:16:22 | LL | m!(0u8, 30..=40, 20..=30); - | ------- ^^^^^^^ overlapping patterns + | ------- ^^^^^^^ overlapping range endpoints | | | this range overlaps on `30_u8` -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:19:22 | LL | m!(0u8, 20.. 30, 29..=40); - | ------- ^^^^^^^ overlapping patterns + | ------- ^^^^^^^ overlapping range endpoints | | | this range overlaps on `29_u8` -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:23:22 | LL | m!(0u8, 20..=30, 30..=31); - | ------- ^^^^^^^ overlapping patterns + | ------- ^^^^^^^ overlapping range endpoints | | | this range overlaps on `30_u8` -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:27:22 | LL | m!(0u8, 20..=30, 19..=20); - | ------- ^^^^^^^ overlapping patterns + | ------- ^^^^^^^ overlapping range endpoints | | | this range overlaps on `20_u8` -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:32:17 | LL | m!(0u8, 20, 20..=30); - | -- ^^^^^^^ overlapping patterns + | -- ^^^^^^^ overlapping range endpoints | | | this range overlaps on `20_u8` -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:34:17 | LL | m!(0u8, 30, 20..=30); - | -- ^^^^^^^ overlapping patterns + | -- ^^^^^^^ overlapping range endpoints | | | this range overlaps on `30_u8` -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:39:9 | LL | 0..=10 => {} @@ -68,23 +68,23 @@ LL | 0..=10 => {} LL | 20..=30 => {} | ------- this range overlaps on `20_u8` LL | 10..=20 => {} - | ^^^^^^^ overlapping patterns + | ^^^^^^^ overlapping range endpoints -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:50:16 | LL | (true, 0..=10) => {} | ------ this range overlaps on `10_u8` LL | (true, 10..20) => {} - | ^^^^^^ overlapping patterns + | ^^^^^^ overlapping range endpoints -error: multiple patterns covering the same range +error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:56:14 | LL | Some(0..=10) => {} | ------ this range overlaps on `10_u8` LL | Some(10..20) => {} - | ^^^^^^ overlapping patterns + | ^^^^^^ overlapping range endpoints error: aborting due to 10 previous errors From c89d439bb5c18608054d767e5b472679fa2f01da Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 22 Oct 2020 19:25:55 +0100 Subject: [PATCH 058/719] Be consistent about linting singletons --- .../src/thir/pattern/deconstruct_pat.rs | 2 +- .../overlapping_range_endpoints.rs | 4 ++-- .../overlapping_range_endpoints.stderr | 18 +----------------- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 34cb9ff1cc5f..7c466ff591ce 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -161,7 +161,7 @@ impl IntRange { // 2 -------- // 2 ------- let (lo, hi) = self.boundaries(); let (other_lo, other_hi) = other.boundaries(); - lo == other_hi || hi == other_lo + (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton() } fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs index 6ad87d873ee6..5ea92b07081a 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs @@ -29,9 +29,9 @@ fn main() { m!(0u8, 20..=30, 25); m!(0u8, 20..=30, 30); m!(0u8, 20.. 30, 29); - m!(0u8, 20, 20..=30); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20, 20..=30); m!(0u8, 25, 20..=30); - m!(0u8, 30, 20..=30); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 30, 20..=30); match 0u8 { 0..=10 => {} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr index 56995421f2ba..f694e4c9aab8 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr @@ -44,22 +44,6 @@ LL | m!(0u8, 20..=30, 19..=20); | | | this range overlaps on `20_u8` -error: multiple patterns overlap on their endpoints - --> $DIR/overlapping_range_endpoints.rs:32:17 - | -LL | m!(0u8, 20, 20..=30); - | -- ^^^^^^^ overlapping range endpoints - | | - | this range overlaps on `20_u8` - -error: multiple patterns overlap on their endpoints - --> $DIR/overlapping_range_endpoints.rs:34:17 - | -LL | m!(0u8, 30, 20..=30); - | -- ^^^^^^^ overlapping range endpoints - | | - | this range overlaps on `30_u8` - error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:39:9 | @@ -86,5 +70,5 @@ LL | Some(0..=10) => {} LL | Some(10..20) => {} | ^^^^^^ overlapping range endpoints -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors From 94ad5e167281d212ce3b32868717fde92501d04d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 22 Oct 2020 19:32:46 +0100 Subject: [PATCH 059/719] Improve error message --- .../src/thir/pattern/deconstruct_pat.rs | 6 +-- .../overlapping_range_endpoints.stderr | 49 ++++++++++++------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 7c466ff591ce..5b1dbabe9a17 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -309,18 +309,18 @@ impl IntRange { pcx.span, |lint| { let mut err = lint.build("multiple patterns overlap on their endpoints"); - err.span_label(pcx.span, "overlapping range endpoints"); + err.span_label(pcx.span, "... with this range"); for (int_range, span) in overlaps { // Use the real type for user display of the ranges: err.span_label( span, &format!( - "this range overlaps on `{}`", + "this range overlaps on `{}`...", int_range.to_pat(pcx.cx.tcx, pcx.ty) ), ); } - // FIXME: add note + err.note("this is likely to be a mistake"); err.emit(); }, ); diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr index f694e4c9aab8..045c487873a3 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr @@ -2,73 +2,88 @@ error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:15:22 | LL | m!(0u8, 20..=30, 30..=40); - | ------- ^^^^^^^ overlapping range endpoints + | ------- ^^^^^^^ ... with this range | | - | this range overlaps on `30_u8` + | this range overlaps on `30_u8`... | note: the lint level is defined here --> $DIR/overlapping_range_endpoints.rs:2:9 | LL | #![deny(overlapping_range_endpoints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this is likely to be a mistake error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:16:22 | LL | m!(0u8, 30..=40, 20..=30); - | ------- ^^^^^^^ overlapping range endpoints + | ------- ^^^^^^^ ... with this range | | - | this range overlaps on `30_u8` + | this range overlaps on `30_u8`... + | + = note: this is likely to be a mistake error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:19:22 | LL | m!(0u8, 20.. 30, 29..=40); - | ------- ^^^^^^^ overlapping range endpoints + | ------- ^^^^^^^ ... with this range | | - | this range overlaps on `29_u8` + | this range overlaps on `29_u8`... + | + = note: this is likely to be a mistake error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:23:22 | LL | m!(0u8, 20..=30, 30..=31); - | ------- ^^^^^^^ overlapping range endpoints + | ------- ^^^^^^^ ... with this range | | - | this range overlaps on `30_u8` + | this range overlaps on `30_u8`... + | + = note: this is likely to be a mistake error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:27:22 | LL | m!(0u8, 20..=30, 19..=20); - | ------- ^^^^^^^ overlapping range endpoints + | ------- ^^^^^^^ ... with this range | | - | this range overlaps on `20_u8` + | this range overlaps on `20_u8`... + | + = note: this is likely to be a mistake error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:39:9 | LL | 0..=10 => {} - | ------ this range overlaps on `10_u8` + | ------ this range overlaps on `10_u8`... LL | 20..=30 => {} - | ------- this range overlaps on `20_u8` + | ------- this range overlaps on `20_u8`... LL | 10..=20 => {} - | ^^^^^^^ overlapping range endpoints + | ^^^^^^^ ... with this range + | + = note: this is likely to be a mistake error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:50:16 | LL | (true, 0..=10) => {} - | ------ this range overlaps on `10_u8` + | ------ this range overlaps on `10_u8`... LL | (true, 10..20) => {} - | ^^^^^^ overlapping range endpoints + | ^^^^^^ ... with this range + | + = note: this is likely to be a mistake error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:56:14 | LL | Some(0..=10) => {} - | ------ this range overlaps on `10_u8` + | ------ this range overlaps on `10_u8`... LL | Some(10..20) => {} - | ^^^^^^ overlapping range endpoints + | ^^^^^^ ... with this range + | + = note: this is likely to be a mistake error: aborting due to 8 previous errors From 5687c162792db8d267f80de7bd56c319e12efead Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 22 Nov 2020 22:21:09 +0000 Subject: [PATCH 060/719] `overlapping_range_endpoints` does not belong in the `unused` lint group --- compiler/rustc_lint/src/lib.rs | 1 - .../integer-ranges/exhaustiveness.rs | 1 + .../integer-ranges/exhaustiveness.stderr | 24 ++++----- .../usefulness/integer-ranges/reachability.rs | 1 + .../integer-ranges/reachability.stderr | 50 +++++++++---------- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index d5e77843b92d..f87796a95e93 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -283,7 +283,6 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { UNUSED_MUT, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, - OVERLAPPING_RANGE_ENDPOINTS, UNUSED_MUST_USE, UNUSED_UNSAFE, PATH_STATEMENTS, diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs index 5a44dfc28bb4..ef573db82104 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs +++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs @@ -1,5 +1,6 @@ #![feature(exclusive_range_pattern)] #![feature(assoc_char_consts)] +#![allow(overlapping_range_endpoints)] #![deny(unreachable_patterns)] macro_rules! m { diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr index 2e0023348e4d..b1440375494b 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered - --> $DIR/exhaustiveness.rs:47:8 + --> $DIR/exhaustiveness.rs:48:8 | LL | m!(0u8, 0..255); | ^^^ pattern `u8::MAX` not covered @@ -8,7 +8,7 @@ LL | m!(0u8, 0..255); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `u8::MAX` not covered - --> $DIR/exhaustiveness.rs:48:8 + --> $DIR/exhaustiveness.rs:49:8 | LL | m!(0u8, 0..=254); | ^^^ pattern `u8::MAX` not covered @@ -17,7 +17,7 @@ LL | m!(0u8, 0..=254); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `0_u8` not covered - --> $DIR/exhaustiveness.rs:49:8 + --> $DIR/exhaustiveness.rs:50:8 | LL | m!(0u8, 1..=255); | ^^^ pattern `0_u8` not covered @@ -26,7 +26,7 @@ LL | m!(0u8, 1..=255); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `42_u8` not covered - --> $DIR/exhaustiveness.rs:50:8 + --> $DIR/exhaustiveness.rs:51:8 | LL | m!(0u8, 0..42 | 43..=255); | ^^^ pattern `42_u8` not covered @@ -35,7 +35,7 @@ LL | m!(0u8, 0..42 | 43..=255); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `i8::MAX` not covered - --> $DIR/exhaustiveness.rs:51:8 + --> $DIR/exhaustiveness.rs:52:8 | LL | m!(0i8, -128..127); | ^^^ pattern `i8::MAX` not covered @@ -44,7 +44,7 @@ LL | m!(0i8, -128..127); = note: the matched value is of type `i8` error[E0004]: non-exhaustive patterns: `i8::MAX` not covered - --> $DIR/exhaustiveness.rs:52:8 + --> $DIR/exhaustiveness.rs:53:8 | LL | m!(0i8, -128..=126); | ^^^ pattern `i8::MAX` not covered @@ -53,7 +53,7 @@ LL | m!(0i8, -128..=126); = note: the matched value is of type `i8` error[E0004]: non-exhaustive patterns: `i8::MIN` not covered - --> $DIR/exhaustiveness.rs:53:8 + --> $DIR/exhaustiveness.rs:54:8 | LL | m!(0i8, -127..=127); | ^^^ pattern `i8::MIN` not covered @@ -62,7 +62,7 @@ LL | m!(0i8, -127..=127); = note: the matched value is of type `i8` error[E0004]: non-exhaustive patterns: `0_i8` not covered - --> $DIR/exhaustiveness.rs:54:11 + --> $DIR/exhaustiveness.rs:55:11 | LL | match 0i8 { | ^^^ pattern `0_i8` not covered @@ -71,7 +71,7 @@ LL | match 0i8 { = note: the matched value is of type `i8` error[E0004]: non-exhaustive patterns: `u128::MAX` not covered - --> $DIR/exhaustiveness.rs:59:8 + --> $DIR/exhaustiveness.rs:60:8 | LL | m!(0u128, 0..=ALMOST_MAX); | ^^^^^ pattern `u128::MAX` not covered @@ -80,7 +80,7 @@ LL | m!(0u128, 0..=ALMOST_MAX); = note: the matched value is of type `u128` error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered - --> $DIR/exhaustiveness.rs:60:8 + --> $DIR/exhaustiveness.rs:61:8 | LL | m!(0u128, 0..=4); | ^^^^^ pattern `5_u128..=u128::MAX` not covered @@ -89,7 +89,7 @@ LL | m!(0u128, 0..=4); = note: the matched value is of type `u128` error[E0004]: non-exhaustive patterns: `0_u128` not covered - --> $DIR/exhaustiveness.rs:61:8 + --> $DIR/exhaustiveness.rs:62:8 | LL | m!(0u128, 1..=u128::MAX); | ^^^^^ pattern `0_u128` not covered @@ -98,7 +98,7 @@ LL | m!(0u128, 1..=u128::MAX); = note: the matched value is of type `u128` error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered - --> $DIR/exhaustiveness.rs:69:11 + --> $DIR/exhaustiveness.rs:70:11 | LL | match (0u8, true) { | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered diff --git a/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs index 6516925e9391..fb4d59b05780 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs +++ b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs @@ -1,4 +1,5 @@ #![feature(exclusive_range_pattern)] +#![allow(overlapping_range_endpoints)] #![deny(unreachable_patterns)] macro_rules! m { diff --git a/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr index e6878d950d62..9a02fac6a75d 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr @@ -1,149 +1,149 @@ error: unreachable pattern - --> $DIR/reachability.rs:16:17 + --> $DIR/reachability.rs:17:17 | LL | m!(0u8, 42, 42); | ^^ | note: the lint level is defined here - --> $DIR/reachability.rs:2:9 + --> $DIR/reachability.rs:3:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:20:22 + --> $DIR/reachability.rs:21:22 | LL | m!(0u8, 20..=30, 20); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:21:22 + --> $DIR/reachability.rs:22:22 | LL | m!(0u8, 20..=30, 21); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:22:22 + --> $DIR/reachability.rs:23:22 | LL | m!(0u8, 20..=30, 25); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:23:22 + --> $DIR/reachability.rs:24:22 | LL | m!(0u8, 20..=30, 29); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:24:22 + --> $DIR/reachability.rs:25:22 | LL | m!(0u8, 20..=30, 30); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:27:21 + --> $DIR/reachability.rs:28:21 | LL | m!(0u8, 20..30, 20); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:28:21 + --> $DIR/reachability.rs:29:21 | LL | m!(0u8, 20..30, 21); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:29:21 + --> $DIR/reachability.rs:30:21 | LL | m!(0u8, 20..30, 25); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:30:21 + --> $DIR/reachability.rs:31:21 | LL | m!(0u8, 20..30, 29); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:34:22 + --> $DIR/reachability.rs:35:22 | LL | m!(0u8, 20..=30, 20..=30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:35:22 + --> $DIR/reachability.rs:36:22 | LL | m!(0u8, 20.. 30, 20.. 30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:36:22 + --> $DIR/reachability.rs:37:22 | LL | m!(0u8, 20..=30, 20.. 30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:38:22 + --> $DIR/reachability.rs:39:22 | LL | m!(0u8, 20..=30, 21..=30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:39:22 + --> $DIR/reachability.rs:40:22 | LL | m!(0u8, 20..=30, 20..=29); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:41:24 + --> $DIR/reachability.rs:42:24 | LL | m!('a', 'A'..='z', 'a'..='z'); | ^^^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:48:9 + --> $DIR/reachability.rs:49:9 | LL | 5..=8 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:54:9 + --> $DIR/reachability.rs:55:9 | LL | 5..15 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:61:9 + --> $DIR/reachability.rs:62:9 | LL | 5..25 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:69:9 + --> $DIR/reachability.rs:70:9 | LL | 5..25 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:75:9 + --> $DIR/reachability.rs:76:9 | LL | 5..15 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:82:9 + --> $DIR/reachability.rs:83:9 | LL | '\u{D7FF}'..='\u{E000}' => {}, | ^^^^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:103:9 + --> $DIR/reachability.rs:104:9 | LL | &FOO => {} | ^^^^ error: unreachable pattern - --> $DIR/reachability.rs:104:9 + --> $DIR/reachability.rs:105:9 | LL | BAR => {} | ^^^ From f059febe85f49fd7b432a24542321f9b948a49de Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 13 Nov 2020 12:13:50 -0600 Subject: [PATCH 061/719] Add redundant else lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 4 + clippy_lints/src/redundant_else.rs | 135 +++++++++++++++++++++++++ tests/ui/redundant_else.rs | 154 +++++++++++++++++++++++++++++ tests/ui/redundant_else.stderr | 80 +++++++++++++++ 5 files changed, 374 insertions(+) create mode 100644 clippy_lints/src/redundant_else.rs create mode 100644 tests/ui/redundant_else.rs create mode 100644 tests/ui/redundant_else.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index e76a781f13bc..c3351793c662 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2023,6 +2023,7 @@ Released 2018-09-13 [`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure [`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call [`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls +[`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6eb5f6a7f48c..66895a866eee 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -293,6 +293,7 @@ mod question_mark; mod ranges; mod redundant_clone; mod redundant_closure_call; +mod redundant_else; mod redundant_field_names; mod redundant_pub_crate; mod redundant_static_lifetimes; @@ -810,6 +811,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &ranges::REVERSED_EMPTY_RANGES, &redundant_clone::REDUNDANT_CLONE, &redundant_closure_call::REDUNDANT_CLOSURE_CALL, + &redundant_else::REDUNDANT_ELSE, &redundant_field_names::REDUNDANT_FIELD_NAMES, &redundant_pub_crate::REDUNDANT_PUB_CRATE, &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, @@ -1113,6 +1115,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); store.register_early_pass(|| box precedence::Precedence); store.register_early_pass(|| box needless_continue::NeedlessContinue); + store.register_early_pass(|| box redundant_else::RedundantElse); store.register_late_pass(|| box create_dir::CreateDir); store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes); @@ -1294,6 +1297,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF), LintId::of(&ranges::RANGE_MINUS_ONE), LintId::of(&ranges::RANGE_PLUS_ONE), + LintId::of(&redundant_else::REDUNDANT_ELSE), LintId::of(&ref_option_ref::REF_OPTION_REF), LintId::of(&shadow::SHADOW_UNRELATED), LintId::of(&strings::STRING_ADD_ASSIGN), diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs new file mode 100644 index 000000000000..3d585cd27a3d --- /dev/null +++ b/clippy_lints/src/redundant_else.rs @@ -0,0 +1,135 @@ +use crate::utils::span_lint_and_help; +use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; +use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for `else` blocks that can be removed without changing semantics. + /// + /// **Why is this bad?** The `else` block adds unnecessary indentation and verbosity. + /// + /// **Known problems:** Some may prefer to keep the `else` block for clarity. + /// + /// **Example:** + /// + /// ```rust + /// fn my_func(count: u32) { + /// if count == 0 { + /// print!("Nothing to do"); + /// return; + /// } else { + /// print!("Moving on..."); + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn my_func(count: u32) { + /// if count == 0 { + /// print!("Nothing to do"); + /// return; + /// } + /// print!("Moving on..."); + /// } + /// ``` + pub REDUNDANT_ELSE, + pedantic, + "`else` branch that can be removed without changing semantics" +} + +declare_lint_pass!(RedundantElse => [REDUNDANT_ELSE]); + +impl EarlyLintPass for RedundantElse { + fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) { + if in_external_macro(cx.sess, stmt.span) { + return; + } + // Only look at expressions that are a whole statement + let expr: &Expr = match &stmt.kind { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr, + _ => return, + }; + // if else + let (mut then, mut els): (&Block, &Expr) = match &expr.kind { + ExprKind::If(_, then, Some(els)) => (then, els), + _ => return, + }; + loop { + if !BreakVisitor::default().check_block(then) { + // then block does not always break + return; + } + match &els.kind { + // else if else + ExprKind::If(_, next_then, Some(next_els)) => { + then = next_then; + els = next_els; + continue; + }, + // else if without else + ExprKind::If(..) => return, + // done + _ => break, + } + } + span_lint_and_help( + cx, + REDUNDANT_ELSE, + els.span, + "redundant else block", + None, + "remove the `else` block and move the contents out", + ); + } +} + +/// Call `check` functions to check if an expression always breaks control flow +#[derive(Default)] +struct BreakVisitor { + is_break: bool, +} + +impl<'ast> Visitor<'ast> for BreakVisitor { + fn visit_block(&mut self, block: &'ast Block) { + self.is_break = match block.stmts.as_slice() { + [.., last] => self.check_stmt(last), + _ => false, + }; + } + + fn visit_expr(&mut self, expr: &'ast Expr) { + self.is_break = match expr.kind { + ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) => true, + ExprKind::Match(_, ref arms) => arms.iter().all(|arm| self.check_expr(&arm.body)), + ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els), + ExprKind::If(_, _, None) + // ignore loops for simplicity + | ExprKind::While(..) | ExprKind::ForLoop(..) | ExprKind::Loop(..) => false, + _ => { + walk_expr(self, expr); + return; + }, + }; + } +} + +impl BreakVisitor { + fn check(&mut self, item: T, visit: fn(&mut Self, T)) -> bool { + visit(self, item); + std::mem::replace(&mut self.is_break, false) + } + + fn check_block(&mut self, block: &Block) -> bool { + self.check(block, Self::visit_block) + } + + fn check_expr(&mut self, expr: &Expr) -> bool { + self.check(expr, Self::visit_expr) + } + + fn check_stmt(&mut self, stmt: &Stmt) -> bool { + self.check(stmt, Self::visit_stmt) + } +} diff --git a/tests/ui/redundant_else.rs b/tests/ui/redundant_else.rs new file mode 100644 index 000000000000..737c8a9f8db4 --- /dev/null +++ b/tests/ui/redundant_else.rs @@ -0,0 +1,154 @@ +#![warn(clippy::redundant_else)] +#![allow(clippy::needless_return)] + +fn main() { + loop { + // break + if foo() { + println!("Love your neighbor;"); + break; + } else { + println!("yet don't pull down your hedge."); + } + // continue + if foo() { + println!("He that lies down with Dogs,"); + continue; + } else { + println!("shall rise up with fleas."); + } + // match block + if foo() { + match foo() { + 1 => break, + _ => return, + } + } else { + println!("You may delay, but time will not."); + } + } + // else if + if foo() { + return; + } else if foo() { + return; + } else { + println!("A fat kitchen makes a lean will."); + } + // let binding outside of block + let _ = { + if foo() { + return; + } else { + 1 + } + }; + // else if with let binding outside of block + let _ = { + if foo() { + return; + } else if foo() { + return; + } else { + 2 + } + }; + // inside if let + let _ = if let Some(1) = foo() { + let _ = 1; + if foo() { + return; + } else { + 1 + } + } else { + 1 + }; + + // + // non-lint cases + // + + // sanity check + if foo() { + let _ = 1; + } else { + println!("Who is wise? He that learns from every one."); + } + // else if without else + if foo() { + return; + } else if foo() { + foo() + }; + // nested if return + if foo() { + if foo() { + return; + } + } else { + foo() + }; + // match with non-breaking branch + if foo() { + match foo() { + 1 => foo(), + _ => return, + } + } else { + println!("Three may keep a secret, if two of them are dead."); + } + // let binding + let _ = if foo() { + return; + } else { + 1 + }; + // assign + let a; + a = if foo() { + return; + } else { + 1 + }; + // assign-op + a += if foo() { + return; + } else { + 1 + }; + // if return else if else + if foo() { + return; + } else if foo() { + 1 + } else { + 2 + }; + // if else if return else + if foo() { + 1 + } else if foo() { + return; + } else { + 2 + }; + // else if with let binding + let _ = if foo() { + return; + } else if foo() { + return; + } else { + 2 + }; + // inside function call + Box::new(if foo() { + return; + } else { + 1 + }); +} + +fn foo() -> T { + unimplemented!("I'm not Santa Claus") +} diff --git a/tests/ui/redundant_else.stderr b/tests/ui/redundant_else.stderr new file mode 100644 index 000000000000..9000cdc814b1 --- /dev/null +++ b/tests/ui/redundant_else.stderr @@ -0,0 +1,80 @@ +error: redundant else block + --> $DIR/redundant_else.rs:10:16 + | +LL | } else { + | ________________^ +LL | | println!("yet don't pull down your hedge."); +LL | | } + | |_________^ + | + = note: `-D clippy::redundant-else` implied by `-D warnings` + = help: remove the `else` block and move the contents out + +error: redundant else block + --> $DIR/redundant_else.rs:17:16 + | +LL | } else { + | ________________^ +LL | | println!("shall rise up with fleas."); +LL | | } + | |_________^ + | + = help: remove the `else` block and move the contents out + +error: redundant else block + --> $DIR/redundant_else.rs:26:16 + | +LL | } else { + | ________________^ +LL | | println!("You may delay, but time will not."); +LL | | } + | |_________^ + | + = help: remove the `else` block and move the contents out + +error: redundant else block + --> $DIR/redundant_else.rs:35:12 + | +LL | } else { + | ____________^ +LL | | println!("A fat kitchen makes a lean will."); +LL | | } + | |_____^ + | + = help: remove the `else` block and move the contents out + +error: redundant else block + --> $DIR/redundant_else.rs:42:16 + | +LL | } else { + | ________________^ +LL | | 1 +LL | | } + | |_________^ + | + = help: remove the `else` block and move the contents out + +error: redundant else block + --> $DIR/redundant_else.rs:52:16 + | +LL | } else { + | ________________^ +LL | | 2 +LL | | } + | |_________^ + | + = help: remove the `else` block and move the contents out + +error: redundant else block + --> $DIR/redundant_else.rs:61:16 + | +LL | } else { + | ________________^ +LL | | 1 +LL | | } + | |_________^ + | + = help: remove the `else` block and move the contents out + +error: aborting due to 7 previous errors + From 70f6a2cae22cc1245ee62ca493f3027a76b3a381 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 13 Nov 2020 12:46:37 -0600 Subject: [PATCH 062/719] Eat redundant else dogfood --- clippy_lints/src/functions.rs | 13 +++++-------- clippy_lints/src/len_zero.rs | 3 +-- clippy_lints/src/matches.rs | 5 ++--- clippy_lints/src/methods/unnecessary_filter_map.rs | 5 ++--- clippy_lints/src/non_expressive_names.rs | 7 +++---- 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 8b58d1f26013..fd93548b55c6 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -405,13 +405,10 @@ impl<'tcx> Functions { break; } if in_comment { - match line.find("*/") { - Some(i) => { - line = &line[i + 2..]; - in_comment = false; - continue; - }, - None => break, + if let Some(i) = line.find("*/") { + line = &line[i + 2..]; + in_comment = false; + continue; } } else { let multi_idx = line.find("/*").unwrap_or_else(|| line.len()); @@ -423,8 +420,8 @@ impl<'tcx> Functions { in_comment = true; continue; } - break; } + break; } if code_in_line { line_count += 1; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 8842901d90b8..6fe533510904 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -222,9 +222,8 @@ fn check_impl_items(cx: &LateContext<'_>, item: &Item<'_>, impl_items: &[ImplIte let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) { if cx.access_levels.is_exported(is_empty.id.hir_id) { return; - } else { - "a private" } + "a private" } else { "no corresponding" }; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 7d64fa6c2629..5c3901e5b282 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -696,10 +696,9 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() { // single statement/expr "else" block, don't lint return; - } else { - // block with 2+ statements or 1 expr and 1+ statement - Some(els) } + // block with 2+ statements or 1 expr and 1+ statement + Some(els) } else { // not a block, don't lint return; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 75e123eb5939..d082a88cd2db 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -69,10 +69,9 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc } } return (true, false); - } else { - // We don't know. It might do anything. - return (true, true); } + // We don't know. It might do anything. + return (true, true); } } (true, true) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 5b42b61fcde9..446426b3e611 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -409,11 +409,10 @@ fn levenstein_not_1(a_name: &str, b_name: &str) -> bool { if let Some(b2) = b_chars.next() { // check if there's just one character inserted return a != b2 || a_chars.ne(b_chars); - } else { - // tuple - // ntuple - return true; } + // tuple + // ntuple + return true; } // for item in items true From 50d9b30a3751388e629d246ad4428c3f3f8d2567 Mon Sep 17 00:00:00 2001 From: PankajChaudhary5 Date: Thu, 8 Oct 2020 10:45:34 +0530 Subject: [PATCH 063/719] Added better error message for shared borrow treated as unique for purposes of lifetimes --- compiler/rustc_mir/src/util/borrowck_errors.rs | 7 ++++--- .../ui/borrowck/borrowck-mut-borrow-linear-errors.stderr | 2 +- src/test/ui/borrowck/mut-borrow-in-loop.stderr | 6 +++--- src/test/ui/borrowck/two-phase-across-loop.stderr | 2 +- src/test/ui/nll/closures-in-loops.stderr | 2 +- src/test/ui/nll/issue-62007-assign-const-index.stderr | 4 ++-- .../ui/nll/issue-62007-assign-differing-fields.stderr | 4 ++-- .../ui/nll/polonius/assignment-to-differing-field.stderr | 8 ++++---- 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir/src/util/borrowck_errors.rs b/compiler/rustc_mir/src/util/borrowck_errors.rs index 83bf7584f2e2..56d8045813c4 100644 --- a/compiler/rustc_mir/src/util/borrowck_errors.rs +++ b/compiler/rustc_mir/src/util/borrowck_errors.rs @@ -68,9 +68,10 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { err.span_label( new_loan_span, format!( - "mutable borrow starts here in previous \ - iteration of loop{}", - opt_via + "{}{} was mutably borrowed here in the previous iteration of the loop{}", + desc, + via(opt_via), + opt_via, ), ); if let Some(old_load_end_span) = old_load_end_span { diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr index ca1496a6c8d9..a40907779390 100644 --- a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr +++ b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr @@ -23,7 +23,7 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-mut-borrow-linear-errors.rs:12:30 | LL | _ => { addr.push(&mut x); } - | ^^^^^^ mutable borrow starts here in previous iteration of loop + | ^^^^^^ `x` was mutably borrowed here in the previous iteration of the loop error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/mut-borrow-in-loop.stderr b/src/test/ui/borrowck/mut-borrow-in-loop.stderr index 260b9673d74b..b621694a548c 100644 --- a/src/test/ui/borrowck/mut-borrow-in-loop.stderr +++ b/src/test/ui/borrowck/mut-borrow-in-loop.stderr @@ -15,7 +15,7 @@ LL | impl<'a, T : 'a> FuncWrapper<'a, T> { LL | (self.func)(arg) | ------------^^^- | | | - | | mutable borrow starts here in previous iteration of loop + | | `*arg` was mutably borrowed here in the previous iteration of the loop | argument requires that `*arg` is borrowed for `'a` error[E0499]: cannot borrow `*arg` as mutable more than once at a time @@ -27,7 +27,7 @@ LL | impl<'a, T : 'a> FuncWrapper<'a, T> { LL | (self.func)(arg) | ------------^^^- | | | - | | mutable borrow starts here in previous iteration of loop + | | `*arg` was mutably borrowed here in the previous iteration of the loop | argument requires that `*arg` is borrowed for `'a` error[E0499]: cannot borrow `*arg` as mutable more than once at a time @@ -39,7 +39,7 @@ LL | impl<'a, T : 'a> FuncWrapper<'a, T> { LL | (self.func)(arg) | ------------^^^- | | | - | | mutable borrow starts here in previous iteration of loop + | | `*arg` was mutably borrowed here in the previous iteration of the loop | argument requires that `*arg` is borrowed for `'a` error: aborting due to 3 previous errors; 1 warning emitted diff --git a/src/test/ui/borrowck/two-phase-across-loop.stderr b/src/test/ui/borrowck/two-phase-across-loop.stderr index 38993a50bf6b..d4e515d12bbb 100644 --- a/src/test/ui/borrowck/two-phase-across-loop.stderr +++ b/src/test/ui/borrowck/two-phase-across-loop.stderr @@ -2,7 +2,7 @@ error[E0499]: cannot borrow `foo` as mutable more than once at a time --> $DIR/two-phase-across-loop.rs:17:22 | LL | strings.push(foo.get_string()); - | ^^^ mutable borrow starts here in previous iteration of loop + | ^^^ `foo` was mutably borrowed here in the previous iteration of the loop error: aborting due to previous error diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr index 37638a93d77f..2f134f83ced1 100644 --- a/src/test/ui/nll/closures-in-loops.stderr +++ b/src/test/ui/nll/closures-in-loops.stderr @@ -15,7 +15,7 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time LL | v.push(|| x = String::new()); | ^^ - borrows occur due to use of `x` in closure | | - | mutable borrow starts here in previous iteration of loop + | `x` was mutably borrowed here in the previous iteration of the loop error[E0524]: two closures require unique access to `x` at the same time --> $DIR/closures-in-loops.rs:20:16 diff --git a/src/test/ui/nll/issue-62007-assign-const-index.stderr b/src/test/ui/nll/issue-62007-assign-const-index.stderr index 758a14d01770..0db9fe62c386 100644 --- a/src/test/ui/nll/issue-62007-assign-const-index.stderr +++ b/src/test/ui/nll/issue-62007-assign-const-index.stderr @@ -5,7 +5,7 @@ LL | fn to_refs(mut list: [&mut List; 2]) -> Vec<&mut T> { | - let's call the lifetime of this reference `'1` ... LL | result.push(&mut list[0].value); - | ^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop + | ^^^^^^^^^^^^^^^^^^ `list[_].value` was mutably borrowed here in the previous iteration of the loop ... LL | return result; | ------ returning this value requires that `list[_].value` is borrowed for `'1` @@ -19,7 +19,7 @@ LL | fn to_refs(mut list: [&mut List; 2]) -> Vec<&mut T> { LL | if let Some(n) = list[0].next.as_mut() { | ^^^^^^^^^^^^--------- | | - | mutable borrow starts here in previous iteration of loop + | `list[_].next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list[_].next` is borrowed for `'1` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/issue-62007-assign-differing-fields.stderr b/src/test/ui/nll/issue-62007-assign-differing-fields.stderr index f942d7628b50..f1af2e855afe 100644 --- a/src/test/ui/nll/issue-62007-assign-differing-fields.stderr +++ b/src/test/ui/nll/issue-62007-assign-differing-fields.stderr @@ -5,7 +5,7 @@ LL | fn to_refs<'a, T>(mut list: (&'a mut List, &'a mut List)) -> Vec<&'a | -- lifetime `'a` defined here ... LL | result.push(&mut (list.0).value); - | ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop + | ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop ... LL | return result; | ------ returning this value requires that `list.0.value` is borrowed for `'a` @@ -19,7 +19,7 @@ LL | fn to_refs<'a, T>(mut list: (&'a mut List, &'a mut List)) -> Vec<&'a LL | if let Some(n) = (list.0).next.as_mut() { | ^^^^^^^^^^^^^--------- | | - | mutable borrow starts here in previous iteration of loop + | `list.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.next` is borrowed for `'a` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/polonius/assignment-to-differing-field.stderr b/src/test/ui/nll/polonius/assignment-to-differing-field.stderr index 07ca021b53bc..2fe6a53a49ae 100644 --- a/src/test/ui/nll/polonius/assignment-to-differing-field.stderr +++ b/src/test/ui/nll/polonius/assignment-to-differing-field.stderr @@ -5,7 +5,7 @@ LL | fn assignment_to_field_projection<'a, T>( | -- lifetime `'a` defined here ... LL | result.push(&mut (list.0).value); - | ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop + | ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop ... LL | return result; | ------ returning this value requires that `list.0.value` is borrowed for `'a` @@ -19,7 +19,7 @@ LL | fn assignment_to_field_projection<'a, T>( LL | if let Some(n) = (list.0).next.as_mut() { | ^^^^^^^^^^^^^--------- | | - | mutable borrow starts here in previous iteration of loop + | `list.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.next` is borrowed for `'a` error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time @@ -29,7 +29,7 @@ LL | fn assignment_through_projection_chain<'a, T>( | -- lifetime `'a` defined here ... LL | result.push(&mut ((((list.0).0).0).0).0.value); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.value` was mutably borrowed here in the previous iteration of the loop ... LL | return result; | ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a` @@ -43,7 +43,7 @@ LL | fn assignment_through_projection_chain<'a, T>( LL | if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^--------- | | - | mutable borrow starts here in previous iteration of loop + | `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.0.0.0.0.next` is borrowed for `'a` error: aborting due to 4 previous errors From 866ef87d3f1f368687095b263829ef1182b2727a Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Tue, 1 Dec 2020 01:06:40 -0500 Subject: [PATCH 064/719] Update rustc version that or_insert_with_key landed --- library/alloc/src/collections/btree/map/entry.rs | 2 +- library/std/src/collections/hash/map.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 3ff648fe24cf..77c285ef595b 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -132,7 +132,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 9); /// ``` #[inline] - #[stable(feature = "or_insert_with_key", since = "1.49.0")] + #[stable(feature = "or_insert_with_key", since = "1.50.0")] pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 3d130c1628e0..323ea5d8244b 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2238,7 +2238,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 9); /// ``` #[inline] - #[stable(feature = "or_insert_with_key", since = "1.49.0")] + #[stable(feature = "or_insert_with_key", since = "1.50.0")] pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), From 5404deeb64f4449079f5165ace6bfa1e52ca4b33 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Wed, 14 Oct 2020 22:27:48 +0200 Subject: [PATCH 065/719] Gracefully handle mistyping -> as => in function return type --- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- compiler/rustc_parse/src/parser/item.rs | 4 ++-- compiler/rustc_parse/src/parser/path.rs | 5 +++-- compiler/rustc_parse/src/parser/ty.rs | 21 +++++++++++++++++++++ src/test/ui/fn/fn-fat-arrow-return.fixed | 18 ++++++++++++++++++ src/test/ui/fn/fn-fat-arrow-return.rs | 18 ++++++++++++++++++ src/test/ui/fn/fn-fat-arrow-return.stderr | 8 ++++++++ src/test/ui/fn/fn-fat-arrow-return2.rs | 10 ++++++++++ src/test/ui/fn/fn-fat-arrow-return2.stderr | 14 ++++++++++++++ 9 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/fn/fn-fat-arrow-return.fixed create mode 100644 src/test/ui/fn/fn-fat-arrow-return.rs create mode 100644 src/test/ui/fn/fn-fat-arrow-return.stderr create mode 100644 src/test/ui/fn/fn-fat-arrow-return2.rs create mode 100644 src/test/ui/fn/fn-fat-arrow-return2.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93be478fc8c2..790a0c867af8 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,5 +1,5 @@ use super::pat::{GateOr, PARAM_EXPECTED}; -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; @@ -1647,7 +1647,7 @@ impl<'a> Parser<'a> { self.expect_or()?; args }; - let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes)?; + let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverFatArrow::Yes)?; Ok(P(FnDecl { inputs, output })) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5954b370e6d9..9e342a0d6813 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,5 +1,5 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error}; -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; @@ -1648,7 +1648,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { Ok(P(FnDecl { inputs: self.parse_fn_params(req_name)?, - output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?, + output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, RecoverFatArrow::Yes)?, })) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 17e5bcf76050..311a4829fcfc 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,4 +1,4 @@ -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; use super::{Parser, TokenType}; use crate::maybe_whole; use rustc_ast::ptr::P; @@ -231,7 +231,8 @@ impl<'a> Parser<'a> { // `(T, U) -> R` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; let span = ident.span.to(self.prev_token.span); - let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No)?; + let output = + self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverFatArrow::No)?; ParenthesizedArgs { inputs, output, span }.into() }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 7a6ebca4e154..ff19c5cfa856 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,6 +43,12 @@ pub(super) enum RecoverQPath { No, } +#[derive(PartialEq)] +pub(super) enum RecoverFatArrow { + Yes, + No, +} + // Is `...` (`CVarArgs`) legal at this level of type parsing? #[derive(PartialEq)] enum AllowCVariadic { @@ -87,11 +93,26 @@ impl<'a> Parser<'a> { &mut self, allow_plus: AllowPlus, recover_qpath: RecoverQPath, + recover_fat_arrow: RecoverFatArrow, ) -> PResult<'a, FnRetTy> { Ok(if self.eat(&token::RArrow) { // FIXME(Centril): Can we unconditionally `allow_plus`? let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; FnRetTy::Ty(ty) + } else if recover_fat_arrow == RecoverFatArrow::Yes && self.token == token::FatArrow { + // Don't `eat` to prevent `=>` from being added as an expected token which isn't + // actually expected and could only confuse users + self.bump(); + self.struct_span_err(self.prev_token.span, "return types are denoted using `->`") + .span_suggestion_short( + self.prev_token.span, + "use `->` instead", + "->".to_string(), + Applicability::MachineApplicable, + ) + .emit(); + let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; + FnRetTy::Ty(ty) } else { FnRetTy::Default(self.token.span.shrink_to_lo()) }) diff --git a/src/test/ui/fn/fn-fat-arrow-return.fixed b/src/test/ui/fn/fn-fat-arrow-return.fixed new file mode 100644 index 000000000000..0acca85aa679 --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return.fixed @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(unused)] +fn a() -> usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn bar(_: u32) {} + +fn baz() -> *const dyn Fn(u32) { unimplemented!() } + +fn foo() { + match () { + _ if baz() == &bar as &dyn Fn(u32) => (), + () => (), + } +} + +fn main() { +} diff --git a/src/test/ui/fn/fn-fat-arrow-return.rs b/src/test/ui/fn/fn-fat-arrow-return.rs new file mode 100644 index 000000000000..4bdcd70d7fc4 --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return.rs @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(unused)] +fn a() => usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn bar(_: u32) {} + +fn baz() -> *const dyn Fn(u32) { unimplemented!() } + +fn foo() { + match () { + _ if baz() == &bar as &dyn Fn(u32) => (), + () => (), + } +} + +fn main() { +} diff --git a/src/test/ui/fn/fn-fat-arrow-return.stderr b/src/test/ui/fn/fn-fat-arrow-return.stderr new file mode 100644 index 000000000000..1fcdb18a5147 --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return.stderr @@ -0,0 +1,8 @@ +error: return types are denoted using `->` + --> $DIR/fn-fat-arrow-return.rs:3:8 + | +LL | fn a() => usize { 0 } + | ^^ help: use `->` instead + +error: aborting due to previous error + diff --git a/src/test/ui/fn/fn-fat-arrow-return2.rs b/src/test/ui/fn/fn-fat-arrow-return2.rs new file mode 100644 index 000000000000..316fa2cbf02e --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return2.rs @@ -0,0 +1,10 @@ +fn a() => impl Fn() => bool { + //~^ ERROR return types are denoted using `->` + //~| ERROR expected `;` or `{`, found `=>` + unimplemented!() +} + +fn main() { + let foo = |a: bool| => bool { a }; + dbg!(foo(false)); +} diff --git a/src/test/ui/fn/fn-fat-arrow-return2.stderr b/src/test/ui/fn/fn-fat-arrow-return2.stderr new file mode 100644 index 000000000000..a6f9fe3b5732 --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return2.stderr @@ -0,0 +1,14 @@ +error: return types are denoted using `->` + --> $DIR/fn-fat-arrow-return2.rs:1:8 + | +LL | fn a() => impl Fn() => bool { + | ^^ help: use `->` instead + +error: expected `;` or `{`, found `=>` + --> $DIR/fn-fat-arrow-return2.rs:1:21 + | +LL | fn a() => impl Fn() => bool { + | ^^ expected `;` or `{` + +error: aborting due to 2 previous errors + From 8bd80e25f0bdb7a3282fecee148afed966067f1e Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 02:32:10 +0100 Subject: [PATCH 066/719] Make some of MaybeUninit's methods const --- .../rustc_mir/src/interpret/intrinsics.rs | 24 +++++++++++++++++++ library/core/src/intrinsics.rs | 1 + library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 7 ++++-- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index f666a89ca56d..c751f4f7eb6c 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -407,6 +407,30 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::transmute => { self.copy_op_transmute(args[0], dest)?; } + sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { + let ty = instance.substs.type_at(0); + let layout = self.layout_of(ty)?; + + if layout.abi.is_uninhabited() { + throw_ub_format!("attempted to instantiate uninhabited type `{}`", ty); + } + if intrinsic_name == sym::assert_zero_valid + && !layout.might_permit_raw_init(self, /*zero:*/ true).unwrap() + { + throw_ub_format!( + "attempted to zero-initialize type `{}`, which is invalid", + ty + ); + } + if intrinsic_name == sym::assert_uninit_valid + && !layout.might_permit_raw_init(self, /*zero:*/ false).unwrap() + { + throw_ub_format!( + "attempted to leave type `{}` uninitialized, which is invalid", + ty + ); + } + } sym::simd_insert => { let index = u64::from(self.read_scalar(args[1])?.to_u32()?); let elem = args[2]; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 1a588b314c4f..c0fcfb3a1395 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -815,6 +815,7 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] pub fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e3b004be39af..5d56a22bfa53 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -100,6 +100,7 @@ #![feature(const_type_name)] #![feature(const_likely)] #![feature(const_unreachable_unchecked)] +#![feature(const_maybe_assume_init)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 1924720b949f..cb32c909717a 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -314,8 +314,10 @@ impl MaybeUninit { /// let data = read(&mut buf); /// ``` #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_allow_const_fn_unstable(const_maybe_assume_init)] #[inline(always)] - pub fn uninit_array() -> [Self; LEN] { + pub const fn uninit_array() -> [Self; LEN] { // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. unsafe { MaybeUninit::<[MaybeUninit; LEN]>::uninit().assume_init() } } @@ -503,9 +505,10 @@ impl MaybeUninit { /// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️ /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] #[rustc_diagnostic_item = "assume_init"] - pub unsafe fn assume_init(self) -> T { + pub const unsafe fn assume_init(self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { From 91772c35c83f369283838ab049712a5f746e11ef Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 03:01:18 +0100 Subject: [PATCH 067/719] Even more const --- library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5d56a22bfa53..a901375a958a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -92,6 +92,7 @@ #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_raw_ptr_comparison)] +#![feature(const_raw_ptr_deref)] #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] #![feature(const_size_of_val)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index cb32c909717a..6251355b9099 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -813,8 +813,9 @@ impl MaybeUninit { /// /// [`assume_init_ref`]: MaybeUninit::assume_init_ref #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { + pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { // SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that // `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`. // The pointer obtained is valid since it refers to memory owned by `slice` which is a @@ -834,8 +835,9 @@ impl MaybeUninit { /// /// [`assume_init_mut`]: MaybeUninit::assume_init_mut #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { + pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a // mutable reference which is also guaranteed to be valid for writes. unsafe { &mut *(slice as *mut [Self] as *mut [T]) } @@ -843,15 +845,17 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } } From 71d75503506880efa89c902465cdcb205d0eb9e5 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 2 Dec 2020 14:33:26 +0100 Subject: [PATCH 068/719] const_evaluatable_checked: fix occurs check --- compiler/rustc_infer/src/infer/combine.rs | 16 ++++++++++++++- compiler/rustc_middle/src/ty/relate.rs | 6 +++++- .../occurs-check/unused-substs-5.rs | 20 +++++++++++++++++++ .../occurs-check/unused-substs-5.stderr | 12 +++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-5.rs create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-5.stderr diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 6a1715ef8189..594e2c6205f8 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -543,6 +543,10 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { true } + fn visit_ct_substs(&self) -> bool { + true + } + fn binders( &mut self, a: ty::Binder, @@ -716,7 +720,10 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { let variable_table = &mut inner.const_unification_table(); let var_value = variable_table.probe_value(vid); match var_value.val { - ConstVariableValue::Known { value: u } => self.relate(u, u), + ConstVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } ConstVariableValue::Unknown { universe } => { if self.for_universe.can_name(universe) { Ok(c) @@ -815,6 +822,10 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { true } + fn visit_ct_substs(&self) -> bool { + true + } + fn relate_with_variance>( &mut self, _variance: ty::Variance, @@ -870,6 +881,9 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { + Ok(t) + } _ => relate::super_relate_tys(self, t, t), } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index ef5034e218da..80dc7d89d187 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -33,6 +33,10 @@ pub trait TypeRelation<'tcx>: Sized { /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; + fn visit_ct_substs(&self) -> bool { + false + } + fn with_cause(&mut self, _cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -579,7 +583,7 @@ pub fn super_relate_consts>( ( ty::ConstKind::Unevaluated(a_def, a_substs, None), ty::ConstKind::Unevaluated(b_def, b_substs, None), - ) if tcx.features().const_evaluatable_checked => { + ) if tcx.features().const_evaluatable_checked && !relation.visit_ct_substs() => { if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { Ok(a.val) } else { diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-5.rs b/src/test/ui/const-generics/occurs-check/unused-substs-5.rs new file mode 100644 index 000000000000..e5d487d89b9f --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-5.rs @@ -0,0 +1,20 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +// `N + 1` also depends on `T` here even if it doesn't use it. +fn q(_: T) -> [u8; N + 1] { + todo!() +} + +fn supplier() -> T { + todo!() +} + +fn catch_me() where [u8; N + 1]: Default { + let mut x = supplier(); + x = q::<_, N>(x); //~ ERROR mismatched types +} + +fn main() { + catch_me::<3>(); +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-5.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-5.stderr new file mode 100644 index 000000000000..239569dab096 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-5.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/unused-substs-5.rs:15:9 + | +LL | x = q::<_, N>(x); + | ^^^^^^^^^^^^ + | | + | cyclic type of infinite size + | help: try using a conversion method: `q::<_, N>(x).to_vec()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 1ef5dbe7167376be7a0babefb0b4971d703e4b5d Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 16:17:37 +0100 Subject: [PATCH 069/719] Resolved some of the comments * Undo fn -> const fn for some fns. * Split feature gate. * Made all three intrinsics const --- library/core/src/intrinsics.rs | 4 +++- library/core/src/lib.rs | 3 ++- library/core/src/mem/maybe_uninit.rs | 15 ++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index c0fcfb3a1395..0c37bec46987 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -815,19 +815,21 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit /// zero-initialization: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_zero_valid(); /// A guard for unsafe functions that cannot ever be executed if `T` has invalid /// bit patterns: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_uninit_valid(); /// Gets a reference to a static `Location` indicating where it was called. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a901375a958a..fc44a5a55fb5 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -69,6 +69,7 @@ #![feature(asm)] #![feature(cfg_target_has_atomic)] #![feature(const_alloc_layout)] +#![feature(const_assert_type)] #![feature(const_discriminant)] #![feature(const_cell_into_inner)] #![feature(const_checked_int_methods)] @@ -101,7 +102,7 @@ #![feature(const_type_name)] #![feature(const_likely)] #![feature(const_unreachable_unchecked)] -#![feature(const_maybe_assume_init)] +#![feature(const_maybe_uninit_assume_init)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 6251355b9099..eddfff6f513a 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -314,8 +314,7 @@ impl MaybeUninit { /// let data = read(&mut buf); /// ``` #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] - #[rustc_allow_const_fn_unstable(const_maybe_assume_init)] + #[rustc_const_unstable(feature = "maybe_uninit_uninit_array", issue = "none")] #[inline(always)] pub const fn uninit_array() -> [Self; LEN] { // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. @@ -505,7 +504,7 @@ impl MaybeUninit { /// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️ /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] #[rustc_diagnostic_item = "assume_init"] pub const unsafe fn assume_init(self) -> T { @@ -813,7 +812,7 @@ impl MaybeUninit { /// /// [`assume_init_ref`]: MaybeUninit::assume_init_ref #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { // SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that @@ -835,7 +834,7 @@ impl MaybeUninit { /// /// [`assume_init_mut`]: MaybeUninit::assume_init_mut #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a @@ -845,17 +844,15 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } } From 806c7281ec1905423aa4569d79940b59efc1905a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 2 Dec 2020 15:38:37 +0100 Subject: [PATCH 070/719] add comment to `visit_ct_substs` --- compiler/rustc_infer/src/infer/combine.rs | 4 +--- compiler/rustc_middle/src/ty/relate.rs | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 594e2c6205f8..987380304d22 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -881,9 +881,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { - Ok(t) - } + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t), _ => relate::super_relate_tys(self, t, t), } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 80dc7d89d187..ea4e731086fb 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -33,6 +33,11 @@ pub trait TypeRelation<'tcx>: Sized { /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; + /// Whether we should look into the substs of unevaluated constants + /// even if `feature(const_evaluatable_checked)` is active. + /// + /// This is needed in `combine` to prevent accidentially creating + /// infinite types as we abuse `TypeRelation` to walk a type there. fn visit_ct_substs(&self) -> bool { false } From f311db100ba338d13a6f590288e027623a8e9434 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 19:14:10 +0100 Subject: [PATCH 071/719] Added tests for assume_init --- library/core/tests/mem.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 59588d97787b..7822c69d10b3 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -129,3 +129,21 @@ fn test_discriminant_send_sync() { is_send_sync::>(); is_send_sync::>(); } + +#[test] +fn assume_init_good() { + const TRUE: bool = { + let mut x = MaybeUninit::::uninit(); + x.as_mut_ptr().write(true); + x.assume_init() + }; + assert!(TRUE); +} + +#[test] +#[should_panic] +fn assume_init_bad() { + const BAD: () = { + MaybeUninit::::uninit().assume_init(); + }; +} From 25740fc6823ee3901e5917869b1f1ae1b4373c5e Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 2 Dec 2020 18:31:55 +0000 Subject: [PATCH 072/719] rustdoc: --default-theme: minor grammar fix to usage message Signed-off-by: Ian Jackson --- src/librustdoc/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 751f23010539..951bb27a9faf 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -275,7 +275,7 @@ fn opts() -> Vec { "default-theme", "Set the default theme. THEME should be the theme name, generally lowercase. \ If an unknown default theme is specified, the builtin default is used. \ - The set of themes, and the rustdoc built-in default is not stable.", + The set of themes, and the rustdoc built-in default, are not stable.", "THEME", ) }), From 36ee3bde07093ac81f9be113000df69c79c1afca Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 2 Dec 2020 18:32:38 +0000 Subject: [PATCH 073/719] rustdoc: stabilise --default-theme As discussed in #77213, this seems like it has bedded in and can be safely and usefully made stable. (rustdoc already has other stable options that interact quite intimately with the rustdoc-supplied CSS, and also an option for supplying entirely different CSS, so exposing the theme names this way seems a very minor step.) Signed-off-by: Ian Jackson --- src/librustdoc/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 951bb27a9faf..83d2c2d894bf 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -269,7 +269,7 @@ fn opts() -> Vec { "sort modules by where they appear in the program, rather than alphabetically", ) }), - unstable("default-theme", |o| { + stable("default-theme", |o| { o.optopt( "", "default-theme", From 0cf5a8ad15af795beff92f923eac9ba4b71e2790 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 18 Nov 2020 16:37:10 +0100 Subject: [PATCH 074/719] Create `rustc_ty_library` --- Cargo.lock | 11 ++ compiler/rustc_middle/Cargo.toml | 1 + compiler/rustc_middle/src/ty/mod.rs | 88 +----------- compiler/rustc_middle/src/ty/sty.rs | 110 +-------------- compiler/rustc_type_ir/Cargo.toml | 14 ++ compiler/rustc_type_ir/src/lib.rs | 204 ++++++++++++++++++++++++++++ 6 files changed, 234 insertions(+), 194 deletions(-) create mode 100644 compiler/rustc_type_ir/Cargo.toml create mode 100644 compiler/rustc_type_ir/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ce1f705bdffa..3f9d628b491f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3918,6 +3918,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec 1.4.2", "tracing", ] @@ -4251,6 +4252,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "rustc_type_ir" +version = "0.0.0" +dependencies = [ + "bitflags", + "rustc_data_structures", + "rustc_index", + "rustc_serialize", +] + [[package]] name = "rustc_typeck" version = "0.0.0" diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 3250f1830de1..47b7768b410a 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -30,3 +30,4 @@ chalk-ir = "0.36.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "9.0.0" rustc_session = { path = "../rustc_session" } +rustc_type_ir = { path = "../rustc_type_ir" } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5d8edcf70bfd..038de42a6f16 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -56,7 +56,7 @@ pub use self::sty::InferTy::*; pub use self::sty::RegionKind; pub use self::sty::RegionKind::*; pub use self::sty::TyKind::*; -pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST}; +pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar}; pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts}; @@ -67,6 +67,7 @@ pub use self::sty::{ExistentialProjection, PolyExistentialProjection}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; pub use self::sty::{PolyTraitRef, TraitRef, TyKind}; pub use crate::ty::diagnostics::*; +pub use rustc_type_ir::{DebruijnIndex, TypeFlags, INNERMOST}; pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; @@ -497,91 +498,6 @@ pub struct CReaderCacheKey { pub pos: usize, } -bitflags! { - /// Flags that we track on types. These flags are propagated upwards - /// through the type during type construction, so that we can quickly check - /// whether the type has various kinds of types in it without recursing - /// over the type itself. - pub struct TypeFlags: u32 { - // Does this have parameters? Used to determine whether substitution is - // required. - /// Does this have [Param]? - const HAS_TY_PARAM = 1 << 0; - /// Does this have [ReEarlyBound]? - const HAS_RE_PARAM = 1 << 1; - /// Does this have [ConstKind::Param]? - const HAS_CT_PARAM = 1 << 2; - - const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_RE_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits; - - /// Does this have [Infer]? - const HAS_TY_INFER = 1 << 3; - /// Does this have [ReVar]? - const HAS_RE_INFER = 1 << 4; - /// Does this have [ConstKind::Infer]? - const HAS_CT_INFER = 1 << 5; - - /// Does this have inference variables? Used to determine whether - /// inference is required. - const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_RE_INFER.bits - | TypeFlags::HAS_CT_INFER.bits; - - /// Does this have [Placeholder]? - const HAS_TY_PLACEHOLDER = 1 << 6; - /// Does this have [RePlaceholder]? - const HAS_RE_PLACEHOLDER = 1 << 7; - /// Does this have [ConstKind::Placeholder]? - const HAS_CT_PLACEHOLDER = 1 << 8; - - /// `true` if there are "names" of regions and so forth - /// that are local to a particular fn/inferctxt - const HAS_FREE_LOCAL_REGIONS = 1 << 9; - - /// `true` if there are "names" of types and regions and so forth - /// that are local to a particular fn - const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits - | TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_CT_INFER.bits - | TypeFlags::HAS_TY_PLACEHOLDER.bits - | TypeFlags::HAS_CT_PLACEHOLDER.bits - | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; - - /// Does this have [Projection]? - const HAS_TY_PROJECTION = 1 << 10; - /// Does this have [Opaque]? - const HAS_TY_OPAQUE = 1 << 11; - /// Does this have [ConstKind::Unevaluated]? - const HAS_CT_PROJECTION = 1 << 12; - - /// Could this type be normalized further? - const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits - | TypeFlags::HAS_TY_OPAQUE.bits - | TypeFlags::HAS_CT_PROJECTION.bits; - - /// Is an error type/const reachable? - const HAS_ERROR = 1 << 13; - - /// Does this have any region that "appears free" in the type? - /// Basically anything but [ReLateBound] and [ReErased]. - const HAS_FREE_REGIONS = 1 << 14; - - /// Does this have any [ReLateBound] regions? Used to check - /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 15; - - /// Does this have any [ReErased] regions? - const HAS_RE_ERASED = 1 << 16; - - /// Does this value have parameters/placeholders/inference variables which could be - /// replaced later, in a way that would change the results of `impl` specialization? - const STILL_FURTHER_SPECIALIZABLE = 1 << 17; - } -} - #[allow(rustc::usage_of_ty_tykind)] pub struct TyS<'tcx> { /// This field shouldn't be used directly and may be removed in the future. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 78994c6e1c77..72c97dfcf5d7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1289,53 +1289,6 @@ impl<'tcx> ParamConst { } } -rustc_index::newtype_index! { - /// A [De Bruijn index][dbi] is a standard means of representing - /// regions (and perhaps later types) in a higher-ranked setting. In - /// particular, imagine a type like this: - /// - /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) - /// ^ ^ | | | - /// | | | | | - /// | +------------+ 0 | | - /// | | | - /// +----------------------------------+ 1 | - /// | | - /// +----------------------------------------------+ 0 - /// - /// In this type, there are two binders (the outer fn and the inner - /// fn). We need to be able to determine, for any given region, which - /// fn type it is bound by, the inner or the outer one. There are - /// various ways you can do this, but a De Bruijn index is one of the - /// more convenient and has some nice properties. The basic idea is to - /// count the number of binders, inside out. Some examples should help - /// clarify what I mean. - /// - /// Let's start with the reference type `&'b isize` that is the first - /// argument to the inner function. This region `'b` is assigned a De - /// Bruijn index of 0, meaning "the innermost binder" (in this case, a - /// fn). The region `'a` that appears in the second argument type (`&'a - /// isize`) would then be assigned a De Bruijn index of 1, meaning "the - /// second-innermost binder". (These indices are written on the arrays - /// in the diagram). - /// - /// What is interesting is that De Bruijn index attached to a particular - /// variable will vary depending on where it appears. For example, - /// the final type `&'a char` also refers to the region `'a` declared on - /// the outermost fn. But this time, this reference is not nested within - /// any other binders (i.e., it is not an argument to the inner fn, but - /// rather the outer one). Therefore, in this case, it is assigned a - /// De Bruijn index of 0, because the innermost binder in that location - /// is the outer fn. - /// - /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index - #[derive(HashStable)] - pub struct DebruijnIndex { - DEBUG_FORMAT = "DebruijnIndex({})", - const INNERMOST = 0, - } -} - pub type Region<'tcx> = &'tcx RegionKind; /// Representation of regions. Note that the NLL checker uses a distinct @@ -1450,7 +1403,7 @@ pub enum RegionKind { /// Region bound in a function scope, which will be substituted when the /// function is called. - ReLateBound(DebruijnIndex, BoundRegion), + ReLateBound(ty::DebruijnIndex, BoundRegion), /// When checking a function body, the types of all arguments and so forth /// that refer to bound region parameters are modified to refer to free @@ -1614,65 +1567,6 @@ impl<'tcx> PolyExistentialProjection<'tcx> { } } -impl DebruijnIndex { - /// Returns the resulting index when this value is moved into - /// `amount` number of new binders. So, e.g., if you had - /// - /// for<'a> fn(&'a x) - /// - /// and you wanted to change it to - /// - /// for<'a> fn(for<'b> fn(&'a x)) - /// - /// you would need to shift the index for `'a` into a new binder. - #[must_use] - pub fn shifted_in(self, amount: u32) -> DebruijnIndex { - DebruijnIndex::from_u32(self.as_u32() + amount) - } - - /// Update this index in place by shifting it "in" through - /// `amount` number of binders. - pub fn shift_in(&mut self, amount: u32) { - *self = self.shifted_in(amount); - } - - /// Returns the resulting index when this value is moved out from - /// `amount` number of new binders. - #[must_use] - pub fn shifted_out(self, amount: u32) -> DebruijnIndex { - DebruijnIndex::from_u32(self.as_u32() - amount) - } - - /// Update in place by shifting out from `amount` binders. - pub fn shift_out(&mut self, amount: u32) { - *self = self.shifted_out(amount); - } - - /// Adjusts any De Bruijn indices so as to make `to_binder` the - /// innermost binder. That is, if we have something bound at `to_binder`, - /// it will now be bound at INNERMOST. This is an appropriate thing to do - /// when moving a region out from inside binders: - /// - /// ``` - /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) - /// // Binder: D3 D2 D1 ^^ - /// ``` - /// - /// Here, the region `'a` would have the De Bruijn index D3, - /// because it is the bound 3 binders out. However, if we wanted - /// to refer to that region `'a` in the second argument (the `_`), - /// those two binders would not be in scope. In that case, we - /// might invoke `shift_out_to_binder(D3)`. This would adjust the - /// De Bruijn index of `'a` to D1 (the innermost binder). - /// - /// If we invoke `shift_out_to_binder` and the region is in fact - /// bound by one of the binders we are shifting out of, that is an - /// error (and should fail an assertion failure). - pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self { - self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32()) - } -} - /// Region utilities impl RegionKind { /// Is this region named by the user? @@ -1703,7 +1597,7 @@ impl RegionKind { } } - pub fn bound_at_or_above_binder(&self, index: DebruijnIndex) -> bool { + pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool { match *self { ty::ReLateBound(debruijn, _) => debruijn >= index, _ => false, diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml new file mode 100644 index 000000000000..d50451b7794c --- /dev/null +++ b/compiler/rustc_type_ir/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rustc_type_ir" +version = "0.0.0" +authors = ["The Rust Project Developers"] +edition = "2018" + +[lib] +doctest = false + +[dependencies] +bitflags = "1.2.1" +rustc_index = { path = "../rustc_index" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs new file mode 100644 index 000000000000..1c9475f7a66e --- /dev/null +++ b/compiler/rustc_type_ir/src/lib.rs @@ -0,0 +1,204 @@ +#![feature(never_type)] +#![feature(const_panic)] +#![feature(control_flow_enum)] + +#[macro_use] +extern crate bitflags; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; + +bitflags! { + /// Flags that we track on types. These flags are propagated upwards + /// through the type during type construction, so that we can quickly check + /// whether the type has various kinds of types in it without recursing + /// over the type itself. + pub struct TypeFlags: u32 { + // Does this have parameters? Used to determine whether substitution is + // required. + /// Does this have `Param`? + const HAS_TY_PARAM = 1 << 0; + /// Does this have `ReEarlyBound`? + const HAS_RE_PARAM = 1 << 1; + /// Does this have `ConstKind::Param`? + const HAS_CT_PARAM = 1 << 2; + + const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits + | TypeFlags::HAS_RE_PARAM.bits + | TypeFlags::HAS_CT_PARAM.bits; + + /// Does this have `Infer`? + const HAS_TY_INFER = 1 << 3; + /// Does this have `ReVar`? + const HAS_RE_INFER = 1 << 4; + /// Does this have `ConstKind::Infer`? + const HAS_CT_INFER = 1 << 5; + + /// Does this have inference variables? Used to determine whether + /// inference is required. + const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_RE_INFER.bits + | TypeFlags::HAS_CT_INFER.bits; + + /// Does this have `Placeholder`? + const HAS_TY_PLACEHOLDER = 1 << 6; + /// Does this have `RePlaceholder`? + const HAS_RE_PLACEHOLDER = 1 << 7; + /// Does this have `ConstKind::Placeholder`? + const HAS_CT_PLACEHOLDER = 1 << 8; + + /// `true` if there are "names" of regions and so forth + /// that are local to a particular fn/inferctxt + const HAS_FREE_LOCAL_REGIONS = 1 << 9; + + /// `true` if there are "names" of types and regions and so forth + /// that are local to a particular fn + const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits + | TypeFlags::HAS_CT_PARAM.bits + | TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_CT_INFER.bits + | TypeFlags::HAS_TY_PLACEHOLDER.bits + | TypeFlags::HAS_CT_PLACEHOLDER.bits + | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; + + /// Does this have `Projection`? + const HAS_TY_PROJECTION = 1 << 10; + /// Does this have `Opaque`? + const HAS_TY_OPAQUE = 1 << 11; + /// Does this have `ConstKind::Unevaluated`? + const HAS_CT_PROJECTION = 1 << 12; + + /// Could this type be normalized further? + const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits + | TypeFlags::HAS_TY_OPAQUE.bits + | TypeFlags::HAS_CT_PROJECTION.bits; + + /// Is an error type/const reachable? + const HAS_ERROR = 1 << 13; + + /// Does this have any region that "appears free" in the type? + /// Basically anything but `ReLateBound` and `ReErased`. + const HAS_FREE_REGIONS = 1 << 14; + + /// Does this have any `ReLateBound` regions? Used to check + /// if a global bound is safe to evaluate. + const HAS_RE_LATE_BOUND = 1 << 15; + + /// Does this have any `ReErased` regions? + const HAS_RE_ERASED = 1 << 16; + + /// Does this value have parameters/placeholders/inference variables which could be + /// replaced later, in a way that would change the results of `impl` specialization? + const STILL_FURTHER_SPECIALIZABLE = 1 << 17; + } +} + +rustc_index::newtype_index! { + /// A [De Bruijn index][dbi] is a standard means of representing + /// regions (and perhaps later types) in a higher-ranked setting. In + /// particular, imagine a type like this: + /// + /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) + /// ^ ^ | | | + /// | | | | | + /// | +------------+ 0 | | + /// | | | + /// +----------------------------------+ 1 | + /// | | + /// +----------------------------------------------+ 0 + /// + /// In this type, there are two binders (the outer fn and the inner + /// fn). We need to be able to determine, for any given region, which + /// fn type it is bound by, the inner or the outer one. There are + /// various ways you can do this, but a De Bruijn index is one of the + /// more convenient and has some nice properties. The basic idea is to + /// count the number of binders, inside out. Some examples should help + /// clarify what I mean. + /// + /// Let's start with the reference type `&'b isize` that is the first + /// argument to the inner function. This region `'b` is assigned a De + /// Bruijn index of 0, meaning "the innermost binder" (in this case, a + /// fn). The region `'a` that appears in the second argument type (`&'a + /// isize`) would then be assigned a De Bruijn index of 1, meaning "the + /// second-innermost binder". (These indices are written on the arrays + /// in the diagram). + /// + /// What is interesting is that De Bruijn index attached to a particular + /// variable will vary depending on where it appears. For example, + /// the final type `&'a char` also refers to the region `'a` declared on + /// the outermost fn. But this time, this reference is not nested within + /// any other binders (i.e., it is not an argument to the inner fn, but + /// rather the outer one). Therefore, in this case, it is assigned a + /// De Bruijn index of 0, because the innermost binder in that location + /// is the outer fn. + /// + /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index + pub struct DebruijnIndex { + DEBUG_FORMAT = "DebruijnIndex({})", + const INNERMOST = 0, + } +} + +impl DebruijnIndex { + /// Returns the resulting index when this value is moved into + /// `amount` number of new binders. So, e.g., if you had + /// + /// for<'a> fn(&'a x) + /// + /// and you wanted to change it to + /// + /// for<'a> fn(for<'b> fn(&'a x)) + /// + /// you would need to shift the index for `'a` into a new binder. + #[must_use] + pub fn shifted_in(self, amount: u32) -> DebruijnIndex { + DebruijnIndex::from_u32(self.as_u32() + amount) + } + + /// Update this index in place by shifting it "in" through + /// `amount` number of binders. + pub fn shift_in(&mut self, amount: u32) { + *self = self.shifted_in(amount); + } + + /// Returns the resulting index when this value is moved out from + /// `amount` number of new binders. + #[must_use] + pub fn shifted_out(self, amount: u32) -> DebruijnIndex { + DebruijnIndex::from_u32(self.as_u32() - amount) + } + + /// Update in place by shifting out from `amount` binders. + pub fn shift_out(&mut self, amount: u32) { + *self = self.shifted_out(amount); + } + + /// Adjusts any De Bruijn indices so as to make `to_binder` the + /// innermost binder. That is, if we have something bound at `to_binder`, + /// it will now be bound at INNERMOST. This is an appropriate thing to do + /// when moving a region out from inside binders: + /// + /// ``` + /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) + /// // Binder: D3 D2 D1 ^^ + /// ``` + /// + /// Here, the region `'a` would have the De Bruijn index D3, + /// because it is the bound 3 binders out. However, if we wanted + /// to refer to that region `'a` in the second argument (the `_`), + /// those two binders would not be in scope. In that case, we + /// might invoke `shift_out_to_binder(D3)`. This would adjust the + /// De Bruijn index of `'a` to D1 (the innermost binder). + /// + /// If we invoke `shift_out_to_binder` and the region is in fact + /// bound by one of the binders we are shifting out of, that is an + /// error (and should fail an assertion failure). + pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self { + self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32()) + } +} + +impl HashStable for DebruijnIndex { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.as_u32().hash_stable(ctx, hasher); + } +} From 4f9fd2a5d45a0ea0c49a3a78f8f1c8e091b9c604 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 21:07:40 +0100 Subject: [PATCH 075/719] Undo fn -> const fn for all intrinsics but assert_inhabited --- compiler/rustc_mir/src/interpret/intrinsics.rs | 18 +----------------- library/core/src/intrinsics.rs | 2 -- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index c751f4f7eb6c..90018673e1a8 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -407,29 +407,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::transmute => { self.copy_op_transmute(args[0], dest)?; } - sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { + sym::assert_inhabited => { let ty = instance.substs.type_at(0); let layout = self.layout_of(ty)?; if layout.abi.is_uninhabited() { throw_ub_format!("attempted to instantiate uninhabited type `{}`", ty); } - if intrinsic_name == sym::assert_zero_valid - && !layout.might_permit_raw_init(self, /*zero:*/ true).unwrap() - { - throw_ub_format!( - "attempted to zero-initialize type `{}`, which is invalid", - ty - ); - } - if intrinsic_name == sym::assert_uninit_valid - && !layout.might_permit_raw_init(self, /*zero:*/ false).unwrap() - { - throw_ub_format!( - "attempted to leave type `{}` uninitialized, which is invalid", - ty - ); - } } sym::simd_insert => { let index = u64::from(self.read_scalar(args[1])?.to_u32()?); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 0c37bec46987..ac31476f227e 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -822,14 +822,12 @@ extern "rust-intrinsic" { /// zero-initialization: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_zero_valid(); /// A guard for unsafe functions that cannot ever be executed if `T` has invalid /// bit patterns: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_uninit_valid(); /// Gets a reference to a static `Location` indicating where it was called. From c21b275d35bbc624ad5859d69ae5172464fd66e8 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Thu, 3 Dec 2020 00:23:01 +0000 Subject: [PATCH 076/719] rustdoc: document --default-theme option in command line doc Signed-off-by: Ian Jackson --- src/doc/rustdoc/src/command-line-arguments.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 31e002810ce4..faf22296b5da 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -237,6 +237,26 @@ for a target triple that's different than your host triple. All of the usual caveats of cross-compiling code apply. +## `--default-theme`: set the default theme + +Using this flag looks like this: + +```bash +$ rustdoc src/lib.rs --default-theme=ayu +``` + +Sets the default theme (for users whose browser has not remembered a +previous theme selection from the on-page theme picker). + +The supplied value should be the lowercase version of the theme name. +The set of available themes can be seen in the theme picker in the +gneerated output. + +Note that the set of available themes - and their appearance - is not +necessarily stable from one rustdoc version to the next. If the +requested theme does not exist, the builtin default (currently +`light`) is used instead. + ## `--markdown-css`: include more CSS files when rendering markdown Using this flag looks like this: From 63f3876b856e8e995d2b4960ca9f6f617950ce7b Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Thu, 3 Dec 2020 10:22:57 +0000 Subject: [PATCH 077/719] fix typo in src/doc/rustdoc/src/command-line-arguments.md Co-authored-by: Guillaume Gomez --- src/doc/rustdoc/src/command-line-arguments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index faf22296b5da..80f7851debfb 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -250,7 +250,7 @@ previous theme selection from the on-page theme picker). The supplied value should be the lowercase version of the theme name. The set of available themes can be seen in the theme picker in the -gneerated output. +generated output. Note that the set of available themes - and their appearance - is not necessarily stable from one rustdoc version to the next. If the From a8cda1aee15733a9994a8a6c98c6676c18a5caf7 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 3 Dec 2020 11:52:11 +0100 Subject: [PATCH 078/719] Rustup to rustc 1.50.0-nightly (f4db9ffb2 2020-12-02) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index ed1e64f45db0..547f1e0d8f0c 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2020-11-27 +nightly-2020-12-03 From 64e7ff25f65c29c80b7e1659a67562e68d1c8fac Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 3 Dec 2020 12:12:46 +0100 Subject: [PATCH 079/719] Update Cranelift --- Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67ed41e76523..1e873d3a01cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,7 +50,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" dependencies = [ "cranelift-entity", ] @@ -58,7 +58,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" dependencies = [ "byteorder", "cranelift-bforest", @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -85,17 +85,17 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" [[package]] name = "cranelift-entity" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" [[package]] name = "cranelift-frontend" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" dependencies = [ "cranelift-codegen", "log", @@ -106,7 +106,7 @@ dependencies = [ [[package]] name = "cranelift-module" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" dependencies = [ "anyhow", "cranelift-codegen", @@ -118,7 +118,7 @@ dependencies = [ [[package]] name = "cranelift-native" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" dependencies = [ "cranelift-codegen", "raw-cpuid", @@ -128,7 +128,7 @@ dependencies = [ [[package]] name = "cranelift-object" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" dependencies = [ "anyhow", "cranelift-codegen", @@ -141,7 +141,7 @@ dependencies = [ [[package]] name = "cranelift-simplejit" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" dependencies = [ "cranelift-codegen", "cranelift-entity", From d95d03ae8ad10f253dce81a62a9ac372835b9bb4 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 3 Dec 2020 12:59:36 +0100 Subject: [PATCH 080/719] Support #[repr(simd)] on array wrappers Complement to rust-lang/rust#78863 --- src/intrinsics/llvm.rs | 4 ++-- src/intrinsics/mod.rs | 42 +++++++++++++----------------------------- src/intrinsics/simd.rs | 25 +++++++++++++------------ 3 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index 171445f2d71b..d58e4d499584 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -23,8 +23,8 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8` llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) { - let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, a.layout()); - let lane_ty = fx.clif_type(lane_layout.ty).unwrap(); + let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx); + let lane_ty = fx.clif_type(lane_ty).unwrap(); assert!(lane_count <= 32); let mut res = fx.bcx.ins().iconst(types::I32, 0); diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 3563aa250a9b..4cfd4569760e 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -171,27 +171,6 @@ macro validate_simd_type($fx:ident, $intrinsic:ident, $span:ident, $ty:expr) { } } -fn lane_type_and_count<'tcx>( - tcx: TyCtxt<'tcx>, - layout: TyAndLayout<'tcx>, -) -> (TyAndLayout<'tcx>, u16) { - assert!(layout.ty.is_simd()); - let lane_count = match layout.fields { - rustc_target::abi::FieldsShape::Array { stride: _, count } => u16::try_from(count).unwrap(), - _ => unreachable!("lane_type_and_count({:?})", layout), - }; - let lane_layout = layout - .field( - &ty::layout::LayoutCx { - tcx, - param_env: ParamEnv::reveal_all(), - }, - 0, - ) - .unwrap(); - (lane_layout, lane_count) -} - pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option { let (element, count) = match &layout.abi { Abi::Vector { element, count } => (element.clone(), *count), @@ -218,8 +197,10 @@ fn simd_for_each_lane<'tcx, M: Module>( ) { let layout = val.layout(); - let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout); - let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout()); + let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let lane_layout = fx.layout_of(lane_ty); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + let ret_lane_layout = fx.layout_of(ret_lane_ty); assert_eq!(lane_count, ret_lane_count); for lane_idx in 0..lane_count { @@ -248,8 +229,10 @@ fn simd_pair_for_each_lane<'tcx, M: Module>( assert_eq!(x.layout(), y.layout()); let layout = x.layout(); - let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout); - let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout()); + let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let lane_layout = fx.layout_of(lane_ty); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + let ret_lane_layout = fx.layout_of(ret_lane_ty); assert_eq!(lane_count, ret_lane_count); for lane in 0..lane_count { @@ -269,13 +252,14 @@ fn simd_reduce<'tcx, M: Module>( ret: CPlace<'tcx>, f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, TyAndLayout<'tcx>, Value, Value) -> Value, ) { - let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout()); + let (lane_count, lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx); + let lane_layout = fx.layout_of(lane_ty); assert_eq!(lane_layout, ret.layout()); let mut res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx); for lane_idx in 1..lane_count { let lane = val - .value_field(fx, mir::Field::new(lane_idx.into())) + .value_field(fx, mir::Field::new(lane_idx.try_into().unwrap())) .load_scalar(fx); res_val = f(fx, lane_layout, res_val, lane); } @@ -289,14 +273,14 @@ fn simd_reduce_bool<'tcx, M: Module>( ret: CPlace<'tcx>, f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, Value, Value) -> Value, ) { - let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout()); + let (lane_count, _lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx); assert!(ret.layout().ty.is_bool()); let res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx); let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean for lane_idx in 1..lane_count { let lane = val - .value_field(fx, mir::Field::new(lane_idx.into())) + .value_field(fx, mir::Field::new(lane_idx.try_into().unwrap())) .load_scalar(fx); let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean res_val = f(fx, res_val, lane); diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 2b32e866e5ef..e0eb5c59590f 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -73,11 +73,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( assert_eq!(x.layout(), y.layout()); let layout = x.layout(); - let (lane_type, lane_count) = lane_type_and_count(fx.tcx, layout); - let (ret_lane_type, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout()); + let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_type, ret_lane_type); - assert_eq!(n, ret_lane_count); + assert_eq!(lane_ty, ret_lane_ty); + assert_eq!(u64::from(n), ret_lane_count); let total_len = lane_count * 2; @@ -105,14 +105,14 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }; for &idx in &indexes { - assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len); + assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len); } for (out_idx, in_idx) in indexes.into_iter().enumerate() { - let in_lane = if in_idx < lane_count { + let in_lane = if u64::from(in_idx) < lane_count { x.value_field(fx, mir::Field::new(in_idx.into())) } else { - y.value_field(fx, mir::Field::new((in_idx - lane_count).into())) + y.value_field(fx, mir::Field::new(usize::from(in_idx) - usize::try_from(lane_count).unwrap())) }; let out_lane = ret.place_field(fx, mir::Field::new(out_idx)); out_lane.write_cvalue(fx, in_lane); @@ -131,7 +131,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }; let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); - let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, base.layout()); + let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx); if idx >= lane_count.into() { fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count)); } @@ -160,7 +160,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }; let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); - let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, v.layout()); + let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx); if idx >= lane_count.into() { fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count)); } @@ -212,12 +212,13 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( assert_eq!(a.layout(), c.layout()); let layout = a.layout(); - let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout); - let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout()); + let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); assert_eq!(lane_count, ret_lane_count); + let ret_lane_layout = fx.layout_of(ret_lane_ty); for lane in 0..lane_count { - let lane = mir::Field::new(lane.into()); + let lane = mir::Field::new(lane.try_into().unwrap()); let a_lane = a.value_field(fx, lane).load_scalar(fx); let b_lane = b.value_field(fx, lane).load_scalar(fx); let c_lane = c.value_field(fx, lane).load_scalar(fx); From 87c1fdbcfb227c1b7b3b85c146a549a54fea63e8 Mon Sep 17 00:00:00 2001 From: Edd Barrett Date: Tue, 24 Nov 2020 11:29:25 +0000 Subject: [PATCH 081/719] Make the kernel_copy tests more robust/concurrent. These tests write to the same filenames in /tmp and in some cases these files don't get cleaned up properly. This caused issues for us when different users run the tests on the same system, e.g.: ``` ---- sys::unix::kernel_copy::tests::bench_file_to_file_copy stdout ---- thread 'sys::unix::kernel_copy::tests::bench_file_to_file_copy' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 13, kind: PermissionDenied, message: "Permission denied" }', library/std/src/sys/unix/kernel_copy/tests.rs:71:10 ---- sys::unix::kernel_copy::tests::bench_file_to_socket_copy stdout ---- thread 'sys::unix::kernel_copy::tests::bench_file_to_socket_copy' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 13, kind: PermissionDenied, message: "Permission denied" }', library/std/src/sys/unix/kernel_copy/tests.rs:100:10 ``` Use `std::sys_common::io__test::tmpdir()` to solve this. --- library/std/src/sys/unix/kernel_copy/tests.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy/tests.rs b/library/std/src/sys/unix/kernel_copy/tests.rs index 554ebd940223..0e20e99226ed 100644 --- a/library/std/src/sys/unix/kernel_copy/tests.rs +++ b/library/std/src/sys/unix/kernel_copy/tests.rs @@ -1,18 +1,18 @@ -use crate::env::temp_dir; use crate::fs::OpenOptions; use crate::io; use crate::io::Result; use crate::io::SeekFrom; use crate::io::{BufRead, Read, Seek, Write}; use crate::os::unix::io::AsRawFd; +use crate::sys_common::io::test::tmpdir; #[test] fn copy_specialization() -> Result<()> { use crate::io::{BufReader, BufWriter}; - let path = crate::env::temp_dir(); - let source_path = path.join("copy-spec.source"); - let sink_path = path.join("copy-spec.sink"); + let tmp_path = tmpdir(); + let source_path = tmp_path.join("copy-spec.source"); + let sink_path = tmp_path.join("copy-spec.sink"); let result: Result<()> = try { let mut source = crate::fs::OpenOptions::new() @@ -61,7 +61,8 @@ fn copy_specialization() -> Result<()> { #[bench] fn bench_file_to_file_copy(b: &mut test::Bencher) { const BYTES: usize = 128 * 1024; - let src_path = temp_dir().join("file-copy-bench-src"); + let temp_path = tmpdir(); + let src_path = temp_path.join("file-copy-bench-src"); let mut src = crate::fs::OpenOptions::new() .create(true) .truncate(true) @@ -71,7 +72,7 @@ fn bench_file_to_file_copy(b: &mut test::Bencher) { .unwrap(); src.write(&vec![0u8; BYTES]).unwrap(); - let sink_path = temp_dir().join("file-copy-bench-sink"); + let sink_path = temp_path.join("file-copy-bench-sink"); let mut sink = crate::fs::OpenOptions::new() .create(true) .truncate(true) @@ -90,7 +91,8 @@ fn bench_file_to_file_copy(b: &mut test::Bencher) { #[bench] fn bench_file_to_socket_copy(b: &mut test::Bencher) { const BYTES: usize = 128 * 1024; - let src_path = temp_dir().join("pipe-copy-bench-src"); + let temp_path = tmpdir(); + let src_path = temp_path.join("pipe-copy-bench-src"); let mut src = OpenOptions::new() .create(true) .truncate(true) @@ -121,7 +123,8 @@ fn bench_file_to_socket_copy(b: &mut test::Bencher) { #[bench] fn bench_file_to_uds_copy(b: &mut test::Bencher) { const BYTES: usize = 128 * 1024; - let src_path = temp_dir().join("uds-copy-bench-src"); + let temp_path = tmpdir(); + let src_path = temp_path.join("uds-copy-bench-src"); let mut src = OpenOptions::new() .create(true) .truncate(true) From 3548be94c03fd6d1c11afd6af9c884f398a6489e Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Thu, 15 Oct 2020 21:21:45 +0200 Subject: [PATCH 082/719] Gracefully handle confusing -> with : in function return type --- compiler/rustc_parse/src/parser/expr.rs | 5 +- compiler/rustc_parse/src/parser/generics.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 7 +- compiler/rustc_parse/src/parser/path.rs | 4 +- compiler/rustc_parse/src/parser/ty.rs | 78 +++++++++++++++---- src/test/ui/fn/fn-fat-arrow-return.fixed | 18 ----- src/test/ui/fn/fn-fat-arrow-return.stderr | 8 -- src/test/ui/fn/fn-fat-arrow-return2.rs | 10 --- src/test/ui/fn/fn-fat-arrow-return2.stderr | 14 ---- src/test/ui/fn/fn-recover-return-sign.fixed | 28 +++++++ ...ow-return.rs => fn-recover-return-sign.rs} | 10 +++ src/test/ui/fn/fn-recover-return-sign.stderr | 26 +++++++ src/test/ui/fn/fn-recover-return-sign2.rs | 8 ++ src/test/ui/fn/fn-recover-return-sign2.stderr | 14 ++++ src/test/ui/parser/fn-colon-return-type.rs | 3 +- .../ui/parser/fn-colon-return-type.stderr | 4 +- src/test/ui/parser/not-a-pred.rs | 13 +++- src/test/ui/parser/not-a-pred.stderr | 32 +++++++- 18 files changed, 205 insertions(+), 79 deletions(-) delete mode 100644 src/test/ui/fn/fn-fat-arrow-return.fixed delete mode 100644 src/test/ui/fn/fn-fat-arrow-return.stderr delete mode 100644 src/test/ui/fn/fn-fat-arrow-return2.rs delete mode 100644 src/test/ui/fn/fn-fat-arrow-return2.stderr create mode 100644 src/test/ui/fn/fn-recover-return-sign.fixed rename src/test/ui/fn/{fn-fat-arrow-return.rs => fn-recover-return-sign.rs} (50%) create mode 100644 src/test/ui/fn/fn-recover-return-sign.stderr create mode 100644 src/test/ui/fn/fn-recover-return-sign2.rs create mode 100644 src/test/ui/fn/fn-recover-return-sign2.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 790a0c867af8..4d2167442bed 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,5 +1,5 @@ use super::pat::{GateOr, PARAM_EXPECTED}; -use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; +use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; @@ -1647,7 +1647,8 @@ impl<'a> Parser<'a> { self.expect_or()?; args }; - let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverFatArrow::Yes)?; + let output = + self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?; Ok(P(FnDecl { inputs, output })) } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index dd99a7587dd5..ed8d4f78426a 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -240,7 +240,7 @@ impl<'a> Parser<'a> { // Parse type with mandatory colon and (possibly empty) bounds, // or with mandatory equality sign and the second type. - let ty = self.parse_ty()?; + let ty = self.parse_ty_for_where_clause()?; if self.eat(&token::Colon) { let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9e342a0d6813..ff0323a107a7 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,5 +1,5 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error}; -use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; +use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; @@ -1514,7 +1514,7 @@ impl<'a> Parser<'a> { let header = self.parse_fn_front_matter()?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` - let decl = self.parse_fn_decl(req_name, AllowPlus::Yes)?; // `(p: u8, ...)` + let decl = self.parse_fn_decl(req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)` generics.where_clause = self.parse_where_clause()?; // `where T: Ord` let mut sig_hi = self.prev_token.span; @@ -1645,10 +1645,11 @@ impl<'a> Parser<'a> { &mut self, req_name: ReqName, ret_allow_plus: AllowPlus, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { Ok(P(FnDecl { inputs: self.parse_fn_params(req_name)?, - output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, RecoverFatArrow::Yes)?, + output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?, })) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 311a4829fcfc..4510e86e0341 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,4 +1,4 @@ -use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; +use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, TokenType}; use crate::maybe_whole; use rustc_ast::ptr::P; @@ -232,7 +232,7 @@ impl<'a> Parser<'a> { let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; let span = ident.span.to(self.prev_token.span); let output = - self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverFatArrow::No)?; + self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?; ParenthesizedArgs { inputs, output, span }.into() }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index ff19c5cfa856..ee0dc8f6304a 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,12 +43,23 @@ pub(super) enum RecoverQPath { No, } -#[derive(PartialEq)] -pub(super) enum RecoverFatArrow { +#[derive(Copy, Clone, PartialEq)] +pub(super) enum RecoverReturnSign { Yes, + OnlyFatArrow, No, } +impl RecoverReturnSign { + fn can_recover(self, token: &TokenKind) -> bool { + match self { + Self::Yes => matches!(token, token::FatArrow | token::Colon), + Self::OnlyFatArrow => matches!(token, token::FatArrow), + Self::No => false, + } + } +} + // Is `...` (`CVarArgs`) legal at this level of type parsing? #[derive(PartialEq)] enum AllowCVariadic { @@ -68,14 +79,24 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P> { - self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::No) + self.parse_ty_common( + AllowPlus::Yes, + RecoverQPath::Yes, + AllowCVariadic::No, + RecoverReturnSign::Yes, + ) } /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { - self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes) + self.parse_ty_common( + AllowPlus::Yes, + RecoverQPath::Yes, + AllowCVariadic::Yes, + RecoverReturnSign::Yes, + ) } /// Parses a type in restricted contexts where `+` is not permitted. @@ -85,7 +106,22 @@ impl<'a> Parser<'a> { /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { - self.parse_ty_common(AllowPlus::No, RecoverQPath::Yes, AllowCVariadic::No) + self.parse_ty_common( + AllowPlus::No, + RecoverQPath::Yes, + AllowCVariadic::No, + RecoverReturnSign::Yes, + ) + } + + /// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>` + pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P> { + self.parse_ty_common( + AllowPlus::Yes, + RecoverQPath::Yes, + AllowCVariadic::Yes, + RecoverReturnSign::OnlyFatArrow, + ) } /// Parses an optional return type `[ -> TY ]` in a function declaration. @@ -93,13 +129,18 @@ impl<'a> Parser<'a> { &mut self, allow_plus: AllowPlus, recover_qpath: RecoverQPath, - recover_fat_arrow: RecoverFatArrow, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, FnRetTy> { Ok(if self.eat(&token::RArrow) { // FIXME(Centril): Can we unconditionally `allow_plus`? - let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; + let ty = self.parse_ty_common( + allow_plus, + recover_qpath, + AllowCVariadic::No, + recover_return_sign, + )?; FnRetTy::Ty(ty) - } else if recover_fat_arrow == RecoverFatArrow::Yes && self.token == token::FatArrow { + } else if recover_return_sign.can_recover(&self.token.kind) { // Don't `eat` to prevent `=>` from being added as an expected token which isn't // actually expected and could only confuse users self.bump(); @@ -111,7 +152,12 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ) .emit(); - let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; + let ty = self.parse_ty_common( + allow_plus, + recover_qpath, + AllowCVariadic::No, + recover_return_sign, + )?; FnRetTy::Ty(ty) } else { FnRetTy::Default(self.token.span.shrink_to_lo()) @@ -123,6 +169,7 @@ impl<'a> Parser<'a> { allow_plus: AllowPlus, recover_qpath: RecoverQPath, allow_c_variadic: AllowCVariadic, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); @@ -150,14 +197,14 @@ impl<'a> Parser<'a> { TyKind::Infer } else if self.check_fn_front_matter() { // Function pointer type - self.parse_ty_bare_fn(lo, Vec::new())? + self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)? } else if self.check_keyword(kw::For) { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` let lifetime_defs = self.parse_late_bound_lifetime_defs()?; if self.check_fn_front_matter() { - self.parse_ty_bare_fn(lo, lifetime_defs)? + self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)? } else { let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); @@ -359,9 +406,14 @@ impl<'a> Parser<'a> { /// Function Style ABI Parameter types /// ``` /// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers. - fn parse_ty_bare_fn(&mut self, lo: Span, params: Vec) -> PResult<'a, TyKind> { + fn parse_ty_bare_fn( + &mut self, + lo: Span, + params: Vec, + recover_return_sign: RecoverReturnSign, + ) -> PResult<'a, TyKind> { let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?; - let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?; + let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?; let whole_span = lo.to(self.prev_token.span); if let ast::Const::Yes(span) = constness { self.error_fn_ptr_bad_qualifier(whole_span, span, "const"); diff --git a/src/test/ui/fn/fn-fat-arrow-return.fixed b/src/test/ui/fn/fn-fat-arrow-return.fixed deleted file mode 100644 index 0acca85aa679..000000000000 --- a/src/test/ui/fn/fn-fat-arrow-return.fixed +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix -#![allow(unused)] -fn a() -> usize { 0 } -//~^ ERROR return types are denoted using `->` - -fn bar(_: u32) {} - -fn baz() -> *const dyn Fn(u32) { unimplemented!() } - -fn foo() { - match () { - _ if baz() == &bar as &dyn Fn(u32) => (), - () => (), - } -} - -fn main() { -} diff --git a/src/test/ui/fn/fn-fat-arrow-return.stderr b/src/test/ui/fn/fn-fat-arrow-return.stderr deleted file mode 100644 index 1fcdb18a5147..000000000000 --- a/src/test/ui/fn/fn-fat-arrow-return.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: return types are denoted using `->` - --> $DIR/fn-fat-arrow-return.rs:3:8 - | -LL | fn a() => usize { 0 } - | ^^ help: use `->` instead - -error: aborting due to previous error - diff --git a/src/test/ui/fn/fn-fat-arrow-return2.rs b/src/test/ui/fn/fn-fat-arrow-return2.rs deleted file mode 100644 index 316fa2cbf02e..000000000000 --- a/src/test/ui/fn/fn-fat-arrow-return2.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn a() => impl Fn() => bool { - //~^ ERROR return types are denoted using `->` - //~| ERROR expected `;` or `{`, found `=>` - unimplemented!() -} - -fn main() { - let foo = |a: bool| => bool { a }; - dbg!(foo(false)); -} diff --git a/src/test/ui/fn/fn-fat-arrow-return2.stderr b/src/test/ui/fn/fn-fat-arrow-return2.stderr deleted file mode 100644 index a6f9fe3b5732..000000000000 --- a/src/test/ui/fn/fn-fat-arrow-return2.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: return types are denoted using `->` - --> $DIR/fn-fat-arrow-return2.rs:1:8 - | -LL | fn a() => impl Fn() => bool { - | ^^ help: use `->` instead - -error: expected `;` or `{`, found `=>` - --> $DIR/fn-fat-arrow-return2.rs:1:21 - | -LL | fn a() => impl Fn() => bool { - | ^^ expected `;` or `{` - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/fn/fn-recover-return-sign.fixed b/src/test/ui/fn/fn-recover-return-sign.fixed new file mode 100644 index 000000000000..076be6a35a4b --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.fixed @@ -0,0 +1,28 @@ +// run-rustfix +#![allow(unused)] +fn a() -> usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn b()-> usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn bar(_: u32) {} + +fn baz() -> *const dyn Fn(u32) { unimplemented!() } + +fn foo() { + match () { + _ if baz() == &bar as &dyn Fn(u32) => (), + () => (), + } +} + +fn main() { + let foo = |a: bool| -> bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(foo(false)); + + let bar = |a: bool|-> bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(bar(false)); +} diff --git a/src/test/ui/fn/fn-fat-arrow-return.rs b/src/test/ui/fn/fn-recover-return-sign.rs similarity index 50% rename from src/test/ui/fn/fn-fat-arrow-return.rs rename to src/test/ui/fn/fn-recover-return-sign.rs index 4bdcd70d7fc4..0656023c0f89 100644 --- a/src/test/ui/fn/fn-fat-arrow-return.rs +++ b/src/test/ui/fn/fn-recover-return-sign.rs @@ -3,6 +3,9 @@ fn a() => usize { 0 } //~^ ERROR return types are denoted using `->` +fn b(): usize { 0 } +//~^ ERROR return types are denoted using `->` + fn bar(_: u32) {} fn baz() -> *const dyn Fn(u32) { unimplemented!() } @@ -15,4 +18,11 @@ fn foo() { } fn main() { + let foo = |a: bool| => bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(foo(false)); + + let bar = |a: bool|: bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(bar(false)); } diff --git a/src/test/ui/fn/fn-recover-return-sign.stderr b/src/test/ui/fn/fn-recover-return-sign.stderr new file mode 100644 index 000000000000..983109730ff3 --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.stderr @@ -0,0 +1,26 @@ +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:3:8 + | +LL | fn a() => usize { 0 } + | ^^ help: use `->` instead + +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:6:7 + | +LL | fn b(): usize { 0 } + | ^ help: use `->` instead + +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:21:25 + | +LL | let foo = |a: bool| => bool { a }; + | ^^ help: use `->` instead + +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:25:24 + | +LL | let bar = |a: bool|: bool { a }; + | ^ help: use `->` instead + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/fn/fn-recover-return-sign2.rs b/src/test/ui/fn/fn-recover-return-sign2.rs new file mode 100644 index 000000000000..b6a6a1ec2a6e --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign2.rs @@ -0,0 +1,8 @@ +// Separate test file because `Fn() => bool` isn't getting fixed and rustfix complained that +// even though a fix was applied the code was still incorrect + +fn foo() => impl Fn() => bool { + //~^ ERROR return types are denoted using `->` + //~| ERROR expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>` + unimplemented!() +} diff --git a/src/test/ui/fn/fn-recover-return-sign2.stderr b/src/test/ui/fn/fn-recover-return-sign2.stderr new file mode 100644 index 000000000000..d62cacd4bf53 --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign2.stderr @@ -0,0 +1,14 @@ +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign2.rs:4:10 + | +LL | fn foo() => impl Fn() => bool { + | ^^ help: use `->` instead + +error: expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>` + --> $DIR/fn-recover-return-sign2.rs:4:23 + | +LL | fn foo() => impl Fn() => bool { + | ^^ expected one of `+`, `->`, `::`, `;`, `where`, or `{` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/fn-colon-return-type.rs b/src/test/ui/parser/fn-colon-return-type.rs index c791fb3ae674..0001ef57c990 100644 --- a/src/test/ui/parser/fn-colon-return-type.rs +++ b/src/test/ui/parser/fn-colon-return-type.rs @@ -1,4 +1,5 @@ -fn foo(x: i32): i32 { //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `:` +fn foo(x: i32): i32 { +//~^ ERROR return types are denoted using `->` x } diff --git a/src/test/ui/parser/fn-colon-return-type.stderr b/src/test/ui/parser/fn-colon-return-type.stderr index 92df9bc60bd3..1de918782056 100644 --- a/src/test/ui/parser/fn-colon-return-type.stderr +++ b/src/test/ui/parser/fn-colon-return-type.stderr @@ -1,8 +1,8 @@ -error: expected one of `->`, `;`, `where`, or `{`, found `:` +error: return types are denoted using `->` --> $DIR/fn-colon-return-type.rs:1:15 | LL | fn foo(x: i32): i32 { - | ^ expected one of `->`, `;`, `where`, or `{` + | ^ help: use `->` instead error: aborting due to previous error diff --git a/src/test/ui/parser/not-a-pred.rs b/src/test/ui/parser/not-a-pred.rs index 1b3d9bf66bb6..5518b554d8e5 100644 --- a/src/test/ui/parser/not-a-pred.rs +++ b/src/test/ui/parser/not-a-pred.rs @@ -1,6 +1,15 @@ fn f(a: isize, b: isize) : lt(a, b) { } -//~^ ERROR expected one of `->`, `;`, `where`, or `{`, found `:` +//~^ ERROR return types are denoted using `->` +//~| ERROR expected type, found function `lt` [E0573] +//~| ERROR expected type, found local variable `a` [E0573] +//~| ERROR expected type, found local variable `b` [E0573] fn lt(a: isize, b: isize) { } -fn main() { let a: isize = 10; let b: isize = 23; check (lt(a, b)); f(a, b); } +fn main() { + let a: isize = 10; + let b: isize = 23; + check (lt(a, b)); + //~^ ERROR cannot find function `check` in this scope [E0425] + f(a, b); +} diff --git a/src/test/ui/parser/not-a-pred.stderr b/src/test/ui/parser/not-a-pred.stderr index ec413c5594c4..bcc64a687fd0 100644 --- a/src/test/ui/parser/not-a-pred.stderr +++ b/src/test/ui/parser/not-a-pred.stderr @@ -1,8 +1,34 @@ -error: expected one of `->`, `;`, `where`, or `{`, found `:` +error: return types are denoted using `->` --> $DIR/not-a-pred.rs:1:26 | LL | fn f(a: isize, b: isize) : lt(a, b) { } - | ^ expected one of `->`, `;`, `where`, or `{` + | ^ help: use `->` instead -error: aborting due to previous error +error[E0573]: expected type, found function `lt` + --> $DIR/not-a-pred.rs:1:28 + | +LL | fn f(a: isize, b: isize) : lt(a, b) { } + | ^^^^^^^^ not a type +error[E0573]: expected type, found local variable `a` + --> $DIR/not-a-pred.rs:1:31 + | +LL | fn f(a: isize, b: isize) : lt(a, b) { } + | ^ not a type + +error[E0573]: expected type, found local variable `b` + --> $DIR/not-a-pred.rs:1:34 + | +LL | fn f(a: isize, b: isize) : lt(a, b) { } + | ^ not a type + +error[E0425]: cannot find function `check` in this scope + --> $DIR/not-a-pred.rs:12:5 + | +LL | check (lt(a, b)); + | ^^^^^ not found in this scope + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0425, E0573. +For more information about an error, try `rustc --explain E0425`. From 3f28a49177e662b9e16ec9b0fb3e4c4fdf810ad1 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 4 Dec 2020 10:19:32 +0100 Subject: [PATCH 083/719] Update Cranelift This includes bytecodealliance/wasmtime#2403 which enables hotswapping with SimpleJIT --- Cargo.lock | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e873d3a01cd..4b19a7b827ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,7 +50,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" dependencies = [ "cranelift-entity", ] @@ -58,7 +58,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" dependencies = [ "byteorder", "cranelift-bforest", @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -85,17 +85,17 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" [[package]] name = "cranelift-entity" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" [[package]] name = "cranelift-frontend" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" dependencies = [ "cranelift-codegen", "log", @@ -106,7 +106,7 @@ dependencies = [ [[package]] name = "cranelift-module" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" dependencies = [ "anyhow", "cranelift-codegen", @@ -118,7 +118,7 @@ dependencies = [ [[package]] name = "cranelift-native" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" dependencies = [ "cranelift-codegen", "raw-cpuid", @@ -128,7 +128,7 @@ dependencies = [ [[package]] name = "cranelift-object" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" dependencies = [ "anyhow", "cranelift-codegen", @@ -141,8 +141,9 @@ dependencies = [ [[package]] name = "cranelift-simplejit" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#b93381e12684c948119fd4406650c804d6396d9d" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" dependencies = [ + "anyhow", "cranelift-codegen", "cranelift-entity", "cranelift-module", From 5f21ff20b3ab8cfce37a3dfc4641bf0d8e1b1c74 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 11 Oct 2020 13:59:31 +0200 Subject: [PATCH 084/719] Inline codegen_mono_item --- src/driver/aot.rs | 22 ++++++++++++++++++++-- src/driver/jit.rs | 19 +++++++++++++++++-- src/driver/mod.rs | 24 ------------------------ 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 491d6cbbf796..c443483be884 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -8,7 +8,7 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::EncodedMetadata; -use rustc_middle::mir::mono::CodegenUnit; +use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{DebugInfo, OutputType}; @@ -148,7 +148,25 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodege super::predefine_mono_items(&mut cx, &mono_items); for (mono_item, (linkage, visibility)) in mono_items { let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); - super::codegen_mono_item(&mut cx, mono_item, linkage); + match mono_item { + MonoItem::Fn(inst) => { + cx.tcx.sess.time("codegen fn", || { + crate::base::codegen_fn(&mut cx, inst, linkage) + }); + } + MonoItem::Static(def_id) => { + crate::constant::codegen_static(&mut cx.constants_cx, def_id) + } + MonoItem::GlobalAsm(hir_id) => { + let item = cx.tcx.hir().expect_item(hir_id); + if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind { + cx.global_asm.push_str(&*asm.as_str()); + cx.global_asm.push_str("\n\n"); + } else { + bug!("Expected GlobalAsm found {:?}", item); + } + } + } } let (mut module, global_asm, debug, mut unwind_context) = tcx.sess.time("finalize CodegenCx", || cx.finalize()); diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 5a844841c2ce..4d40debc956d 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -5,6 +5,7 @@ use std::ffi::CString; use std::os::raw::{c_char, c_int}; use rustc_codegen_ssa::CrateInfo; +use rustc_middle::mir::mono::MonoItem; use cranelift_simplejit::{SimpleJITBuilder, SimpleJITModule}; @@ -73,12 +74,26 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! { super::predefine_mono_items(&mut cx, &mono_items); for (mono_item, (linkage, visibility)) in mono_items { let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); - super::codegen_mono_item(&mut cx, mono_item, linkage); + match mono_item { + MonoItem::Fn(inst) => { + cx.tcx.sess.time("codegen fn", || { + crate::base::codegen_fn(&mut cx, inst, linkage) + }); + } + MonoItem::Static(def_id) => { + crate::constant::codegen_static(&mut cx.constants_cx, def_id) + } + MonoItem::GlobalAsm(hir_id) => { + let item = cx.tcx.hir().expect_item(hir_id); + tcx.sess + .span_fatal(item.span, "Global asm is not supported in JIT mode"); + } + } } tcx.sess.time("finalize CodegenCx", || cx.finalize()) }); if !global_asm.is_empty() { - tcx.sess.fatal("Global asm is not supported in JIT mode"); + tcx.sess.fatal("Inline asm is not supported in JIT mode"); } crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, &mut unwind_context, true); crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context); diff --git a/src/driver/mod.rs b/src/driver/mod.rs index 7b8cc2ddd48d..0b0ea8a852c6 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -63,30 +63,6 @@ fn predefine_mono_items<'tcx>( }); } -fn codegen_mono_item<'tcx, M: Module>( - cx: &mut crate::CodegenCx<'tcx, M>, - mono_item: MonoItem<'tcx>, - linkage: Linkage, -) { - match mono_item { - MonoItem::Fn(inst) => { - cx.tcx - .sess - .time("codegen fn", || crate::base::codegen_fn(cx, inst, linkage)); - } - MonoItem::Static(def_id) => crate::constant::codegen_static(&mut cx.constants_cx, def_id), - MonoItem::GlobalAsm(hir_id) => { - let item = cx.tcx.hir().expect_item(hir_id); - if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind { - cx.global_asm.push_str(&*asm.as_str()); - cx.global_asm.push_str("\n\n"); - } else { - bug!("Expected GlobalAsm found {:?}", item); - } - } - } -} - fn time(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R { if std::env::var("CG_CLIF_DISPLAY_CG_TIME") .as_ref() From 36363e535a6efb56cc7ef57e5231f526843d3c68 Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Fri, 4 Dec 2020 21:18:01 +0900 Subject: [PATCH 085/719] Refine E0212 error message --- compiler/rustc_typeck/src/collect.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 0ff10abb60a3..38da1e5ea039 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -359,8 +359,8 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx().sess, span, E0212, - "cannot extract an associated type from a higher-ranked trait bound \ - in this context" + "cannot use the associated type of a trait \ + with uninferred generic parameters" ); match self.node() { From a1e94cdcd509779163eff165bd346f7f40607542 Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Thu, 3 Dec 2020 00:23:01 +0900 Subject: [PATCH 086/719] Add long explanation for E0212 Update compiler/rustc_error_codes/src/error_codes/E0212.md Co-authored-by: Joshua Nelson --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0212.md | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0212.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 636c37142ad9..fef6602b9ccb 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -111,6 +111,7 @@ E0206: include_str!("./error_codes/E0206.md"), E0207: include_str!("./error_codes/E0207.md"), E0210: include_str!("./error_codes/E0210.md"), E0211: include_str!("./error_codes/E0211.md"), +E0212: include_str!("./error_codes/E0212.md"), E0214: include_str!("./error_codes/E0214.md"), E0220: include_str!("./error_codes/E0220.md"), E0221: include_str!("./error_codes/E0221.md"), @@ -503,7 +504,6 @@ E0779: include_str!("./error_codes/E0779.md"), // E0196, // cannot determine a type for this closure E0208, // E0209, // builtin traits can only be implemented on structs or enums - E0212, // cannot extract an associated type from a higher-ranked trait bound // E0213, // associated types are not accepted in this context // E0215, // angle-bracket notation is not stable with `Fn` // E0216, // parenthetical notation is only stable with `Fn` diff --git a/compiler/rustc_error_codes/src/error_codes/E0212.md b/compiler/rustc_error_codes/src/error_codes/E0212.md new file mode 100644 index 000000000000..17465414650b --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0212.md @@ -0,0 +1,35 @@ +Cannot use the associated type of +a trait with uninferred generic parameters. + +Erroneous code example: + +```compile_fail,E0212 +pub trait Foo { + type A; + + fn get(&self, t: T) -> Self::A; +} + +fn foo2 Foo<&'x isize>>( + field: I::A) {} // error! +``` + +In this example, we have to instantiate `'x`, and +we don't know what lifetime to instantiate it with. +To fix this, spell out the precise lifetimes involved. +Example: + +``` +pub trait Foo { + type A; + + fn get(&self, t: T) -> Self::A; +} + +fn foo3 Foo<&'x isize>>( + x: >::A) {} // ok! + + +fn foo4<'a, I : for<'x> Foo<&'x isize>>( + x: >::A) {} // ok! +``` From 87c621690a00c96e9f2874ba318ee46db98b7ab5 Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Thu, 3 Dec 2020 00:38:02 +0900 Subject: [PATCH 087/719] Update some associated-types ui test suites --- .../associated-types-project-from-hrtb-in-fn.fixed | 2 +- .../associated-types-project-from-hrtb-in-fn.rs | 2 +- .../associated-types-project-from-hrtb-in-fn.stderr | 3 ++- .../associated-types-project-from-hrtb-in-struct.rs | 8 ++++---- .../associated-types-project-from-hrtb-in-struct.stderr | 9 +++++---- ...ociated-types-project-from-hrtb-in-trait-method.fixed | 4 ++-- ...associated-types-project-from-hrtb-in-trait-method.rs | 4 ++-- ...ciated-types-project-from-hrtb-in-trait-method.stderr | 5 +++-- 8 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed index 760d2b433c87..bca69a976778 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed @@ -11,7 +11,7 @@ pub trait Foo { fn foo2 Foo<&'x isize>>( x: >::A) - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters { // This case is illegal because we have to instantiate `'x`, and // we don't know what region to instantiate it with. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs index 6eb584ea645a..1e23dd8890b9 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs @@ -11,7 +11,7 @@ pub trait Foo { fn foo2 Foo<&'x isize>>( x: I::A) - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters { // This case is illegal because we have to instantiate `'x`, and // we don't know what region to instantiate it with. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr index f2137f68665d..989624bdd93e 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr @@ -1,4 +1,4 @@ -error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context +error[E0212]: cannot use the associated type of a trait with uninferred generic parameters --> $DIR/associated-types-project-from-hrtb-in-fn.rs:13:8 | LL | x: I::A) @@ -6,3 +6,4 @@ LL | x: I::A) error: aborting due to previous error +For more information about this error, try `rustc --explain E0212`. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs index 58f186d7775e..ed30d86cb5b4 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs @@ -9,14 +9,14 @@ pub trait Foo { struct SomeStruct Foo<&'x isize>> { field: I::A - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters } enum SomeEnum<'b, I: for<'a> Foo<&'a isize>> { TupleVariant(I::A), - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters StructVariant { field: I::A }, - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters OkVariant(&'b usize), } @@ -33,7 +33,7 @@ struct YetAnotherStruct<'a, I: for<'x> Foo<&'x isize>> { struct Why<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, 'y, 'z, 'aa, I: for<'l, 'm> Foo<&'l &'m isize>> { field: I::A, - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters } pub fn main() {} diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr index e3fd2860ebcf..cadc3e9eab1c 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr @@ -1,4 +1,4 @@ -error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context +error[E0212]: cannot use the associated type of a trait with uninferred generic parameters --> $DIR/associated-types-project-from-hrtb-in-struct.rs:11:12 | LL | field: I::A @@ -10,7 +10,7 @@ LL | struct SomeStruct<'a, I: for<'x> Foo<&'x isize>> { LL | field: >::A | -error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context +error[E0212]: cannot use the associated type of a trait with uninferred generic parameters --> $DIR/associated-types-project-from-hrtb-in-struct.rs:16:18 | LL | TupleVariant(I::A), @@ -22,7 +22,7 @@ LL | enum SomeEnum<'c, 'b, I: for<'a> Foo<&'a isize>> { LL | TupleVariant(>::A), | -error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context +error[E0212]: cannot use the associated type of a trait with uninferred generic parameters --> $DIR/associated-types-project-from-hrtb-in-struct.rs:18:28 | LL | StructVariant { field: I::A }, @@ -36,7 +36,7 @@ LL | LL | StructVariant { field: >::A }, | -error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context +error[E0212]: cannot use the associated type of a trait with uninferred generic parameters --> $DIR/associated-types-project-from-hrtb-in-struct.rs:35:12 | LL | field: I::A, @@ -51,3 +51,4 @@ LL | field: >::A, error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0212`. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed index acf32bccbecf..66d8613f184a 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed @@ -11,7 +11,7 @@ pub trait Foo { trait SomeTrait Foo<&'x isize>> { fn some_method(&self, arg: >::A); - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters } trait AnotherTrait Foo<&'x isize>> { @@ -30,7 +30,7 @@ struct Peach(std::marker::PhantomData); impl Banana<'a>> Peach { fn mango(&self) -> >::Assoc { - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters Default::default() } } diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs index a249f89685e3..0a1b29de19e3 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs @@ -11,7 +11,7 @@ pub trait Foo { trait SomeTrait Foo<&'x isize>> { fn some_method(&self, arg: I::A); - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters } trait AnotherTrait Foo<&'x isize>> { @@ -30,7 +30,7 @@ struct Peach(std::marker::PhantomData); impl Banana<'a>> Peach { fn mango(&self) -> X::Assoc { - //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + //~^ ERROR cannot use the associated type of a trait with uninferred generic parameters Default::default() } } diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr index a37fec244933..d457f9f8468b 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr @@ -1,10 +1,10 @@ -error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context +error[E0212]: cannot use the associated type of a trait with uninferred generic parameters --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:13:32 | LL | fn some_method(&self, arg: I::A); | ^^^^ help: use a fully qualified path with inferred lifetimes: `>::A` -error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context +error[E0212]: cannot use the associated type of a trait with uninferred generic parameters --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:32:24 | LL | fn mango(&self) -> X::Assoc { @@ -12,3 +12,4 @@ LL | fn mango(&self) -> X::Assoc { error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0212`. From fda4c8d5c188da56d8f25b562a4a25d422179a87 Mon Sep 17 00:00:00 2001 From: oli Date: Fri, 4 Dec 2020 17:28:22 +0000 Subject: [PATCH 088/719] Update documentation to review comments --- library/core/src/alloc/global.rs | 15 +++++++++------ library/core/src/alloc/mod.rs | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 1ecf6abc7546..6549ea1a1241 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -55,9 +55,12 @@ use crate::ptr; /// and implementors must ensure such contracts remain true. /// /// * You may not rely on allocations actually happening, even if there are explicit -/// heap allocations in the source. The optimizer may detect allocation/deallocation -/// pairs that it can instead move to stack allocations/deallocations and thus never -/// invoke the allocator here. +/// heap allocations in the source. +/// The optimizer may detect unused allocations that it can either +/// eliminate entirely or move to the stack and thus never invoke the allocator here. The +/// optimizer may further assume that allocation is infallible, so code that used to fail due +/// to allocator failures may now suddenly work because the optimizer worked around the +/// need for an allocation. /// More concretely, the following code example is unsound, irrespective of whether your /// custom allocator allows counting how many allocations have happened. /// @@ -67,10 +70,10 @@ use crate::ptr; /// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } /// ``` /// -/// Note that allocation/deallocation pairs being moved to the stack is not the only +/// Note that the optimizations mentioned above are not the only /// optimization that can be applied. You may generally not rely on heap allocations -/// happening, if they can be removed without changing program behaviour. -/// Whether allocations happen or not is not part of the program behaviour, even if it +/// happening if they can be removed without changing program behavior. +/// Whether allocations happen or not is not part of the program behavior, even if it /// could be detected via an allocator that tracks allocations by printing or otherwise /// having side effects. #[stable(feature = "global_alloc", since = "1.28.0")] diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 1616d8fab212..fc89046bc427 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -95,8 +95,11 @@ pub unsafe trait AllocRef { /// not have its contents initialized. /// /// Note that you may not rely on this method actually getting called, even if there are calls - /// to it in the source. The optimizer may detect allocation/deallocation pairs that it can - /// instead move to stack allocations/deallocations and thus never invoke the allocator here. + /// to it in the source. The optimizer may detect unused allocations that it can either + /// eliminate entirely or move to the stack and thus never invoke the allocator here. The + /// optimizer may further assume that allocation is infallible, so code that used to fail due + /// to allocator failures may now suddenly work because the optimizer worked around the + /// need for an allocation. /// More concretely, the following code example is unsound, irrespective of whether your /// custom allocator allows counting how many allocations have happened. /// @@ -106,6 +109,13 @@ pub unsafe trait AllocRef { /// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); } /// ``` /// + /// Note that the optimizations mentioned above are not the only + /// optimization that can be applied. You may generally not rely on heap allocations + /// happening if they can be removed without changing program behavior. + /// Whether allocations happen or not is not part of the program behavior, even if it + /// could be detected via an allocator that tracks allocations by printing or otherwise + /// having side effects. + /// /// # Errors /// /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet From 9709ef149c50258b0205995be1dbd99a22a075e0 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 24 Oct 2020 15:37:03 +0200 Subject: [PATCH 089/719] Move hygienic comparison into own function --- .../src/coherence/inherent_impls_overlap.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs index dd90724e93fe..2d1ea7d200ce 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs @@ -33,12 +33,9 @@ impl InherentOverlapChecker<'tcx> { } for item1 in impl_items1.in_definition_order() { - let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).any(|item2| { - // Symbols and namespace match, compare hygienically. - item1.kind.namespace() == item2.kind.namespace() - && item1.ident.normalize_to_macros_2_0() - == item2.ident.normalize_to_macros_2_0() - }); + let collision = impl_items2 + .filter_by_name_unhygienic(item1.ident.name) + .any(|item2| self.compare_hygienically(item1, item2)); if collision { return true; @@ -48,6 +45,12 @@ impl InherentOverlapChecker<'tcx> { false } + fn compare_hygienically(&self, item1: &'tcx ty::AssocItem, item2: &'tcx ty::AssocItem) -> bool { + // Symbols and namespace match, compare hygienically. + item1.kind.namespace() == item2.kind.namespace() + && item1.ident.normalize_to_macros_2_0() == item2.ident.normalize_to_macros_2_0() + } + fn check_for_common_items_in_impls( &self, impl1: DefId, @@ -58,12 +61,9 @@ impl InherentOverlapChecker<'tcx> { let impl_items2 = self.tcx.associated_items(impl2); for item1 in impl_items1.in_definition_order() { - let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).find(|item2| { - // Symbols and namespace match, compare hygienically. - item1.kind.namespace() == item2.kind.namespace() - && item1.ident.normalize_to_macros_2_0() - == item2.ident.normalize_to_macros_2_0() - }); + let collision = impl_items2 + .filter_by_name_unhygienic(item1.ident.name) + .find(|item2| self.compare_hygienically(item1, item2)); if let Some(item2) = collision { let name = item1.ident.normalize_to_macros_2_0(); From 4e14c0597650a3919b0f8f6d725fe24a53892b5c Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Sat, 5 Dec 2020 20:21:21 +0530 Subject: [PATCH 090/719] fix clippy test --- tests/ui/crashes/used_underscore_binding_macro.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/ui/crashes/used_underscore_binding_macro.rs b/tests/ui/crashes/used_underscore_binding_macro.rs index 6d2124c12fe9..c57a45dc7aab 100644 --- a/tests/ui/crashes/used_underscore_binding_macro.rs +++ b/tests/ui/crashes/used_underscore_binding_macro.rs @@ -1,7 +1,6 @@ -#![allow(clippy::useless_attribute)] //issue #2910 +// edition:2018 -#[macro_use] -extern crate serde_derive; +use serde::Deserialize; /// Tests that we do not lint for unused underscores in a `MacroAttribute` /// expansion From 6fe31e76fb7c3a1d6346977e8edfd06c8f2c405e Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Sat, 5 Dec 2020 20:21:21 +0530 Subject: [PATCH 091/719] fix clippy test --- .../clippy/tests/ui/crashes/used_underscore_binding_macro.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs index 6d2124c12fe9..c57a45dc7aab 100644 --- a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs +++ b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs @@ -1,7 +1,6 @@ -#![allow(clippy::useless_attribute)] //issue #2910 +// edition:2018 -#[macro_use] -extern crate serde_derive; +use serde::Deserialize; /// Tests that we do not lint for unused underscores in a `MacroAttribute` /// expansion From db8ddbf570fa7d8df5d71b19b44a771c80c689ba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 5 Dec 2020 17:31:31 +0100 Subject: [PATCH 092/719] Move tooltips messages to CSS instead of inside HTML --- src/librustdoc/html/highlight.rs | 15 +++-- src/librustdoc/html/markdown.rs | 61 +++++---------------- src/librustdoc/html/static/rustdoc.css | 24 +++++--- src/librustdoc/html/static/themes/ayu.css | 4 +- src/librustdoc/html/static/themes/dark.css | 4 +- src/librustdoc/html/static/themes/light.css | 4 +- 6 files changed, 47 insertions(+), 65 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 1cbfbf50dd74..47d2707e40df 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -11,6 +11,7 @@ use std::fmt::{Display, Write}; use std::iter::Peekable; use rustc_lexer::{LiteralKind, TokenKind}; +use rustc_span::edition::Edition; use rustc_span::symbol::Ident; use rustc_span::with_default_session_globals; @@ -19,16 +20,20 @@ crate fn render_with_highlighting( src: String, class: Option<&str>, playground_button: Option<&str>, - tooltip: Option<(&str, &str)>, + tooltip: Option<(Option, &str)>, ) -> String { debug!("highlighting: ================\n{}\n==============", src); let mut out = String::with_capacity(src.len()); - if let Some((tooltip, class)) = tooltip { + if let Some((edition_info, class)) = tooltip { write!( out, - "
{}
", - class, tooltip + "
", + class, + if let Some(edition_info) = edition_info { + format!(" edition=\"{}\"", edition_info) + } else { + String::new() + }, ) .unwrap(); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 8ce686c65502..6229a479b4d0 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -286,60 +286,27 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { }); let tooltip = if ignore != Ignore::None { - Some(("This example is not tested".to_owned(), "ignore")) + Some((None, "ignore")) } else if compile_fail { - Some(("This example deliberately fails to compile".to_owned(), "compile_fail")) + Some((None, "compile_fail")) } else if should_panic { - Some(("This example panics".to_owned(), "should_panic")) + Some((None, "should_panic")) } else if explicit_edition { - Some((format!("This code runs with edition {}", edition), "edition")) + Some((Some(edition), "edition")) } else { None }; - if let Some((s1, s2)) = tooltip { - s.push_str(&highlight::render_with_highlighting( - text, - Some(&format!( - "rust-example-rendered{}", - if ignore != Ignore::None { - " ignore" - } else if compile_fail { - " compile_fail" - } else if should_panic { - " should_panic" - } else if explicit_edition { - " edition " - } else { - "" - } - )), - playground_button.as_deref(), - Some((s1.as_str(), s2)), - )); - Some(Event::Html(s.into())) - } else { - s.push_str(&highlight::render_with_highlighting( - text, - Some(&format!( - "rust-example-rendered{}", - if ignore != Ignore::None { - " ignore" - } else if compile_fail { - " compile_fail" - } else if should_panic { - " should_panic" - } else if explicit_edition { - " edition " - } else { - "" - } - )), - playground_button.as_deref(), - None, - )); - Some(Event::Html(s.into())) - } + s.push_str(&highlight::render_with_highlighting( + text, + Some(&format!( + "rust-example-rendered{}", + if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() } + )), + playground_button.as_deref(), + tooltip, + )); + Some(Event::Html(s.into())) } } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 8eef65a231d0..afc4308b68f9 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1079,20 +1079,29 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { cursor: pointer; } -.tooltip .tooltiptext { - width: 120px; +.tooltip::after { display: none; text-align: center; padding: 5px 3px 3px 3px; border-radius: 6px; margin-left: 5px; - top: -5px; - left: 105%; - z-index: 10; font-size: 16px; } -.tooltip .tooltiptext::after { +.tooltip.ignore::after { + content: "This example is not tested"; +} +.tooltip.compile_fail::after { + content: "This example deliberately fails to compile"; +} +.tooltip.should_panic::after { + content: "This example panics"; +} +.tooltip.edition::after { + content: "This code runs with edition " attr(edition); +} + +.tooltip::before { content: " "; position: absolute; top: 50%; @@ -1100,9 +1109,10 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { margin-top: -5px; border-width: 5px; border-style: solid; + display: none; } -.tooltip:hover .tooltiptext { +.tooltip:hover::before, .tooltip:hover::after { display: inline; } diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index c1f796f09e80..9c71fbb7f03a 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -388,13 +388,13 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #39AFD7; } -.tooltip .tooltiptext { +.tooltip::after { background-color: #314559; color: #c5c5c5; border: 1px solid #5c6773; } -.tooltip .tooltiptext::after { +.tooltip::before { border-color: transparent #314559 transparent transparent; } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 946ca0a40c9d..eb25272ea3bb 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -337,13 +337,13 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #0089ff; } -.tooltip .tooltiptext { +.tooltip::after { background-color: #000; color: #fff; border-color: #000; } -.tooltip .tooltiptext::after { +.tooltip::before { border-color: transparent black transparent transparent; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index e0b9a04921a8..20e3c0a40929 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -329,12 +329,12 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #0089ff; } -.tooltip .tooltiptext { +.tooltip::after { background-color: #000; color: #fff; } -.tooltip .tooltiptext::after { +.tooltip::before { border-color: transparent black transparent transparent; } From d366ed2730ed4a11df8a18f440c6874f7fa610f2 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 5 Dec 2020 17:32:19 +0100 Subject: [PATCH 093/719] abort() now takes a msg parameter --- compiler/rustc_mir/src/const_eval/error.rs | 2 ++ compiler/rustc_mir/src/interpret/intrinsics.rs | 4 ++-- compiler/rustc_mir/src/interpret/machine.rs | 6 ++++-- compiler/rustc_mir/src/interpret/terminator.rs | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 39358e03e759..345a3d7e79bc 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -20,6 +20,7 @@ pub enum ConstEvalErrKind { ModifiedGlobal, AssertFailure(AssertKind), Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, + Abort(String), } // The errors become `MachineStop` with plain strings when being raised. @@ -46,6 +47,7 @@ impl fmt::Display for ConstEvalErrKind { Panic { msg, line, col, file } => { write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) } + Abort(ref msg) => write!(f, "{}", msg) } } } diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 90018673e1a8..18abf4291b1e 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -126,7 +126,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { None => match intrinsic_name { sym::transmute => throw_ub_format!("transmuting to uninhabited type"), sym::unreachable => throw_ub!(Unreachable), - sym::abort => M::abort(self)?, + sym::abort => M::abort(self, "aborted execution".to_owned())?, // Unsupported diverging intrinsic. _ => return Ok(false), }, @@ -412,7 +412,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of(ty)?; if layout.abi.is_uninhabited() { - throw_ub_format!("attempted to instantiate uninhabited type `{}`", ty); + M::abort(self, format!("attempted to instantiate uninhabited type `{}`", ty))?; } } sym::simd_insert => { diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 66dbacb2f9d4..1c13cdbc6e67 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -176,8 +176,10 @@ pub trait Machine<'mir, 'tcx>: Sized { ) -> InterpResult<'tcx>; /// Called to evaluate `Abort` MIR terminator. - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { - throw_unsup_format!("aborting execution is not supported") + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + use crate::const_eval::ConstEvalErrKind; + + Err(ConstEvalErrKind::Abort(msg).into()) } /// Called for all binary operations where the LHS has pointer type. diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index bb11c2a23bd8..18079488c891 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Abort => { - M::abort(self)?; + M::abort(self, "aborted execution".to_owned())?; } // When we encounter Resume, we've finished unwinding From 7bd754cf8ca8e4b673f5432c837150b53c8d713d Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 5 Dec 2020 18:39:10 +0100 Subject: [PATCH 094/719] Fix tests (hopefully) --- compiler/rustc_mir/src/const_eval/error.rs | 2 +- library/core/tests/mem.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 345a3d7e79bc..0e610e375522 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -47,7 +47,7 @@ impl fmt::Display for ConstEvalErrKind { Panic { msg, line, col, file } => { write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) } - Abort(ref msg) => write!(f, "{}", msg) + Abort(ref msg) => write!(f, "{}", msg), } } } diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 7822c69d10b3..f2e441de30bb 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -132,7 +132,7 @@ fn test_discriminant_send_sync() { #[test] fn assume_init_good() { - const TRUE: bool = { + const TRUE: bool = unsafe { let mut x = MaybeUninit::::uninit(); x.as_mut_ptr().write(true); x.assume_init() @@ -143,7 +143,7 @@ fn assume_init_good() { #[test] #[should_panic] fn assume_init_bad() { - const BAD: () = { + const BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); }; } From 94762417e8957caa5db219e11be58c4de5def4c6 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 5 Dec 2020 19:37:03 +0100 Subject: [PATCH 095/719] Still unable to get the tests working --- library/core/tests/lib.rs | 2 ++ library/core/tests/mem.rs | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 106c9fe5da3e..9e7a8189c816 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -11,6 +11,7 @@ #![feature(cfg_target_has_atomic)] #![feature(const_assume)] #![feature(const_cell_into_inner)] +#![feature(const_maybe_uninit_assume_init)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -53,6 +54,7 @@ #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] +#![feature(const_assert_type)] #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(option_unwrap_none)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index f2e441de30bb..4ebcf27e1734 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -132,18 +132,17 @@ fn test_discriminant_send_sync() { #[test] fn assume_init_good() { - const TRUE: bool = unsafe { - let mut x = MaybeUninit::::uninit(); - x.as_mut_ptr().write(true); - x.assume_init() - }; + const TRUE: bool = unsafe { MaybeUninit::::new(true).assume_init() }; + assert!(TRUE); } #[test] -#[should_panic] fn assume_init_bad() { - const BAD: () = unsafe { + const _BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); + //~^ ERROR the type `!` does not permit being left uninitialized + //~| ERROR this code causes undefined behavior when executed + //~| ERROR help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done }; } From 9b6293692801f703e694c4c7f61b165b939cea8d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 5 Dec 2020 17:31:39 +0100 Subject: [PATCH 096/719] Update tests --- src/test/rustdoc/codeblock-title.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/test/rustdoc/codeblock-title.rs b/src/test/rustdoc/codeblock-title.rs index b59b21111b00..1327fd67d316 100644 --- a/src/test/rustdoc/codeblock-title.rs +++ b/src/test/rustdoc/codeblock-title.rs @@ -1,10 +1,9 @@ #![crate_name = "foo"] -// ignore-tidy-linelength - -// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]/span' "This example deliberately fails to compile" -// @has foo/fn.bar.html '//*[@class="tooltip ignore"]/span' "This example is not tested" -// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]/span' "This example panics" +// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]' "ⓘ" +// @has foo/fn.bar.html '//*[@class="tooltip ignore"]' "ⓘ" +// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]' "ⓘ" +// @has foo/fn.bar.html '//*[@edition="2018"]' "ⓘ" /// foo /// @@ -20,7 +19,7 @@ /// hoo(); /// ``` /// -/// ``` +/// ```edition2018 /// let x = 0; /// ``` pub fn bar() -> usize { 2 } From 77d80b22f1abe8392f7124fec343fdbbe760340e Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 24 Oct 2020 21:13:54 +0200 Subject: [PATCH 097/719] Introduce if-let guards in the HIR --- compiler/rustc_ast_lowering/src/expr.rs | 15 ++++++++++----- compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_hir/src/intravisit.rs | 4 ++++ compiler/rustc_hir_pretty/src/lib.rs | 9 +++++++++ src/test/ui/rfc-2294-if-let-guard/feature-gate.rs | 1 - .../ui/rfc-2294-if-let-guard/feature-gate.stderr | 9 --------- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e0e78a4d6095..7c95c7f64809 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -505,14 +505,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { + let pat = self.lower_pat(&arm.pat); + let guard = arm.guard.as_ref().map(|cond| { + if let ExprKind::Let(ref pat, ref scrutinee) = cond.kind { + hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee)) + } else { + hir::Guard::If(self.lower_expr(cond)) + } + }); hir::Arm { hir_id: self.next_id(), attrs: self.lower_attrs(&arm.attrs), - pat: self.lower_pat(&arm.pat), - guard: match arm.guard { - Some(ref x) => Some(hir::Guard::If(self.lower_expr(x))), - _ => None, - }, + pat, + guard, body: self.lower_expr(&arm.body), span: arm.span, } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 44dc6673564a..03cb4b76dc0e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1160,6 +1160,7 @@ pub struct Arm<'hir> { #[derive(Debug, HashStable_Generic)] pub enum Guard<'hir> { If(&'hir Expr<'hir>), + IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>), } #[derive(Debug, HashStable_Generic)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3e8fc689acf7..ea3f2b7f679e 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1228,6 +1228,10 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { if let Some(ref g) = arm.guard { match g { Guard::If(ref e) => visitor.visit_expr(e), + Guard::IfLet(ref pat, ref e) => { + visitor.visit_pat(pat); + visitor.visit_expr(e); + } } } visitor.visit_expr(&arm.body); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 25b09d76295f..6897a3495131 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2002,6 +2002,15 @@ impl<'a> State<'a> { self.print_expr(&e); self.s.space(); } + hir::Guard::IfLet(pat, e) => { + self.word_nbsp("if"); + self.word_nbsp("let"); + self.print_pat(&pat); + self.s.space(); + self.word_space("="); + self.print_expr(&e); + self.s.space(); + } } } self.word_space("=>"); diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs index c0a9bbc36b24..311d1afcfc0e 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs @@ -6,7 +6,6 @@ fn _if_let_guard() { match () { () if let 0 = 1 => {} //~^ ERROR `if let` guard is not implemented - //~| ERROR `let` expressions are not supported here () if (let 0 = 1) => {} //~^ ERROR `let` expressions in this position are experimental diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr index 5c7f8190dd6e..d43096336c5b 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -169,15 +169,6 @@ LL | use_expr!((let 0 = 1)); = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable -error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:7:15 - | -LL | () if let 0 = 1 => {} - | ^^^^^^^^^ - | - = note: only supported directly in conditions of `if`- and `while`-expressions - = note: as well as when nested within `&&` and parenthesis in those conditions - error: `let` expressions are not supported here --> $DIR/feature-gate.rs:11:16 | From f9cc626028d5ae1bcecf4703fae59d165338ee20 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 11 Nov 2020 16:12:45 +0100 Subject: [PATCH 098/719] Implement typechecking if-let guards --- compiler/rustc_typeck/src/check/_match.rs | 32 ++++++++++++------- .../src/check/generator_interior.rs | 4 +++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 3a5eeb5381be..3106f19cf86f 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(60707): Consider removing hack with principled solution. self.check_expr_has_type_or_error(scrut, self.tcx.types.bool, |_| {}) } else { - self.demand_scrutinee_type(arms, scrut) + self.demand_scrutinee_type(scrut, arms_contain_ref_bindings(arms), arms.is_empty()) }; // If there are no arms, that is a diverging match; a special case. @@ -98,7 +98,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.diverges.set(Diverges::Maybe); match g { hir::Guard::If(e) => { - self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}) + self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); + } + hir::Guard::IfLet(pat, e) => { + let scrutinee_ty = self.demand_scrutinee_type( + e, + pat.contains_explicit_ref_binding(), + false, + ); + self.check_pat_top(&pat, scrutinee_ty, None, true); } }; } @@ -450,8 +458,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn demand_scrutinee_type( &self, - arms: &'tcx [hir::Arm<'tcx>], scrut: &'tcx hir::Expr<'tcx>, + contains_ref_bindings: Option, + no_arms: bool, ) -> Ty<'tcx> { // Not entirely obvious: if matches may create ref bindings, we want to // use the *precise* type of the scrutinee, *not* some supertype, as @@ -505,17 +514,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // (once introduced) is populated by the time we get here. // // See #44848. - let contains_ref_bindings = arms - .iter() - .filter_map(|a| a.pat.contains_explicit_ref_binding()) - .max_by_key(|m| match *m { - hir::Mutability::Mut => 1, - hir::Mutability::Not => 0, - }); - if let Some(m) = contains_ref_bindings { self.check_expr_with_needs(scrut, Needs::maybe_mut_place(m)) - } else if arms.is_empty() { + } else if no_arms { self.check_expr(scrut) } else { // ...but otherwise we want to use any supertype of the @@ -546,3 +547,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + +fn arms_contain_ref_bindings(arms: &'tcx [hir::Arm<'tcx>]) -> Option { + arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max_by_key(|m| match *m { + hir::Mutability::Mut => 1, + hir::Mutability::Not => 0, + }) +} diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 602b79802b33..5bc40d617d04 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -246,6 +246,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { Guard::If(ref e) => { self.visit_expr(e); } + Guard::IfLet(ref pat, ref e) => { + self.visit_pat(pat); + self.visit_expr(e); + } } let mut scope_var_ids = From cfaaa21e2a8d0871be0e1e0120ead44e7c8c3625 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 11 Nov 2020 16:14:04 +0100 Subject: [PATCH 099/719] Implement liveness passes for if-let guards --- compiler/rustc_passes/src/liveness.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index debb873beb93..5ff5fd3a6b6d 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -358,6 +358,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { self.add_from_pat(&arm.pat); + if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + self.add_from_pat(pat); + } intravisit::walk_arm(self, arm); } @@ -1029,10 +1032,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { for arm in arms { let body_succ = self.propagate_through_expr(&arm.body, succ); - let guard_succ = self.propagate_through_opt_expr( - arm.guard.as_ref().map(|hir::Guard::If(e)| *e), - body_succ, - ); + let guard_succ = arm.guard.as_ref().map_or(body_succ, |g| match g { + hir::Guard::If(e) => self.propagate_through_expr(e, body_succ), + hir::Guard::IfLet(pat, e) => { + let let_bind = self.define_bindings_in_pat(pat, body_succ); + self.propagate_through_expr(e, let_bind) + } + }); let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ); self.merge_from_succ(ln, arm_succ, first_merge); first_merge = false; From bab20800f0e7e6252c5c0da0a7a1ba123785cbca Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 11 Nov 2020 16:14:45 +0100 Subject: [PATCH 100/719] Introduce if-let guards in the THIR --- compiler/rustc_mir_build/src/thir/cx/expr.rs | 8 ++++---- compiler/rustc_mir_build/src/thir/mod.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e404afeb698a..310673f5efc8 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -776,10 +776,10 @@ impl ToBorrowKind for hir::Mutability { fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> { Arm { pattern: cx.pattern_from_hir(&arm.pat), - guard: match arm.guard { - Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())), - _ => None, - }, + guard: arm.guard.as_ref().map(|g| match g { + hir::Guard::If(ref e) => Guard::If(e.to_ref()), + hir::Guard::IfLet(ref pat, ref e) => Guard::IfLet(cx.pattern_from_hir(pat), e.to_ref()) + }), body: arm.body.to_ref(), lint_level: LintLevel::Explicit(arm.hir_id), scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }, diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index 1a901746d508..ace9cad4d299 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -344,6 +344,7 @@ crate struct Arm<'tcx> { #[derive(Clone, Debug)] crate enum Guard<'tcx> { If(ExprRef<'tcx>), + IfLet(Pat<'tcx>, ExprRef<'tcx>), } #[derive(Copy, Clone, Debug)] From f3d4aa6afbad980da62b20cd4583079be7d62104 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 13 Nov 2020 18:27:27 +0100 Subject: [PATCH 101/719] Implement lowering of if-let guards to MIR --- compiler/rustc_hir/src/hir.rs | 4 +- .../rustc_mir_build/src/build/matches/mod.rs | 54 +++++++++++++++---- compiler/rustc_mir_build/src/build/scope.rs | 1 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- .../src/thir/pattern/check_match.rs | 31 +++++++++++ compiler/rustc_passes/src/check_const.rs | 2 + .../clippy/clippy_lints/src/utils/author.rs | 1 + 7 files changed, 84 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 03cb4b76dc0e..f850295e62f5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1722,6 +1722,8 @@ pub enum MatchSource { IfDesugar { contains_else_clause: bool }, /// An `if let _ = _ { .. }` (optionally with `else { .. }`). IfLetDesugar { contains_else_clause: bool }, + /// An `if let _ = _ => { .. }` match guard. + IfLetGuardDesugar, /// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`). WhileDesugar, /// A `while let _ = _ { .. }` (which was desugared to a @@ -1740,7 +1742,7 @@ impl MatchSource { use MatchSource::*; match self { Normal => "match", - IfDesugar { .. } | IfLetDesugar { .. } => "if", + IfDesugar { .. } | IfLetDesugar { .. } | IfLetGuardDesugar => "if", WhileDesugar | WhileLetDesugar => "while", ForLoopDesugar => "for", TryDesugar => "?", diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 7ffdb7e33fb1..d4715b836ea0 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -228,6 +228,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard: Option<&Guard<'tcx>>, fake_borrow_temps: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, + arm_span: Option, arm_scope: Option, ) -> BasicBlock { if candidate.subcandidates.is_empty() { @@ -239,6 +240,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard, fake_borrow_temps, scrutinee_span, + arm_span, true, ) } else { @@ -274,6 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard, &fake_borrow_temps, scrutinee_span, + arm_span, schedule_drops, ); if arm_scope.is_none() { @@ -436,6 +439,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &fake_borrow_temps, irrefutable_pat.span, None, + None, ) .unit() } @@ -817,11 +821,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// For an example of a case where we set `otherwise_block`, even for an /// exhaustive match consider: /// + /// ```rust /// match x { /// (true, true) => (), /// (_, false) => (), /// (false, true) => (), /// } + /// ``` /// /// For this match, we check if `x.0` matches `true` (for the first /// arm). If that's false, we check `x.1`. If it's `true` we check if @@ -935,11 +941,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Link up matched candidates. For example, if we have something like /// this: /// + /// ```rust /// ... /// Some(x) if cond => ... /// Some(x) => ... /// Some(x) if cond => ... /// ... + /// ``` /// /// We generate real edges from: /// * `start_block` to the `prebinding_block` of the first pattern, @@ -1517,7 +1525,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Initializes each of the bindings from the candidate by /// moving/copying/ref'ing the source as appropriate. Tests the guard, if /// any, and then branches to the arm. Returns the block for the case where - /// the guard fails. + /// the guard succeeds. /// /// Note: we do not check earlier that if there is a guard, /// there cannot be move bindings. We avoid a use-after-move by only @@ -1529,6 +1537,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard: Option<&Guard<'tcx>>, fake_borrows: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, + arm_span: Option, schedule_drops: bool, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -1659,15 +1668,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow); } - // the block to branch to if the guard fails; if there is no - // guard, this block is simply unreachable - let guard = match guard { - Guard::If(e) => self.hir.mirror(e.clone()), + let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard { + Guard::If(e) => { + let e = self.hir.mirror(e.clone()); + let source_info = self.source_info(e.span); + (e.span, self.test_bool(block, e, source_info)) + }, + Guard::IfLet(pat, scrutinee) => { + let scrutinee_span = scrutinee.span(); + let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span)); + let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false); + let wildcard = Pat::wildcard_from_ty(pat.ty); + let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false); + let fake_borrow_temps = + self.lower_match_tree(block, pat.span, false, &mut [&mut guard_candidate, &mut otherwise_candidate]); + self.declare_bindings( + None, + pat.span.to(arm_span.unwrap()), + pat, + ArmHasGuard(false), + Some((Some(&scrutinee_place), scrutinee.span())), + ); + let post_guard_block = self.bind_pattern( + self.source_info(pat.span), + guard_candidate, + None, + &fake_borrow_temps, + scrutinee.span(), + None, + None, + ); + let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); + (scrutinee_span, (post_guard_block, otherwise_post_guard_block)) + } }; - let source_info = self.source_info(guard.span); - let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span)); - let (post_guard_block, otherwise_post_guard_block) = - self.test_bool(block, guard, source_info); + let source_info = self.source_info(guard_span); + let guard_end = self.source_info(tcx.sess.source_map().end_point(guard_span)); let guard_frame = self.guard_context.pop().unwrap(); debug!("Exiting guard building context with locals: {:?}", guard_frame); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 468b3484ca5e..0f38c30818fd 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -1220,6 +1220,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm.guard.as_ref(), &fake_borrow_temps, scrutinee_span, + Some(arm.span), Some(arm.scope), ); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 310673f5efc8..aac1e505b653 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -778,7 +778,7 @@ fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'t pattern: cx.pattern_from_hir(&arm.pat), guard: arm.guard.as_ref().map(|g| match g { hir::Guard::If(ref e) => Guard::If(e.to_ref()), - hir::Guard::IfLet(ref pat, ref e) => Guard::IfLet(cx.pattern_from_hir(pat), e.to_ref()) + hir::Guard::IfLet(ref pat, ref e) => Guard::IfLet(cx.pattern_from_hir(pat), e.to_ref()), }), body: arm.body.to_ref(), lint_level: LintLevel::Explicit(arm.hir_id), diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 97edbd83b89c..29b7e176b0e1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -164,10 +164,20 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { for arm in arms { // Check the arm for some things unrelated to exhaustiveness. self.check_patterns(&arm.pat); + if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + self.check_patterns(pat); + } } let mut cx = self.new_cx(scrut.hir_id); + for arm in arms { + if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; + check_if_let_guard(&mut cx, &tpat, pat.hir_id); + } + } + let mut have_errors = false; let arms: Vec<_> = arms @@ -360,12 +370,28 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir:: let msg = match source { hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern", hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern", + hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard", _ => bug!(), }; lint.build(msg).emit() }); } +fn check_if_let_guard<'p, 'tcx>( + cx: &mut MatchCheckCtxt<'p, 'tcx>, + pat: &'p super::Pat<'tcx>, + pat_id: HirId, +) { + let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; + let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty); + report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar); + + if report.non_exhaustiveness_witnesses.is_empty() { + // The match is exhaustive, i.e. the if let pattern is irrefutable. + irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar) + } +} + /// Report unreachable arms, if any. fn report_arm_reachability<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, @@ -390,6 +416,11 @@ fn report_arm_reachability<'p, 'tcx>( } } + hir::MatchSource::IfLetGuardDesugar => { + assert_eq!(arm_index, 0); + unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None); + } + hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall); } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index e37c6418eb81..2d6bbff460d7 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -45,6 +45,8 @@ impl NonConstExpr { return None; } + Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"), + // All other expressions are allowed. Self::Loop(Loop | While | WhileLet) | Self::Match( diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 7250de3a41c0..135f289a2b3f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -730,6 +730,7 @@ fn desugaring_name(des: hir::MatchSource) -> String { "MatchSource::IfLetDesugar {{ contains_else_clause: {} }}", contains_else_clause ), + hir::MatchSource::IfLetGuardDesugar => "MatchSource::IfLetGuardDesugar".to_string(), hir::MatchSource::IfDesugar { contains_else_clause } => format!( "MatchSource::IfDesugar {{ contains_else_clause: {} }}", contains_else_clause From 402f55f33f368a34ee7375864f30f78403b9b159 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 13 Nov 2020 18:27:27 +0100 Subject: [PATCH 102/719] Implement lowering of if-let guards to MIR --- clippy_lints/src/utils/author.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 7250de3a41c0..135f289a2b3f 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -730,6 +730,7 @@ fn desugaring_name(des: hir::MatchSource) -> String { "MatchSource::IfLetDesugar {{ contains_else_clause: {} }}", contains_else_clause ), + hir::MatchSource::IfLetGuardDesugar => "MatchSource::IfLetGuardDesugar".to_string(), hir::MatchSource::IfDesugar { contains_else_clause } => format!( "MatchSource::IfDesugar {{ contains_else_clause: {} }}", contains_else_clause From 61e69bc3fc92c0e76bc8a3977c82cfac75efd743 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 15 Nov 2020 22:51:02 +0100 Subject: [PATCH 103/719] Handle `Guard::IfLet` in clippy --- src/tools/clippy/clippy_lints/src/shadow.rs | 4 ++++ src/tools/clippy/clippy_lints/src/utils/author.rs | 12 ++++++++++++ src/tools/clippy/clippy_lints/src/utils/hir_utils.rs | 4 +++- src/tools/clippy/clippy_lints/src/utils/inspector.rs | 5 +++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 225fe58906f7..f83965926782 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -342,6 +342,10 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut if let Some(ref guard) = arm.guard { match guard { Guard::If(if_expr) => check_expr(cx, if_expr, bindings), + Guard::IfLet(guard_pat, guard_expr) => { + check_pat(cx, guard_pat, Some(*guard_expr), guard_pat.span, bindings); + check_expr(cx, guard_expr, bindings); + }, } } check_expr(cx, &arm.body, bindings); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 135f289a2b3f..4249dbb4e651 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -372,6 +372,18 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = if_expr_pat; self.visit_expr(if_expr); }, + hir::Guard::IfLet(ref if_let_pat, ref if_let_expr) => { + let if_let_pat_pat = self.next("pat"); + let if_let_expr_pat = self.next("expr"); + println!( + " if let Guard::IfLet(ref {}, ref {}) = {};", + if_let_pat_pat, if_let_expr_pat, guard_pat + ); + self.current = if_let_expr_pat; + self.visit_expr(if_let_expr); + self.current = if_let_pat_pat; + self.visit_pat(if_let_pat); + }, } } self.current = format!("{}[{}].pat", arms_pat, i); diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs index e4ad105c3513..b0099b4a7925 100644 --- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs @@ -169,6 +169,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool { match (left, right) { (Guard::If(l), Guard::If(r)) => self.eq_expr(l, r), + (Guard::IfLet(lp, le), Guard::IfLet(rp, re)) => self.eq_pat(lp, rp) && self.eq_expr(le, re), + _ => false, } } @@ -643,7 +645,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_guard(&mut self, g: &Guard<'_>) { match g { - Guard::If(ref expr) => { + Guard::If(ref expr) | Guard::IfLet(_, ref expr) => { self.hash_expr(expr); }, } diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 8f0ef9150d45..0c93a12b9219 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -560,5 +560,10 @@ fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) { println!("{}If", ind); print_expr(cx, expr, indent + 1); }, + hir::Guard::IfLet(pat, expr) => { + println!("{}IfLet", ind); + print_pat(cx, pat, indent + 1); + print_expr(cx, expr, indent + 1); + }, } } From 93c6135c153cdb67a7c39c671d85a76576a081b6 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 15 Nov 2020 22:51:02 +0100 Subject: [PATCH 104/719] Handle `Guard::IfLet` in clippy --- clippy_lints/src/shadow.rs | 4 ++++ clippy_lints/src/utils/author.rs | 12 ++++++++++++ clippy_lints/src/utils/hir_utils.rs | 4 +++- clippy_lints/src/utils/inspector.rs | 5 +++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 225fe58906f7..f83965926782 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -342,6 +342,10 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut if let Some(ref guard) = arm.guard { match guard { Guard::If(if_expr) => check_expr(cx, if_expr, bindings), + Guard::IfLet(guard_pat, guard_expr) => { + check_pat(cx, guard_pat, Some(*guard_expr), guard_pat.span, bindings); + check_expr(cx, guard_expr, bindings); + }, } } check_expr(cx, &arm.body, bindings); diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 135f289a2b3f..4249dbb4e651 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -372,6 +372,18 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = if_expr_pat; self.visit_expr(if_expr); }, + hir::Guard::IfLet(ref if_let_pat, ref if_let_expr) => { + let if_let_pat_pat = self.next("pat"); + let if_let_expr_pat = self.next("expr"); + println!( + " if let Guard::IfLet(ref {}, ref {}) = {};", + if_let_pat_pat, if_let_expr_pat, guard_pat + ); + self.current = if_let_expr_pat; + self.visit_expr(if_let_expr); + self.current = if_let_pat_pat; + self.visit_pat(if_let_pat); + }, } } self.current = format!("{}[{}].pat", arms_pat, i); diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index e4ad105c3513..b0099b4a7925 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -169,6 +169,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool { match (left, right) { (Guard::If(l), Guard::If(r)) => self.eq_expr(l, r), + (Guard::IfLet(lp, le), Guard::IfLet(rp, re)) => self.eq_pat(lp, rp) && self.eq_expr(le, re), + _ => false, } } @@ -643,7 +645,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_guard(&mut self, g: &Guard<'_>) { match g { - Guard::If(ref expr) => { + Guard::If(ref expr) | Guard::IfLet(_, ref expr) => { self.hash_expr(expr); }, } diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 8f0ef9150d45..0c93a12b9219 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -560,5 +560,10 @@ fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) { println!("{}If", ind); print_expr(cx, expr, indent + 1); }, + hir::Guard::IfLet(pat, expr) => { + println!("{}IfLet", ind); + print_pat(cx, pat, indent + 1); + print_expr(cx, expr, indent + 1); + }, } } From 09172603685ba72f1cae4f69b6fff63f2dfcd27f Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 15 Nov 2020 23:42:48 +0100 Subject: [PATCH 105/719] Add a few basic tests for if-let guards --- .../ui/generator/yielding-in-match-guards.rs | 11 +++ src/test/ui/rfc-2294-if-let-guard/bindings.rs | 10 +++ .../ui/rfc-2294-if-let-guard/bindings.stderr | 15 ++++ .../rfc-2294-if-let-guard/feature-gate.stderr | 70 +++++++++---------- src/test/ui/rfc-2294-if-let-guard/run-pass.rs | 34 +++++++++ src/test/ui/rfc-2294-if-let-guard/typeck.rs | 16 +++++ .../ui/rfc-2294-if-let-guard/typeck.stderr | 21 ++++++ src/test/ui/rfc-2294-if-let-guard/warns.rs | 22 ++++++ .../ui/rfc-2294-if-let-guard/warns.stderr | 26 +++++++ 9 files changed, 190 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/rfc-2294-if-let-guard/bindings.rs create mode 100644 src/test/ui/rfc-2294-if-let-guard/bindings.stderr create mode 100644 src/test/ui/rfc-2294-if-let-guard/run-pass.rs create mode 100644 src/test/ui/rfc-2294-if-let-guard/typeck.rs create mode 100644 src/test/ui/rfc-2294-if-let-guard/typeck.stderr create mode 100644 src/test/ui/rfc-2294-if-let-guard/warns.rs create mode 100644 src/test/ui/rfc-2294-if-let-guard/warns.stderr diff --git a/src/test/ui/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs index c76726414df8..5c10a7c78118 100644 --- a/src/test/ui/generator/yielding-in-match-guards.rs +++ b/src/test/ui/generator/yielding-in-match-guards.rs @@ -10,6 +10,9 @@ // Thus, `&'_ u8` should be included in type signature // of the underlying generator. +#![feature(if_let_guard)] +#![allow(incomplete_features)] + async fn f() -> u8 { 1 } async fn foo() -> [bool; 10] { [false; 10] } @@ -36,8 +39,16 @@ async fn i(x: u8) { } } +async fn j(x: u8) { + match x { + y if let (1, 42) = (f().await, y) => (), + _ => (), + } +} + fn main() { let _ = g(10); let _ = h(9); let _ = i(8); + let _ = j(7); } diff --git a/src/test/ui/rfc-2294-if-let-guard/bindings.rs b/src/test/ui/rfc-2294-if-let-guard/bindings.rs new file mode 100644 index 000000000000..4e2d70e3290e --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/bindings.rs @@ -0,0 +1,10 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +fn main() { + match Some(None) { + Some(x) if let Some(y) = x => (x, y), + _ => y, //~ ERROR cannot find value `y` + } + y //~ ERROR cannot find value `y` +} diff --git a/src/test/ui/rfc-2294-if-let-guard/bindings.stderr b/src/test/ui/rfc-2294-if-let-guard/bindings.stderr new file mode 100644 index 000000000000..9c5d92a33ada --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/bindings.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:7:14 + | +LL | _ => y, + | ^ not found in this scope + +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:9:5 + | +LL | y + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr index d43096336c5b..1670078e0d38 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `let` - --> $DIR/feature-gate.rs:81:15 + --> $DIR/feature-gate.rs:80:15 | LL | macro_rules! use_expr { | --------------------- when calling this macro @@ -17,7 +17,7 @@ LL | () if let 0 = 1 => {} = help: add `#![feature(if_let_guard)]` to the crate attributes to enable error[E0658]: `if let` guard is not implemented - --> $DIR/feature-gate.rs:77:12 + --> $DIR/feature-gate.rs:76:12 | LL | () if let 0 = 1 => {} | ^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | () if let 0 = 1 => {} = help: add `#![feature(if_let_guard)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:11:16 + --> $DIR/feature-gate.rs:10:16 | LL | () if (let 0 = 1) => {} | ^^^^^^^^^ @@ -35,7 +35,7 @@ LL | () if (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:15:18 + --> $DIR/feature-gate.rs:14:18 | LL | () if (((let 0 = 1))) => {} | ^^^^^^^^^ @@ -44,7 +44,7 @@ LL | () if (((let 0 = 1))) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:19:23 + --> $DIR/feature-gate.rs:18:23 | LL | () if true && let 0 = 1 => {} | ^^^^^^^^^ @@ -53,7 +53,7 @@ LL | () if true && let 0 = 1 => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:23:15 + --> $DIR/feature-gate.rs:22:15 | LL | () if let 0 = 1 && true => {} | ^^^^^^^^^ @@ -62,7 +62,7 @@ LL | () if let 0 = 1 && true => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:27:16 + --> $DIR/feature-gate.rs:26:16 | LL | () if (let 0 = 1) && true => {} | ^^^^^^^^^ @@ -71,7 +71,7 @@ LL | () if (let 0 = 1) && true => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:31:24 + --> $DIR/feature-gate.rs:30:24 | LL | () if true && (let 0 = 1) => {} | ^^^^^^^^^ @@ -80,7 +80,7 @@ LL | () if true && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:35:16 + --> $DIR/feature-gate.rs:34:16 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:35:31 + --> $DIR/feature-gate.rs:34:31 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -98,7 +98,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:15 + --> $DIR/feature-gate.rs:40:15 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -107,7 +107,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:28 + --> $DIR/feature-gate.rs:40:28 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -116,7 +116,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:42 + --> $DIR/feature-gate.rs:40:42 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -125,7 +125,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:55 + --> $DIR/feature-gate.rs:40:55 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -134,7 +134,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:68 + --> $DIR/feature-gate.rs:40:68 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -143,7 +143,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:53:15 + --> $DIR/feature-gate.rs:52:15 | LL | () if let Range { start: _, end: _ } = (true..true) && false => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -152,7 +152,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:69:16 + --> $DIR/feature-gate.rs:68:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^ @@ -161,7 +161,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:72:16 + --> $DIR/feature-gate.rs:71:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ @@ -170,7 +170,7 @@ LL | use_expr!((let 0 = 1)); = help: add `#![feature(let_chains)]` to the crate attributes to enable error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:11:16 + --> $DIR/feature-gate.rs:10:16 | LL | () if (let 0 = 1) => {} | ^^^^^^^^^ @@ -179,7 +179,7 @@ LL | () if (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:15:18 + --> $DIR/feature-gate.rs:14:18 | LL | () if (((let 0 = 1))) => {} | ^^^^^^^^^ @@ -188,7 +188,7 @@ LL | () if (((let 0 = 1))) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:19:23 + --> $DIR/feature-gate.rs:18:23 | LL | () if true && let 0 = 1 => {} | ^^^^^^^^^ @@ -197,7 +197,7 @@ LL | () if true && let 0 = 1 => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:23:15 + --> $DIR/feature-gate.rs:22:15 | LL | () if let 0 = 1 && true => {} | ^^^^^^^^^ @@ -206,7 +206,7 @@ LL | () if let 0 = 1 && true => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:27:16 + --> $DIR/feature-gate.rs:26:16 | LL | () if (let 0 = 1) && true => {} | ^^^^^^^^^ @@ -215,7 +215,7 @@ LL | () if (let 0 = 1) && true => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:31:24 + --> $DIR/feature-gate.rs:30:24 | LL | () if true && (let 0 = 1) => {} | ^^^^^^^^^ @@ -224,7 +224,7 @@ LL | () if true && (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:35:16 + --> $DIR/feature-gate.rs:34:16 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -233,7 +233,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:35:31 + --> $DIR/feature-gate.rs:34:31 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -242,7 +242,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:15 + --> $DIR/feature-gate.rs:40:15 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -251,7 +251,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:28 + --> $DIR/feature-gate.rs:40:28 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -260,7 +260,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:42 + --> $DIR/feature-gate.rs:40:42 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -269,7 +269,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:55 + --> $DIR/feature-gate.rs:40:55 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -278,7 +278,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:68 + --> $DIR/feature-gate.rs:40:68 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -287,7 +287,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:53:15 + --> $DIR/feature-gate.rs:52:15 | LL | () if let Range { start: _, end: _ } = (true..true) && false => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +296,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:69:16 + --> $DIR/feature-gate.rs:68:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^ @@ -305,7 +305,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:72:16 + --> $DIR/feature-gate.rs:71:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ @@ -313,6 +313,6 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if`- and `while`-expressions = note: as well as when nested within `&&` and parenthesis in those conditions -error: aborting due to 36 previous errors +error: aborting due to 35 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2294-if-let-guard/run-pass.rs b/src/test/ui/rfc-2294-if-let-guard/run-pass.rs new file mode 100644 index 000000000000..a3663003790f --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/run-pass.rs @@ -0,0 +1,34 @@ +// run-pass + +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +enum Foo { + Bar, + Baz, + Qux(u8), +} + +fn bar(x: bool) -> Foo { + if x { Foo::Baz } else { Foo::Bar } +} + +fn baz(x: u8) -> Foo { + if x % 2 == 0 { Foo::Bar } else { Foo::Baz } +} + +fn qux(x: u8) -> Foo { + Foo::Qux(x.rotate_left(1)) +} + +fn main() { + match Some((true, 3)) { + Some((x, _)) if let Foo::Bar = bar(x) => panic!(), + Some((_, x)) if let Foo::Baz = baz(x) => {}, + _ => panic!(), + } + match Some(42) { + Some(x) if let Foo::Qux(y) = qux(x) => assert_eq!(y, 84), + _ => panic!(), + } +} diff --git a/src/test/ui/rfc-2294-if-let-guard/typeck.rs b/src/test/ui/rfc-2294-if-let-guard/typeck.rs new file mode 100644 index 000000000000..a4fc7f8cf2b2 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/typeck.rs @@ -0,0 +1,16 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +fn ok() -> Result, ()> { + Ok(Some(true)) +} + +fn main() { + match ok() { + Ok(x) if let Err(_) = x => {}, + //~^ ERROR mismatched types + Ok(x) if let 0 = x => {}, + //~^ ERROR mismatched types + _ => {} + } +} diff --git a/src/test/ui/rfc-2294-if-let-guard/typeck.stderr b/src/test/ui/rfc-2294-if-let-guard/typeck.stderr new file mode 100644 index 000000000000..7ce93fe7348f --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/typeck.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/typeck.rs:10:22 + | +LL | Ok(x) if let Err(_) = x => {}, + | ^^^^^^ expected enum `Option`, found enum `std::result::Result` + | + = note: expected enum `Option` + found enum `std::result::Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/typeck.rs:12:22 + | +LL | Ok(x) if let 0 = x => {}, + | ^ expected enum `Option`, found integer + | + = note: expected enum `Option` + found type `{integer}` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.rs b/src/test/ui/rfc-2294-if-let-guard/warns.rs new file mode 100644 index 000000000000..9691a12f45b0 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/warns.rs @@ -0,0 +1,22 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +#[deny(irrefutable_let_patterns)] +fn irrefutable_let_guard() { + match Some(()) { + Some(x) if let () = x => {} + //~^ ERROR irrefutable if-let guard + _ => {} + } +} + +#[deny(unreachable_patterns)] +fn unreachable_pattern() { + match Some(()) { + x if let None | None = x => {} + //~^ ERROR unreachable pattern + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.stderr b/src/test/ui/rfc-2294-if-let-guard/warns.stderr new file mode 100644 index 000000000000..45720f9fbc55 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/warns.stderr @@ -0,0 +1,26 @@ +error: irrefutable if-let guard + --> $DIR/warns.rs:7:24 + | +LL | Some(x) if let () = x => {} + | ^^ + | +note: the lint level is defined here + --> $DIR/warns.rs:4:8 + | +LL | #[deny(irrefutable_let_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/warns.rs:16:25 + | +LL | x if let None | None = x => {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/warns.rs:13:8 + | +LL | #[deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 8eca423ea13bb0612df4b8f2c20c5228f54d0c2d Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 6 Dec 2020 15:01:03 +0100 Subject: [PATCH 106/719] Merge commit 'c1664c50b27a51f7a78c93ba65558e7c33eabee6' into clippyup --- .github/workflows/clippy_bors.yml | 12 +- CHANGELOG.md | 3 + CONTRIBUTING.md | 9 +- Cargo.toml | 5 +- README.md | 29 +- clippy_dev/src/lib.rs | 32 +- clippy_dev/src/update_lints.rs | 2 +- clippy_lints/Cargo.toml | 3 + clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/collapsible_match.rs | 172 +++++ clippy_lints/src/comparison_chain.rs | 3 +- clippy_lints/src/default.rs | 3 +- clippy_lints/src/deprecated_lints.rs | 20 - clippy_lints/src/eq_op.rs | 27 +- clippy_lints/src/if_let_some_result.rs | 3 +- clippy_lints/src/implicit_return.rs | 3 +- clippy_lints/src/implicit_saturating_sub.rs | 3 +- clippy_lints/src/items_after_statements.rs | 4 +- clippy_lints/src/large_const_arrays.rs | 3 +- clippy_lints/src/large_stack_arrays.rs | 3 +- clippy_lints/src/let_if_seq.rs | 53 +- clippy_lints/src/lib.rs | 113 +-- clippy_lints/src/literal_representation.rs | 37 +- clippy_lints/src/loops.rs | 69 +- clippy_lints/src/manual_non_exhaustive.rs | 27 +- clippy_lints/src/manual_strip.rs | 31 +- clippy_lints/src/map_err_ignore.rs | 6 +- clippy_lints/src/matches.rs | 115 ++- .../methods/manual_saturating_arithmetic.rs | 3 +- clippy_lints/src/methods/mod.rs | 76 +- clippy_lints/src/misc.rs | 144 ++-- clippy_lints/src/needless_bool.rs | 11 +- clippy_lints/src/panic_unimplemented.rs | 9 +- clippy_lints/src/question_mark.rs | 3 +- clippy_lints/src/redundant_closure_call.rs | 4 +- clippy_lints/src/size_of_in_element_count.rs | 145 ++++ clippy_lints/src/strings.rs | 103 ++- .../src/suspicious_operation_groupings.rs | 693 ++++++++++++++++++ clippy_lints/src/trait_bounds.rs | 3 +- clippy_lints/src/transmuting_null.rs | 3 +- clippy_lints/src/types.rs | 18 +- clippy_lints/src/unnecessary_wraps.rs | 5 +- clippy_lints/src/utils/ast_utils.rs | 11 + .../src/utils/ast_utils/ident_iter.rs | 45 ++ clippy_lints/src/utils/attrs.rs | 19 + clippy_lints/src/utils/conf.rs | 4 + clippy_lints/src/utils/diagnostics.rs | 4 +- clippy_lints/src/utils/higher.rs | 3 +- clippy_lints/src/utils/hir_utils.rs | 28 +- clippy_lints/src/utils/mod.rs | 76 ++ clippy_lints/src/utils/paths.rs | 18 + clippy_lints/src/utils/visitors.rs | 55 +- tests/compile-test.rs | 15 +- tests/dogfood.rs | 16 +- .../collapsible_span_lint_calls.fixed | 0 .../collapsible_span_lint_calls.rs | 0 .../collapsible_span_lint_calls.stderr | 0 .../{ui => ui-internal}/custom_ice_message.rs | 0 .../custom_ice_message.stderr | 0 tests/{ui => ui-internal}/default_lint.rs | 0 tests/{ui => ui-internal}/default_lint.stderr | 0 tests/{ui => ui-internal}/invalid_paths.rs | 0 .../{ui => ui-internal}/invalid_paths.stderr | 0 .../lint_without_lint_pass.rs | 0 .../lint_without_lint_pass.stderr | 0 .../match_type_on_diag_item.rs | 0 .../match_type_on_diag_item.stderr | 0 .../{ui => ui-internal}/outer_expn_data.fixed | 0 tests/{ui => ui-internal}/outer_expn_data.rs | 0 .../outer_expn_data.stderr | 0 .../invalid_min_rust_version/clippy.toml | 1 + .../invalid_min_rust_version.rs | 3 + .../invalid_min_rust_version.stderr | 4 + .../lint_decimal_readability/clippy.toml | 1 + .../ui-toml/lint_decimal_readability/test.rs | 22 + .../lint_decimal_readability/test.stderr | 10 + tests/ui-toml/min_rust_version/clippy.toml | 1 + .../min_rust_version/min_rust_version.rs | 68 ++ .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/as_conversions.rs | 14 +- tests/ui/as_conversions.stderr | 6 +- tests/ui/auxiliary/macro_rules.rs | 14 + tests/ui/collapsible_match.rs | 239 ++++++ tests/ui/collapsible_match.stderr | 179 +++++ tests/ui/collapsible_match2.rs | 53 ++ tests/ui/collapsible_match2.stderr | 61 ++ tests/ui/deprecated.rs | 2 - tests/ui/deprecated.stderr | 46 +- tests/ui/deprecated_old.rs | 2 - tests/ui/deprecated_old.stderr | 30 +- tests/ui/eq_op.rs | 9 + tests/ui/eq_op.stderr | 10 +- tests/ui/item_after_statement.rs | 13 + tests/ui/map_err.rs | 4 + tests/ui/map_err.stderr | 4 +- tests/ui/min_rust_version_attr.rs | 87 +++ tests/ui/min_rust_version_attr.stderr | 37 + tests/ui/min_rust_version_invalid_attr.rs | 4 + tests/ui/min_rust_version_invalid_attr.stderr | 8 + .../min_rust_version_multiple_inner_attr.rs | 11 + ...in_rust_version_multiple_inner_attr.stderr | 38 + tests/ui/min_rust_version_no_patch.rs | 14 + tests/ui/min_rust_version_outer_attr.rs | 4 + tests/ui/min_rust_version_outer_attr.stderr | 8 + tests/ui/modulo_one.rs | 11 +- tests/ui/modulo_one.stderr | 54 +- tests/ui/needless_collect_indirect.rs | 20 + tests/ui/panicking_macros.stderr | 8 +- .../redundant_pattern_matching_ipaddr.fixed | 73 ++ tests/ui/redundant_pattern_matching_ipaddr.rs | 91 +++ .../redundant_pattern_matching_ipaddr.stderr | 130 ++++ .../redundant_pattern_matching_option.fixed | 13 +- tests/ui/redundant_pattern_matching_option.rs | 13 +- .../redundant_pattern_matching_option.stderr | 40 +- .../ui/redundant_pattern_matching_poll.fixed | 70 ++ tests/ui/redundant_pattern_matching_poll.rs | 85 +++ .../ui/redundant_pattern_matching_poll.stderr | 128 ++++ ...> redundant_pattern_matching_result.fixed} | 1 - ...s => redundant_pattern_matching_result.rs} | 1 - ... redundant_pattern_matching_result.stderr} | 44 +- tests/ui/size_of_in_element_count.rs | 61 ++ tests/ui/size_of_in_element_count.stderr | 195 +++++ tests/ui/str_to_string.rs | 7 + tests/ui/str_to_string.stderr | 19 + tests/ui/string_to_string.rs | 7 + tests/ui/string_to_string.stderr | 11 + tests/ui/suspicious_operation_groupings.rs | 207 ++++++ .../ui/suspicious_operation_groupings.stderr | 166 +++++ tests/ui/unnecessary_cast.rs | 3 + tests/ui/unnecessary_cast_fixable.fixed | 2 + tests/ui/unnecessary_cast_fixable.rs | 2 + tests/ui/unnecessary_cast_fixable.stderr | 32 +- tests/ui/unnecessary_wraps.rs | 7 + tests/ui/unreadable_literal.fixed | 18 +- tests/ui/unreadable_literal.rs | 18 +- tests/ui/unreadable_literal.stderr | 42 +- tests/ui/wildcard_enum_match_arm.fixed | 3 +- tests/ui/wildcard_enum_match_arm.rs | 3 +- tests/ui/wildcard_enum_match_arm.stderr | 10 +- 139 files changed, 4334 insertions(+), 576 deletions(-) create mode 100644 clippy_lints/src/collapsible_match.rs create mode 100644 clippy_lints/src/size_of_in_element_count.rs create mode 100644 clippy_lints/src/suspicious_operation_groupings.rs create mode 100644 clippy_lints/src/utils/ast_utils/ident_iter.rs rename tests/{ui => ui-internal}/collapsible_span_lint_calls.fixed (100%) rename tests/{ui => ui-internal}/collapsible_span_lint_calls.rs (100%) rename tests/{ui => ui-internal}/collapsible_span_lint_calls.stderr (100%) rename tests/{ui => ui-internal}/custom_ice_message.rs (100%) rename tests/{ui => ui-internal}/custom_ice_message.stderr (100%) rename tests/{ui => ui-internal}/default_lint.rs (100%) rename tests/{ui => ui-internal}/default_lint.stderr (100%) rename tests/{ui => ui-internal}/invalid_paths.rs (100%) rename tests/{ui => ui-internal}/invalid_paths.stderr (100%) rename tests/{ui => ui-internal}/lint_without_lint_pass.rs (100%) rename tests/{ui => ui-internal}/lint_without_lint_pass.stderr (100%) rename tests/{ui => ui-internal}/match_type_on_diag_item.rs (100%) rename tests/{ui => ui-internal}/match_type_on_diag_item.stderr (100%) rename tests/{ui => ui-internal}/outer_expn_data.fixed (100%) rename tests/{ui => ui-internal}/outer_expn_data.rs (100%) rename tests/{ui => ui-internal}/outer_expn_data.stderr (100%) create mode 100644 tests/ui-toml/invalid_min_rust_version/clippy.toml create mode 100644 tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs create mode 100644 tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr create mode 100644 tests/ui-toml/lint_decimal_readability/clippy.toml create mode 100644 tests/ui-toml/lint_decimal_readability/test.rs create mode 100644 tests/ui-toml/lint_decimal_readability/test.stderr create mode 100644 tests/ui-toml/min_rust_version/clippy.toml create mode 100644 tests/ui-toml/min_rust_version/min_rust_version.rs create mode 100644 tests/ui/collapsible_match.rs create mode 100644 tests/ui/collapsible_match.stderr create mode 100644 tests/ui/collapsible_match2.rs create mode 100644 tests/ui/collapsible_match2.stderr create mode 100644 tests/ui/min_rust_version_attr.rs create mode 100644 tests/ui/min_rust_version_attr.stderr create mode 100644 tests/ui/min_rust_version_invalid_attr.rs create mode 100644 tests/ui/min_rust_version_invalid_attr.stderr create mode 100644 tests/ui/min_rust_version_multiple_inner_attr.rs create mode 100644 tests/ui/min_rust_version_multiple_inner_attr.stderr create mode 100644 tests/ui/min_rust_version_no_patch.rs create mode 100644 tests/ui/min_rust_version_outer_attr.rs create mode 100644 tests/ui/min_rust_version_outer_attr.stderr create mode 100644 tests/ui/redundant_pattern_matching_ipaddr.fixed create mode 100644 tests/ui/redundant_pattern_matching_ipaddr.rs create mode 100644 tests/ui/redundant_pattern_matching_ipaddr.stderr create mode 100644 tests/ui/redundant_pattern_matching_poll.fixed create mode 100644 tests/ui/redundant_pattern_matching_poll.rs create mode 100644 tests/ui/redundant_pattern_matching_poll.stderr rename tests/ui/{redundant_pattern_matching.fixed => redundant_pattern_matching_result.fixed} (98%) rename tests/ui/{redundant_pattern_matching.rs => redundant_pattern_matching_result.rs} (99%) rename tests/ui/{redundant_pattern_matching.stderr => redundant_pattern_matching_result.stderr} (80%) create mode 100644 tests/ui/size_of_in_element_count.rs create mode 100644 tests/ui/size_of_in_element_count.stderr create mode 100644 tests/ui/str_to_string.rs create mode 100644 tests/ui/str_to_string.stderr create mode 100644 tests/ui/string_to_string.rs create mode 100644 tests/ui/string_to_string.stderr create mode 100644 tests/ui/suspicious_operation_groupings.rs create mode 100644 tests/ui/suspicious_operation_groupings.stderr diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 7509d90c6c2f..784463fe0df9 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -128,14 +128,14 @@ jobs: SYSROOT=$(rustc --print sysroot) echo "$SYSROOT/bin" >> $GITHUB_PATH - - name: Build - run: cargo build --features deny-warnings + - name: Build with internal lints + run: cargo build --features deny-warnings,internal-lints - - name: Test - run: cargo test --features deny-warnings + - name: Test with internal lints + run: cargo test --features deny-warnings,internal-lints - - name: Test clippy_lints - run: cargo test --features deny-warnings + - name: Test clippy_lints with internal lints + run: cargo test --features deny-warnings,internal-lints working-directory: clippy_lints - name: Test rustc_tools_util diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e4b0e67040..c7e02aaf4e18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1770,6 +1770,7 @@ Released 2018-09-13 [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned [`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if +[`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator @@ -2056,6 +2057,7 @@ Released 2018-09-13 [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else +[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive @@ -2073,6 +2075,7 @@ Released 2018-09-13 [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl +[`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a8e2123656e9..f8c26e2d456d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,11 +14,16 @@ All contributors are expected to follow the [Rust Code of Conduct]. - [Contributing to Clippy](#contributing-to-clippy) - [Getting started](#getting-started) + - [High level approach](#high-level-approach) - [Finding something to fix/improve](#finding-something-to-fiximprove) - [Writing code](#writing-code) - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work) - [How Clippy works](#how-clippy-works) - [Fixing build failures caused by Rust](#fixing-build-failures-caused-by-rust) + - [Patching git-subtree to work with big repos](#patching-git-subtree-to-work-with-big-repos) + - [Performing the sync](#performing-the-sync) + - [Syncing back changes in Clippy to [`rust-lang/rust`]](#syncing-back-changes-in-clippy-to-rust-langrust) + - [Defining remotes](#defining-remotes) - [Issue and PR triage](#issue-and-pr-triage) - [Bors and Homu](#bors-and-homu) - [Contributions](#contributions) @@ -320,8 +325,8 @@ commands [here][homu_instructions]. [l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash [l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug [homu]: https://github.com/rust-lang/homu -[homu_instructions]: https://buildbot2.rust-lang.org/homu/ -[homu_queue]: https://buildbot2.rust-lang.org/homu/queue/clippy +[homu_instructions]: https://bors.rust-lang.org/ +[homu_queue]: https://bors.rust-lang.org/queue/clippy ## Contributions diff --git a/Cargo.toml b/Cargo.toml index 1ddcd18598de..a765390c6032 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ path = "src/driver.rs" clippy_lints = { version = "0.0.212", path = "clippy_lints" } # end automatic update semver = "0.11" -rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"} +rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" } tempfile = { version = "3.1.0", optional = true } [dev-dependencies] @@ -49,8 +49,9 @@ derive-new = "0.5" rustc-workspace-hack = "1.0.0" [build-dependencies] -rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"} +rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" } [features] deny-warnings = [] integration = ["tempfile"] +internal-lints = ["clippy_lints/internal-lints"] diff --git a/README.md b/README.md index 1da626b505df..fddf0614a0b8 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ cargo clippy -- -W clippy::lint_name ``` This also works with lint groups. For example you -can run Clippy with warnings for all lints enabled: +can run Clippy with warnings for all lints enabled: ```terminal cargo clippy -- -W clippy::pedantic ``` @@ -194,6 +194,33 @@ cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... ``` Note that if you've run clippy before, this may only take effect after you've modified a file or ran `cargo clean`. +### Specifying the minimum supported Rust version + +Projects that intend to support old versions of Rust can disable lints pertaining to newer features by +specifying the minimum supported Rust version (MSRV) in the clippy configuration file. + +```toml +msrv = "1.30.0" +``` + +The MSRV can also be specified as an inner attribute, like below. + +```rust +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.30.0"] + +fn main() { + ... +} +``` + +You can also omit the patch version when specifying the MSRV, so `msrv = 1.30` +is equivalent to `msrv = 1.30.0`. + +Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. + +Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv) + ## Contributing If you want to contribute to Clippy, you can find more information in [CONTRIBUTING.md](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md). diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 43cb2954b74b..f51c45e9eb59 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -146,16 +146,30 @@ pub fn gen_deprecated<'a>(lints: impl Iterator) -> Vec } #[must_use] -pub fn gen_register_lint_list<'a>(lints: impl Iterator) -> Vec { - let pre = " store.register_lints(&[".to_string(); - let post = " ]);".to_string(); - let mut inner = lints +pub fn gen_register_lint_list<'a>( + internal_lints: impl Iterator, + usable_lints: impl Iterator, +) -> Vec { + let header = " store.register_lints(&[".to_string(); + let footer = " ]);".to_string(); + let internal_lints = internal_lints + .sorted_by_key(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) + .map(|l| { + format!( + " #[cfg(feature = \"internal-lints\")]\n &{}::{},", + l.module, + l.name.to_uppercase() + ) + }); + let other_lints = usable_lints + .sorted_by_key(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) .map(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) - .sorted() - .collect::>(); - inner.insert(0, pre); - inner.push(post); - inner + .sorted(); + let mut lint_list = vec![header]; + lint_list.extend(internal_lints); + lint_list.extend(other_lints); + lint_list.push(footer); + lint_list } /// Gathers all files in `src/clippy_lints` and gathers all lints inside diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index fcf093f8835d..edf6c5f57a49 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -68,7 +68,7 @@ pub fn run(update_mode: UpdateMode) { "end register lints", false, update_mode == UpdateMode::Change, - || gen_register_lint_list(usable_lints.iter().chain(internal_lints.iter())), + || gen_register_lint_list(internal_lints.iter(), usable_lints.iter()), ) .changed; diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index d9471d251974..7697eba650ac 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -28,6 +28,7 @@ smallvec = { version = "1", features = ["union"] } toml = "0.5.3" unicode-normalization = "0.1" semver = "0.11" +rustc-semver="1.1.0" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } @@ -36,3 +37,5 @@ syn = { version = "1", features = ["full"] } [features] deny-warnings = [] +# build clippy with internal lints enabled, off by default +internal-lints = [] diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 15505fd79f4a..3edbe723922f 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -5,7 +5,6 @@ use crate::utils::{ span_lint_and_sugg, span_lint_and_then, without_block_comments, }; use if_chain::if_chain; -use rustc_span::lev_distance::find_best_match_for_name; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; use rustc_hir::{ @@ -15,6 +14,7 @@ use rustc_lint::{CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::Span; use rustc_span::sym; use rustc_span::symbol::{Symbol, SymbolStr}; diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs new file mode 100644 index 000000000000..a34ba2d00a8c --- /dev/null +++ b/clippy_lints/src/collapsible_match.rs @@ -0,0 +1,172 @@ +use crate::utils::visitors::LocalUsedVisitor; +use crate::utils::{span_lint_and_then, SpanlessEq}; +use if_chain::if_chain; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{DefIdTree, TyCtxt}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{MultiSpan, Span}; + +declare_clippy_lint! { + /// **What it does:** Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together + /// without adding any branches. + /// + /// Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only + /// cases where merging would most likely make the code more readable. + /// + /// **Why is this bad?** It is unnecessarily verbose and complex. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// fn func(opt: Option>) { + /// let n = match opt { + /// Some(n) => match n { + /// Ok(n) => n, + /// _ => return, + /// } + /// None => return, + /// }; + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn func(opt: Option>) { + /// let n = match opt { + /// Some(Ok(n)) => n, + /// _ => return, + /// }; + /// } + /// ``` + pub COLLAPSIBLE_MATCH, + style, + "Nested `match` or `if let` expressions where the patterns may be \"collapsed\" together." +} + +declare_lint_pass!(CollapsibleMatch => [COLLAPSIBLE_MATCH]); + +impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::Match(_expr, arms, _source) = expr.kind { + if let Some(wild_arm) = arms.iter().rfind(|arm| arm_is_wild_like(arm, cx.tcx)) { + for arm in arms { + check_arm(arm, wild_arm, cx); + } + } + } + } +} + +fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) { + if_chain! { + let expr = strip_singleton_blocks(arm.body); + if let ExprKind::Match(expr_in, arms_inner, _) = expr.kind; + // the outer arm pattern and the inner match + if expr_in.span.ctxt() == arm.pat.span.ctxt(); + // there must be no more than two arms in the inner match for this lint + if arms_inner.len() == 2; + // no if guards on the inner match + if arms_inner.iter().all(|arm| arm.guard.is_none()); + // match expression must be a local binding + // match { .. } + if let ExprKind::Path(QPath::Resolved(None, path)) = expr_in.kind; + if let Res::Local(binding_id) = path.res; + // one of the branches must be "wild-like" + if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(arm_inner, cx.tcx)); + let (wild_inner_arm, non_wild_inner_arm) = + (&arms_inner[wild_inner_arm_idx], &arms_inner[1 - wild_inner_arm_idx]); + if !pat_contains_or(non_wild_inner_arm.pat); + // the binding must come from the pattern of the containing match arm + // .... => match { .. } + if let Some(binding_span) = find_pat_binding(arm.pat, binding_id); + // the "wild-like" branches must be equal + if SpanlessEq::new(cx).eq_expr(wild_inner_arm.body, wild_outer_arm.body); + // the binding must not be used in the if guard + if !matches!(arm.guard, Some(Guard::If(guard)) if LocalUsedVisitor::new(binding_id).check_expr(guard)); + // ...or anywhere in the inner match + if !arms_inner.iter().any(|arm| LocalUsedVisitor::new(binding_id).check_arm(arm)); + then { + span_lint_and_then( + cx, + COLLAPSIBLE_MATCH, + expr.span, + "Unnecessary nested match", + |diag| { + let mut help_span = MultiSpan::from_spans(vec![binding_span, non_wild_inner_arm.pat.span]); + help_span.push_span_label(binding_span, "Replace this binding".into()); + help_span.push_span_label(non_wild_inner_arm.pat.span, "with this pattern".into()); + diag.span_help(help_span, "The outer pattern can be modified to include the inner pattern."); + }, + ); + } + } +} + +fn strip_singleton_blocks<'hir>(mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { + while let ExprKind::Block(block, _) = expr.kind { + match (block.stmts, block.expr) { + ([stmt], None) => match stmt.kind { + StmtKind::Expr(e) | StmtKind::Semi(e) => expr = e, + _ => break, + }, + ([], Some(e)) => expr = e, + _ => break, + } + } + expr +} + +/// A "wild-like" pattern is wild ("_") or `None`. +/// For this lint to apply, both the outer and inner match expressions +/// must have "wild-like" branches that can be combined. +fn arm_is_wild_like(arm: &Arm<'_>, tcx: TyCtxt<'_>) -> bool { + if arm.guard.is_some() { + return false; + } + match arm.pat.kind { + PatKind::Binding(..) | PatKind::Wild => true, + PatKind::Path(QPath::Resolved(None, path)) if is_none_ctor(path.res, tcx) => true, + _ => false, + } +} + +fn find_pat_binding(pat: &Pat<'_>, hir_id: HirId) -> Option { + let mut span = None; + pat.walk_short(|p| match &p.kind { + // ignore OR patterns + PatKind::Or(_) => false, + PatKind::Binding(_bm, _, _ident, _) => { + let found = p.hir_id == hir_id; + if found { + span = Some(p.span); + } + !found + }, + _ => true, + }); + span +} + +fn pat_contains_or(pat: &Pat<'_>) -> bool { + let mut result = false; + pat.walk(|p| { + let is_or = matches!(p.kind, PatKind::Or(_)); + result |= is_or; + !is_or + }); + result +} + +fn is_none_ctor(res: Res, tcx: TyCtxt<'_>) -> bool { + if let Some(none_id) = tcx.lang_items().option_none_variant() { + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = res { + if let Some(variant_id) = tcx.parent(id) { + return variant_id == none_id; + } + } + } + false +} diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 99f161a0510f..ae1143b2c50c 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -12,7 +12,8 @@ declare_clippy_lint! { /// **Why is this bad?** `if` is not guaranteed to be exhaustive and conditionals can get /// repetitive /// - /// **Known problems:** None. + /// **Known problems:** The match statement may be slower due to the compiler + /// not inlining the call to cmp. See issue #5354 /// /// **Example:** /// ```rust,ignore diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 612c5355338a..f69f6f1412af 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -280,8 +280,7 @@ fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Op // only take assignments to fields where the left-hand side field is a field of // the same binding as the previous statement if let ExprKind::Field(ref binding, field_ident) = assign_lhs.kind; - if let ExprKind::Path(ref qpath) = binding.kind; - if let QPath::Resolved(_, path) = qpath; + if let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind; if let Some(second_binding_name) = path.segments.last(); if second_binding_name.ident.name == binding_name; then { diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 1c3285ed701d..bec0c9f93a0d 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -51,26 +51,6 @@ declare_deprecated_lint! { "`Vec::as_mut_slice` has been stabilized in 1.7" } -declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. - /// - /// **Deprecation reason:** This used to check for `.to_string()` method calls on values - /// of type `&str`. This is not unidiomatic and with specialization coming, `to_string` could be - /// specialized to be as efficient as `to_owned`. - pub STR_TO_STRING, - "using `str::to_string` is common even today and specialization will likely happen soon" -} - -declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. - /// - /// **Deprecation reason:** This used to check for `.to_string()` method calls on values - /// of type `String`. This is not unidiomatic and with specialization coming, `to_string` could be - /// specialized to be as efficient as `clone`. - pub STRING_TO_STRING, - "using `string::to_string` is common even today and specialization will likely happen soon" -} - declare_deprecated_lint! { /// **What it does:** Nothing. This lint has been deprecated. /// diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 3201adbf9a0b..6308f6e2e7e9 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,10 +1,10 @@ use crate::utils::{ - eq_expr_value, higher, implements_trait, in_macro, is_copy, is_expn_of, multispan_sugg, snippet, span_lint, - span_lint_and_then, + ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, implements_trait, in_macro, is_copy, is_expn_of, + multispan_sugg, snippet, span_lint, span_lint_and_then, }; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) { return; } - if is_valid_operator(op) && eq_expr_value(cx, left, right) { + if is_useless_with_eq_exprs(higher::binop(op.node)) && eq_expr_value(cx, left, right) { span_lint( cx, EQ_OP, @@ -245,22 +245,3 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } } } - -fn is_valid_operator(op: BinOp) -> bool { - matches!( - op.node, - BinOpKind::Sub - | BinOpKind::Div - | BinOpKind::Eq - | BinOpKind::Lt - | BinOpKind::Le - | BinOpKind::Gt - | BinOpKind::Ge - | BinOpKind::Ne - | BinOpKind::And - | BinOpKind::Or - | BinOpKind::BitXor - | BinOpKind::BitAnd - | BinOpKind::BitOr - ) -} diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index e0a1f4c5ca4f..1194bd7e55e2 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -41,8 +41,7 @@ declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]); impl<'tcx> LateLintPass<'tcx> for OkIfLet { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { //begin checking variables - if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match - if let MatchSource::IfLetDesugar { .. } = source; //test if it is an If Let + if let ExprKind::Match(ref op, ref body, MatchSource::IfLetDesugar { .. }) = expr.kind; //test if expr is if let if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index ed7f3b9293db..03e95c9e27f6 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -68,8 +68,7 @@ fn expr_match(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let StmtKind::Semi(expr, ..) = &stmt.kind; // make sure it's a break, otherwise we want to skip - if let ExprKind::Break(.., break_expr) = &expr.kind; - if let Some(break_expr) = break_expr; + if let ExprKind::Break(.., Some(break_expr)) = &expr.kind; then { lint(cx, expr.span, break_expr.span, LINT_BREAK); } diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index b57fe8dc4269..3a01acd8fdc9 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -59,8 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if let Some(target) = subtracts_one(cx, e); // Extracting out the variable name - if let ExprKind::Path(ref assign_path) = target.kind; - if let QPath::Resolved(_, ref ares_path) = assign_path; + if let ExprKind::Path(QPath::Resolved(_, ref ares_path)) = target.kind; then { // Handle symmetric conditions in the if statement diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 8998fae09de3..0927d218446d 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -58,12 +58,12 @@ impl EarlyLintPass for ItemsAfterStatements { return; } - // skip initial items + // skip initial items and trailing semicolons let stmts = item .stmts .iter() .map(|stmt| &stmt.kind) - .skip_while(|s| matches!(**s, StmtKind::Item(..))); + .skip_while(|s| matches!(**s, StmtKind::Item(..) | StmtKind::Empty)); // lint on all further items for stmt in stmts { diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 025ff86da39d..a76595ed0897 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -52,8 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { if let ItemKind::Const(hir_ty, _) = &item.kind; let ty = hir_ty_to_ty(cx.tcx, hir_ty); if let ty::Array(element_type, cst) = ty.kind(); - if let ConstKind::Value(val) = cst.val; - if let ConstValue::Scalar(element_count) = val; + if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); if self.maximum_allowed_size < element_count * element_size; diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 9fd3780e14e0..9a448ab12568 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -43,8 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { if_chain! { if let ExprKind::Repeat(_, _) = expr.kind; if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind(); - if let ConstKind::Value(val) = cst.val; - if let ConstValue::Scalar(element_count) = val; + if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); if self.maximum_allowed_size < element_count * element_size; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 8243b0a29bc6..0d2d95324c4f 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,12 +1,11 @@ +use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{higher, qpath_res, snippet, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::intravisit; use rustc_hir::BindingAnnotation; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -66,10 +65,10 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; if let hir::StmtKind::Expr(ref if_) = expr.kind; if let Some((ref cond, ref then, ref else_)) = higher::if_block(&if_); - if !used_in_expr(cx, canonical_id, cond); + if !LocalUsedVisitor::new(canonical_id).check_expr(cond); if let hir::ExprKind::Block(ref then, _) = then.kind; if let Some(value) = check_assign(cx, canonical_id, &*then); - if !used_in_expr(cx, canonical_id, value); + if !LocalUsedVisitor::new(canonical_id).check_expr(value); then { let span = stmt.span.to(if_.span); @@ -136,32 +135,6 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { } } -struct UsedVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - id: hir::HirId, - used: bool, -} - -impl<'a, 'tcx> intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::Path(ref qpath) = expr.kind; - if let Res::Local(local_id) = qpath_res(self.cx, qpath, expr.hir_id); - if self.id == local_id; - then { - self.used = true; - return; - } - } - intravisit::walk_expr(self, expr); - } - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } -} - fn check_assign<'tcx>( cx: &LateContext<'tcx>, decl: hir::HirId, @@ -176,18 +149,10 @@ fn check_assign<'tcx>( if let Res::Local(local_id) = qpath_res(cx, qpath, var.hir_id); if decl == local_id; then { - let mut v = UsedVisitor { - cx, - id: decl, - used: false, - }; + let mut v = LocalUsedVisitor::new(decl); - for s in block.stmts.iter().take(block.stmts.len()-1) { - intravisit::walk_stmt(&mut v, s); - - if v.used { - return None; - } + if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| v.check_stmt(stmt)) { + return None; } return Some(value); @@ -196,9 +161,3 @@ fn check_assign<'tcx>( None } - -fn used_in_expr<'tcx>(cx: &LateContext<'tcx>, id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> bool { - let mut v = UsedVisitor { cx, id, used: false }; - intravisit::walk_expr(&mut v, expr); - v.used -} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7e8cbd00c22a..2b99ed570b14 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -44,6 +44,7 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; +use crate::utils::parse_msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::LintId; use rustc_session::Session; @@ -171,6 +172,7 @@ mod cargo_common_metadata; mod checked_conversions; mod cognitive_complexity; mod collapsible_if; +mod collapsible_match; mod comparison_chain; mod copies; mod copy_iterator; @@ -304,9 +306,11 @@ mod self_assignment; mod serde_api; mod shadow; mod single_component_path_imports; +mod size_of_in_element_count; mod slow_vector_initialization; mod stable_sort_primitive; mod strings; +mod suspicious_operation_groupings; mod suspicious_trait_impl; mod swap; mod tabs_in_doc_comments; @@ -440,14 +444,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` has been stabilized in 1.7", ); - store.register_removed( - "clippy::str_to_string", - "using `str::to_string` is common even today and specialization will likely happen soon", - ); - store.register_removed( - "clippy::string_to_string", - "using `string::to_string` is common even today and specialization will likely happen soon", - ); store.register_removed( "clippy::misaligned_transmute", "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", @@ -504,6 +500,24 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: // begin register lints, do not remove this comment, it’s used in `update_lints` store.register_lints(&[ + #[cfg(feature = "internal-lints")] + &utils::internal_lints::CLIPPY_LINTS_INTERNAL, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::COMPILER_LINT_FUNCTIONS, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::DEFAULT_LINT, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::INVALID_PATHS, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::LINT_WITHOUT_LINT_PASS, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::OUTER_EXPN_EXPN_DATA, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::PRODUCE_ICE, &approx_const::APPROX_CONSTANT, &arithmetic::FLOAT_ARITHMETIC, &arithmetic::INTEGER_ARITHMETIC, @@ -537,6 +551,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &checked_conversions::CHECKED_CONVERSIONS, &cognitive_complexity::COGNITIVE_COMPLEXITY, &collapsible_if::COLLAPSIBLE_IF, + &collapsible_match::COLLAPSIBLE_MATCH, &comparison_chain::COMPARISON_CHAIN, &copies::IFS_SAME_COND, &copies::IF_SAME_THEN_ELSE, @@ -833,12 +848,16 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &shadow::SHADOW_SAME, &shadow::SHADOW_UNRELATED, &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, + &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, &stable_sort_primitive::STABLE_SORT_PRIMITIVE, &strings::STRING_ADD, &strings::STRING_ADD_ASSIGN, &strings::STRING_FROM_UTF8_AS_BYTES, &strings::STRING_LIT_AS_BYTES, + &strings::STRING_TO_STRING, + &strings::STR_TO_STRING, + &suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS, &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, &swap::ALMOST_SWAPPED, @@ -907,15 +926,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unwrap_in_result::UNWRAP_IN_RESULT, &use_self::USE_SELF, &useless_conversion::USELESS_CONVERSION, - &utils::internal_lints::CLIPPY_LINTS_INTERNAL, - &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, - &utils::internal_lints::COMPILER_LINT_FUNCTIONS, - &utils::internal_lints::DEFAULT_LINT, - &utils::internal_lints::INVALID_PATHS, - &utils::internal_lints::LINT_WITHOUT_LINT_PASS, - &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, - &utils::internal_lints::OUTER_EXPN_EXPN_DATA, - &utils::internal_lints::PRODUCE_ICE, &vec::USELESS_VEC, &vec_resize_to_zero::VEC_RESIZE_TO_ZERO, &verbose_file_reads::VERBOSE_FILE_READS, @@ -934,14 +944,22 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ]); // end register lints, do not remove this comment, it’s used in `update_lints` + // all the internal lints + #[cfg(feature = "internal-lints")] + { + store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal); + store.register_early_pass(|| box utils::internal_lints::ProduceIce); + store.register_late_pass(|| box utils::inspector::DeepCodeInspector); + store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); + store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); + store.register_late_pass(|| box utils::internal_lints::InvalidPaths); + store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); + store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); + store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass); + } + store.register_late_pass(|| box utils::author::Author); store.register_late_pass(|| box await_holding_invalid::AwaitHolding); store.register_late_pass(|| box serde_api::SerdeAPI); - store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); - store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); - store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass); - store.register_late_pass(|| box utils::internal_lints::InvalidPaths); - store.register_late_pass(|| box utils::inspector::DeepCodeInspector); - store.register_late_pass(|| box utils::author::Author); let vec_box_size_threshold = conf.vec_box_size_threshold; store.register_late_pass(move || box types::Types::new(vec_box_size_threshold)); store.register_late_pass(|| box booleans::NonminimalBool); @@ -964,12 +982,25 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box len_zero::LenZero); store.register_late_pass(|| box attrs::Attributes); store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions); + store.register_late_pass(|| box collapsible_match::CollapsibleMatch); store.register_late_pass(|| box unicode::Unicode); store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd); store.register_late_pass(|| box strings::StringAdd); store.register_late_pass(|| box implicit_return::ImplicitReturn); store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); - store.register_late_pass(|| box methods::Methods); + + let msrv = conf.msrv.as_ref().and_then(|s| { + parse_msrv(s, None, None).or_else(|| { + sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s)); + None + }) + }); + + store.register_late_pass(move || box methods::Methods::new(msrv)); + store.register_late_pass(move || box matches::Matches::new(msrv)); + store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); + store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); + store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount); store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); @@ -983,7 +1014,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box types::Casts); let type_complexity_threshold = conf.type_complexity_threshold; store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold)); - store.register_late_pass(|| box matches::Matches::default()); store.register_late_pass(|| box minmax::MinMaxPass); store.register_late_pass(|| box open_options::OpenOptions); store.register_late_pass(|| box zero_div_zero::ZeroDiv); @@ -1057,6 +1087,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box types::UnitArg); store.register_late_pass(|| box double_comparison::DoubleComparisons); store.register_late_pass(|| box question_mark::QuestionMark); + store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings); store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl); store.register_late_pass(|| box map_unit_fn::MapUnit); store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default()); @@ -1107,10 +1138,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); - store.register_early_pass(|| box literal_representation::LiteralDigitGrouping); + let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; + store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability)); let literal_representation_threshold = conf.literal_representation_threshold; store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)); - store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal); let enum_variant_name_threshold = conf.enum_variant_name_threshold; store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold)); store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments); @@ -1124,7 +1155,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold)); store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic); store.register_early_pass(|| box as_conversions::AsConversions); - store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_late_pass(|| box let_underscore::LetUnderscore); store.register_late_pass(|| box atomic_ordering::AtomicOrdering); store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports); @@ -1140,16 +1170,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box dereference::Dereferencing); store.register_late_pass(|| box option_if_let_else::OptionIfLetElse); store.register_late_pass(|| box future_not_send::FutureNotSend); - store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_late_pass(|| box if_let_mutex::IfLetMutex); store.register_late_pass(|| box mut_mutex_lock::MutMutexLock); store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); - store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn); - let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { single_char_binding_names_threshold, @@ -1166,14 +1193,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box manual_ok_or::ManualOkOr); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); - store.register_late_pass(|| box manual_strip::ManualStrip); - store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::>(); store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax); store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax); store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops); - + store.register_late_pass(|| box strings::StrToString); + store.register_late_pass(|| box strings::StringToString); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1192,6 +1218,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&integer_division::INTEGER_DIVISION), LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION), + LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), LintId::of(&mem_forget::MEM_FORGET), @@ -1215,6 +1242,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&shadow::SHADOW_REUSE), LintId::of(&shadow::SHADOW_SAME), LintId::of(&strings::STRING_ADD), + LintId::of(&strings::STRING_TO_STRING), + LintId::of(&strings::STR_TO_STRING), LintId::of(&types::RC_BUFFER), LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT), LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), @@ -1256,7 +1285,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EXPLICIT_ITER_LOOP), LintId::of(¯o_use::MACRO_USE_IMPORTS), LintId::of(&manual_ok_or::MANUAL_OK_OR), - LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_SAME_ARMS), @@ -1304,6 +1332,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&wildcard_imports::WILDCARD_IMPORTS), ]); + #[cfg(feature = "internal-lints")] store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL), LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), @@ -1337,6 +1366,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&booleans::NONMINIMAL_BOOL), LintId::of(&bytecount::NAIVE_BYTECOUNT), LintId::of(&collapsible_if::COLLAPSIBLE_IF), + LintId::of(&collapsible_match::COLLAPSIBLE_MATCH), LintId::of(&comparison_chain::COMPARISON_CHAIN), LintId::of(&copies::IFS_SAME_COND), LintId::of(&copies::IF_SAME_THEN_ELSE), @@ -1533,9 +1563,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&self_assignment::SELF_ASSIGNMENT), LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), + LintId::of(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), @@ -1602,6 +1634,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&blacklisted_name::BLACKLISTED_NAME), LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(&collapsible_if::COLLAPSIBLE_IF), + LintId::of(&collapsible_match::COLLAPSIBLE_MATCH), LintId::of(&comparison_chain::COMPARISON_CHAIN), LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT), LintId::of(&doc::MISSING_SAFETY_DOC), @@ -1687,6 +1720,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), LintId::of(&try_err::TRY_ERR), @@ -1839,6 +1873,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(®ex::INVALID_REGEX), LintId::of(&self_assignment::SELF_ASSIGNMENT), LintId::of(&serde_api::SERDE_API_MISUSE), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), @@ -1930,14 +1965,6 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) { "unstable_as_mut_slice", "`Vec::as_mut_slice` has been stabilized in 1.7", ); - store.register_removed( - "str_to_string", - "using `str::to_string` is common even today and specialization will likely happen soon", - ); - store.register_removed( - "string_to_string", - "using `string::to_string` is common even today and specialization will likely happen soon", - ); store.register_removed( "misaligned_transmute", "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index e8a741683dac..87a957a9bd24 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -11,7 +11,7 @@ use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// **What it does:** Warns if a long integral or floating-point constant does @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ``` pub UNREADABLE_LITERAL, pedantic, - "long integer literal without underscores" + "long literal without underscores" } declare_clippy_lint! { @@ -208,7 +208,13 @@ impl WarningType { } } -declare_lint_pass!(LiteralDigitGrouping => [ +#[allow(clippy::module_name_repetitions)] +#[derive(Copy, Clone)] +pub struct LiteralDigitGrouping { + lint_fraction_readability: bool, +} + +impl_lint_pass!(LiteralDigitGrouping => [ UNREADABLE_LITERAL, INCONSISTENT_DIGIT_GROUPING, LARGE_DIGIT_GROUPS, @@ -223,7 +229,7 @@ impl EarlyLintPass for LiteralDigitGrouping { } if let ExprKind::Lit(ref lit) = expr.kind { - Self::check_lit(cx, lit) + self.check_lit(cx, lit) } } } @@ -232,7 +238,13 @@ impl EarlyLintPass for LiteralDigitGrouping { const UUID_GROUP_LENS: [usize; 5] = [8, 4, 4, 4, 12]; impl LiteralDigitGrouping { - fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) { + pub fn new(lint_fraction_readability: bool) -> Self { + Self { + lint_fraction_readability, + } + } + + fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { if_chain! { if let Some(src) = snippet_opt(cx, lit.span); if let Some(mut num_lit) = NumericLiteral::from_lit(&src, &lit); @@ -247,9 +259,12 @@ impl LiteralDigitGrouping { let result = (|| { - let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix)?; + let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix, true)?; if let Some(fraction) = num_lit.fraction { - let fractional_group_size = Self::get_group_size(fraction.rsplit('_'), num_lit.radix)?; + let fractional_group_size = Self::get_group_size( + fraction.rsplit('_'), + num_lit.radix, + self.lint_fraction_readability)?; let consistent = Self::parts_consistent(integral_group_size, fractional_group_size, @@ -363,7 +378,11 @@ impl LiteralDigitGrouping { /// Returns the size of the digit groups (or None if ungrouped) if successful, /// otherwise returns a `WarningType` for linting. - fn get_group_size<'a>(groups: impl Iterator, radix: Radix) -> Result, WarningType> { + fn get_group_size<'a>( + groups: impl Iterator, + radix: Radix, + lint_unreadable: bool, + ) -> Result, WarningType> { let mut groups = groups.map(str::len); let first = groups.next().expect("At least one group"); @@ -380,7 +399,7 @@ impl LiteralDigitGrouping { } else { Ok(Some(second)) } - } else if first > 5 { + } else if first > 5 && lint_unreadable { Err(WarningType::UnreadableLiteral) } else { Ok(None) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 0d31e9cfc3de..400148ab81dd 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2,6 +2,7 @@ use crate::consts::constant; use crate::utils::paths; use crate::utils::sugg::Sugg; use crate::utils::usage::{is_unused, mutated_variables}; +use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, @@ -1919,8 +1920,7 @@ fn check_for_single_element_loop<'tcx>( if_chain! { if let ExprKind::AddrOf(BorrowKind::Ref, _, ref arg_expr) = arg.kind; if let PatKind::Binding(.., target, _) = pat.kind; - if let ExprKind::Array(ref arg_expr_list) = arg_expr.kind; - if let [arg_expression] = arg_expr_list; + if let ExprKind::Array([arg_expression]) = arg_expr.kind; if let ExprKind::Path(ref list_item) = arg_expression.kind; if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name); if let ExprKind::Block(ref block, _) = body.kind; @@ -2025,8 +2025,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option let node_str = cx.tcx.hir().get(hir_id); if_chain! { if let Node::Binding(pat) = node_str; - if let PatKind::Binding(bind_ann, ..) = pat.kind; - if let BindingAnnotation::Mutable = bind_ann; + if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; then { return Some(hir_id); } @@ -2071,28 +2070,6 @@ fn pat_is_wild<'tcx>(pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { } } -struct LocalUsedVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - local: HirId, - used: bool, -} - -impl<'a, 'tcx> Visitor<'tcx> for LocalUsedVisitor<'a, 'tcx> { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if same_var(self.cx, expr, self.local) { - self.used = true; - } else { - walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } -} - struct VarVisitor<'a, 'tcx> { /// context reference cx: &'a LateContext<'tcx>, @@ -2126,11 +2103,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { then { let index_used_directly = same_var(self.cx, idx, self.var); let indexed_indirectly = { - let mut used_visitor = LocalUsedVisitor { - cx: self.cx, - local: self.var, - used: false, - }; + let mut used_visitor = LocalUsedVisitor::new(self.var); walk_expr(&mut used_visitor, idx); used_visitor.used }; @@ -2950,7 +2923,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo for ref stmt in block.stmts { if_chain! { if let StmtKind::Local( - Local { pat: Pat { kind: PatKind::Binding(_, _, ident, .. ), .. }, + Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. }, init: Some(ref init_expr), .. } ) = stmt.kind; if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind; @@ -2964,6 +2937,16 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident); if iter_calls.len() == 1; then { + let mut used_count_visitor = UsedCountVisitor { + cx, + id: *pat_id, + count: 0, + }; + walk_block(&mut used_count_visitor, block); + if used_count_visitor.count > 1 { + return; + } + // Suggest replacing iter_call with iter_replacement, and removing stmt let iter_call = &iter_calls[0]; span_lint_and_then( @@ -3087,6 +3070,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor { } } +struct UsedCountVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + id: HirId, + count: usize, +} + +impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + if same_var(self.cx, expr, self.id) { + self.count += 1; + } else { + walk_expr(self, expr); + } + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } +} + /// Detect the occurrences of calls to `iter` or `into_iter` for the /// given identifier fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option> { diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index a1450b0d5fea..91849e748878 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,12 +1,15 @@ -use crate::utils::{snippet_opt, span_lint_and_then}; +use crate::utils::{meets_msrv, snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind}; use rustc_attr as attr; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; +const MANUAL_NON_EXHAUSTIVE_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); + declare_clippy_lint! { /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. /// @@ -55,10 +58,26 @@ declare_clippy_lint! { "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]" } -declare_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); +#[derive(Clone)] +pub struct ManualNonExhaustive { + msrv: Option, +} + +impl ManualNonExhaustive { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustive { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if !meets_msrv(self.msrv.as_ref(), &MANUAL_NON_EXHAUSTIVE_MSRV) { + return; + } + match &item.kind { ItemKind::Enum(def, _) => { check_manual_non_exhaustive_enum(cx, item, &def.variants); @@ -73,6 +92,8 @@ impl EarlyLintPass for ManualNonExhaustive { _ => {}, } } + + extract_msrv_attr!(EarlyContext); } fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 4afb0ab3badb..3c4368a3545a 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,7 +1,7 @@ use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - eq_expr_value, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then, + eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then, }; use if_chain::if_chain; @@ -10,13 +10,16 @@ use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::BinOpKind; use rustc_hir::{BorrowKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::Span; +const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0); + declare_clippy_lint! { /// **What it does:** /// Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using @@ -51,7 +54,18 @@ declare_clippy_lint! { "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing" } -declare_lint_pass!(ManualStrip => [MANUAL_STRIP]); +pub struct ManualStrip { + msrv: Option, +} + +impl ManualStrip { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualStrip => [MANUAL_STRIP]); #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum StripKind { @@ -61,6 +75,10 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) { + return; + } + if_chain! { if let Some((cond, then, _)) = higher::if_block(&expr); if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind; @@ -114,6 +132,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { } } } + + extract_msrv_attr!(LateContext); } // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise. @@ -199,8 +219,7 @@ fn find_stripping<'tcx>( if is_ref_str(self.cx, ex); let unref = peel_ref(ex); if let ExprKind::Index(indexed, index) = &unref.kind; - if let Some(range) = higher::range(index); - if let higher::Range { start, end, .. } = range; + if let Some(higher::Range { start, end, .. }) = higher::range(index); if let ExprKind::Path(path) = &indexed.kind; if qpath_res(self.cx, path, ex.hir_id) == self.target; then { diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 5298e16a04d9..f3c0515b9bcd 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -99,7 +99,7 @@ declare_clippy_lint! { /// } /// ``` pub MAP_ERR_IGNORE, - pedantic, + restriction, "`map_err` should not ignore the original error" } @@ -133,9 +133,9 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { cx, MAP_ERR_IGNORE, body_span, - "`map_err(|_|...` ignores the original error", + "`map_err(|_|...` wildcard pattern discards the original error", None, - "Consider wrapping the error in an enum variant", + "Consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", ); } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index c6dca54e2509..274d20cfa800 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -3,8 +3,8 @@ use crate::utils::sugg::Sugg; use crate::utils::usage::is_unused; use crate::utils::{ expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, - is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet, - snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, + is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, remove_blocks, + snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; @@ -20,6 +20,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty, TyS}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::{sym, Symbol}; @@ -411,8 +412,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Lint for redundant pattern matching over `Result` or - /// `Option` + /// **What it does:** Lint for redundant pattern matching over `Result`, `Option`, + /// `std::task::Poll` or `std::net::IpAddr` /// /// **Why is this bad?** It's more concise and clear to just use the proper /// utility function @@ -422,10 +423,16 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// # use std::task::Poll; + /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if let Ok(_) = Ok::(42) {} /// if let Err(_) = Err::(42) {} /// if let None = None::<()> {} /// if let Some(_) = Some(42) {} + /// if let Poll::Pending = Poll::Pending::<()> {} + /// if let Poll::Ready(_) = Poll::Ready(42) {} + /// if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {} + /// if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {} /// match Ok::(42) { /// Ok(_) => true, /// Err(_) => false, @@ -435,10 +442,16 @@ declare_clippy_lint! { /// The more idiomatic use would be: /// /// ```rust + /// # use std::task::Poll; + /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if Ok::(42).is_ok() {} /// if Err::(42).is_err() {} /// if None::<()>.is_none() {} /// if Some(42).is_some() {} + /// if Poll::Pending::<()>.is_pending() {} + /// if Poll::Ready(42).is_ready() {} + /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {} /// Ok::(42).is_ok(); /// ``` pub REDUNDANT_PATTERN_MATCHING, @@ -452,7 +465,8 @@ declare_clippy_lint! { /// /// **Why is this bad?** Readability and needless complexity. /// - /// **Known problems:** None + /// **Known problems:** This lint falsely triggers, if there are arms with + /// `cfg` attributes that remove an arm evaluating to `false`. /// /// **Example:** /// ```rust @@ -521,9 +535,20 @@ declare_clippy_lint! { #[derive(Default)] pub struct Matches { + msrv: Option, infallible_destructuring_match_linted: bool, } +impl Matches { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { + msrv, + ..Matches::default() + } + } +} + impl_lint_pass!(Matches => [ SINGLE_MATCH, MATCH_REF_PATS, @@ -543,6 +568,8 @@ impl_lint_pass!(Matches => [ MATCH_SAME_ARMS, ]); +const MATCH_LIKE_MATCHES_MACRO_MSRV: RustcVersion = RustcVersion::new(1, 42, 0); + impl<'tcx> LateLintPass<'tcx> for Matches { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) { @@ -550,7 +577,12 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } redundant_pattern_match::check(cx, expr); - if !check_match_like_matches(cx, expr) { + + if meets_msrv(self.msrv.as_ref(), &MATCH_LIKE_MATCHES_MACRO_MSRV) { + if !check_match_like_matches(cx, expr) { + lint_match_arms(cx, expr); + } + } else { lint_match_arms(cx, expr); } @@ -614,8 +646,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if_chain! { if !in_external_macro(cx.sess(), pat.span); if !in_macro(pat.span); - if let PatKind::Struct(ref qpath, fields, true) = pat.kind; - if let QPath::Resolved(_, ref path) = qpath; + if let PatKind::Struct(QPath::Resolved(_, ref path), fields, true) = pat.kind; if let Some(def_id) = path.res.opt_def_id(); let ty = cx.tcx.type_of(def_id); if let ty::Adt(def, _) = ty.kind(); @@ -634,6 +665,8 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } } + + extract_msrv_attr!(LateContext); } #[rustfmt::skip] @@ -922,16 +955,14 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) if let QPath::Resolved(_, p) = path { missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); } - } else if let PatKind::TupleStruct(ref path, ref patterns, ..) = arm.pat.kind { - if let QPath::Resolved(_, p) = path { - // Some simple checks for exhaustive patterns. - // There is a room for improvements to detect more cases, - // but it can be more expensive to do so. - let is_pattern_exhaustive = - |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None)); - if patterns.iter().all(is_pattern_exhaustive) { - missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); - } + } else if let PatKind::TupleStruct(QPath::Resolved(_, p), ref patterns, ..) = arm.pat.kind { + // Some simple checks for exhaustive patterns. + // There is a room for improvements to detect more cases, + // but it can be more expensive to do so. + let is_pattern_exhaustive = + |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None)); + if patterns.iter().all(is_pattern_exhaustive) { + missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); } } } @@ -1134,13 +1165,16 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr if b0 != b1; let if_guard = &b0_arms[0].guard; if if_guard.is_none() || b0_arms.len() == 1; + if b0_arms[0].attrs.is_empty(); if b0_arms[1..].iter() .all(|arm| { find_bool_lit(&arm.body.kind, desugared).map_or(false, |b| b == b0) && - arm.guard.is_none() + arm.guard.is_none() && arm.attrs.is_empty() }); then { - let mut applicability = Applicability::MachineApplicable; + // The suggestion may be incorrect, because some arms can have `cfg` attributes + // evaluated into `false` and so such arms will be stripped before. + let mut applicability = Applicability::MaybeIncorrect; let pat = { use itertools::Itertools as _; b0_arms.iter() @@ -1403,8 +1437,7 @@ fn is_ref_some_arm(arm: &Arm<'_>) -> Option { if let ExprKind::Call(ref e, ref args) = remove_blocks(&arm.body).kind; if let ExprKind::Path(ref some_path) = e.kind; if match_qpath(some_path, &paths::OPTION_SOME) && args.len() == 1; - if let ExprKind::Path(ref qpath) = args[0].kind; - if let &QPath::Resolved(_, ref path2) = qpath; + if let ExprKind::Path(QPath::Resolved(_, ref path2)) = args[0].kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { return Some(rb) @@ -1538,6 +1571,12 @@ mod redundant_pattern_match { "is_err()" } else if match_qpath(path, &paths::OPTION_SOME) { "is_some()" + } else if match_qpath(path, &paths::POLL_READY) { + "is_ready()" + } else if match_qpath(path, &paths::IPADDR_V4) { + "is_ipv4()" + } else if match_qpath(path, &paths::IPADDR_V6) { + "is_ipv6()" } else { return; } @@ -1545,7 +1584,15 @@ mod redundant_pattern_match { return; } }, - PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()", + PatKind::Path(ref path) => { + if match_qpath(path, &paths::OPTION_NONE) { + "is_none()" + } else if match_qpath(path, &paths::POLL_PENDING) { + "is_pending()" + } else { + return; + } + }, _ => return, }; @@ -1610,6 +1657,17 @@ mod redundant_pattern_match { "is_ok()", "is_err()", ) + .or_else(|| { + find_good_method_for_match( + arms, + path_left, + path_right, + &paths::IPADDR_V4, + &paths::IPADDR_V6, + "is_ipv4()", + "is_ipv6()", + ) + }) } else { None } @@ -1628,6 +1686,17 @@ mod redundant_pattern_match { "is_some()", "is_none()", ) + .or_else(|| { + find_good_method_for_match( + arms, + path_left, + path_right, + &paths::POLL_READY, + &paths::POLL_PENDING, + "is_ready()", + "is_pending()", + ) + }) } else { None } diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 40a625758616..44c974b9d985 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -90,8 +90,7 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option return Some(MinMax::Max), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fa1744043657..8002c27a5e91 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -14,13 +14,12 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; -use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -28,11 +27,12 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, - is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, - match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, - single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, + contains_return, contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, + implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, + match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls, + method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, + walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -1404,7 +1404,18 @@ declare_clippy_lint! { "use `.collect()` instead of `::from_iter()`" } -declare_lint_pass!(Methods => [ +pub struct Methods { + msrv: Option, +} + +impl Methods { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, SHOULD_IMPLEMENT_TRAIT, @@ -1531,8 +1542,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { check_pointer_offset(cx, expr, arg_lists[0]) }, ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), - ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false), - ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true), + ["map", "as_ref"] => { + lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref()) + }, + ["map", "as_mut"] => { + lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref()) + }, ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"), ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"), ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), @@ -1738,6 +1753,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } } + + extract_msrv_attr!(LateContext); } /// Checks for the `OR_FUN_CALL` lint. @@ -3453,6 +3470,8 @@ fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { ); } +const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); + /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s fn lint_option_as_ref_deref<'tcx>( cx: &LateContext<'tcx>, @@ -3460,7 +3479,12 @@ fn lint_option_as_ref_deref<'tcx>( as_ref_args: &[hir::Expr<'_>], map_args: &[hir::Expr<'_>], is_mut: bool, + msrv: Option<&RustcVersion>, ) { + if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) { + return; + } + let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]); @@ -3846,36 +3870,6 @@ fn is_bool(ty: &hir::Ty<'_>) -> bool { } } -// Returns `true` if `expr` contains a return expression -fn contains_return(expr: &hir::Expr<'_>) -> bool { - struct RetCallFinder { - found: bool, - } - - impl<'tcx> intravisit::Visitor<'tcx> for RetCallFinder { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if self.found { - return; - } - if let hir::ExprKind::Ret(..) = &expr.kind { - self.found = true; - } else { - intravisit::walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - } - - let mut visitor = RetCallFinder { found: false }; - visitor.visit_expr(expr); - visitor.found -} - fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { if_chain! { if args.len() == 2; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 308e92057b75..0512d74c7b1c 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -18,7 +18,7 @@ use crate::utils::sugg::Sugg; use crate::utils::{ get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, span_lint_hir_and_then, SpanlessEq, + span_lint_and_then, span_lint_hir_and_then, unsext, SpanlessEq, }; declare_clippy_lint! { @@ -139,12 +139,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for getting the remainder of a division by one. + /// **What it does:** Checks for getting the remainder of a division by one or minus + /// one. /// - /// **Why is this bad?** The result can only ever be zero. No one will write - /// such code deliberately, unless trying to win an Underhanded Rust - /// Contest. Even for that contest, it's probably a bad idea. Use something more - /// underhanded. + /// **Why is this bad?** The result for a divisor of one can only ever be zero; for + /// minus one it can cause panic/overflow (if the left operand is the minimal value of + /// the respective integer type) or results in zero. No one will write such code + /// deliberately, unless trying to win an Underhanded Rust Contest. Even for that + /// contest, it's probably a bad idea. Use something more underhanded. /// /// **Known problems:** None. /// @@ -152,10 +154,11 @@ declare_clippy_lint! { /// ```rust /// # let x = 1; /// let a = x % 1; + /// let a = x % -1; /// ``` pub MODULO_ONE, correctness, - "taking a number modulo 1, which always returns 0" + "taking a number modulo +/-1, which can either panic/overflow or always returns 0" } declare_clippy_lint! { @@ -378,60 +381,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { return; }, ExprKind::Binary(ref cmp, ref left, ref right) => { - let op = cmp.node; - if op.is_comparison() { - check_nan(cx, left, expr); - check_nan(cx, right, expr); - check_to_owned(cx, left, right, true); - check_to_owned(cx, right, left, false); - } - if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { - if is_allowed(cx, left) || is_allowed(cx, right) { - return; - } - - // Allow comparing the results of signum() - if is_signum(cx, left) && is_signum(cx, right) { - return; - } - - if let Some(name) = get_item_name(cx, expr) { - let name = name.as_str(); - if name == "eq" - || name == "ne" - || name == "is_nan" - || name.starts_with("eq_") - || name.ends_with("_eq") - { - return; - } - } - let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); - let (lint, msg) = get_lint_and_message( - is_named_constant(cx, left) || is_named_constant(cx, right), - is_comparing_arrays, - ); - span_lint_and_then(cx, lint, expr.span, msg, |diag| { - let lhs = Sugg::hir(cx, left, ".."); - let rhs = Sugg::hir(cx, right, ".."); - - if !is_comparing_arrays { - diag.span_suggestion( - expr.span, - "consider comparing them within some margin of error", - format!( - "({}).abs() {} error_margin", - lhs - rhs, - if op == BinOpKind::Eq { '<' } else { '>' } - ), - Applicability::HasPlaceholders, // snippet - ); - } - diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); - }); - } else if op == BinOpKind::Rem && is_integer_const(cx, right, 1) { - span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); - } + check_binary(cx, expr, cmp, left, right); + return; }, _ => {}, } @@ -744,3 +695,74 @@ fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) } } } + +fn check_binary( + cx: &LateContext<'a>, + expr: &Expr<'_>, + cmp: &rustc_span::source_map::Spanned, + left: &'a Expr<'_>, + right: &'a Expr<'_>, +) { + let op = cmp.node; + if op.is_comparison() { + check_nan(cx, left, expr); + check_nan(cx, right, expr); + check_to_owned(cx, left, right, true); + check_to_owned(cx, right, left, false); + } + if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { + if is_allowed(cx, left) || is_allowed(cx, right) { + return; + } + + // Allow comparing the results of signum() + if is_signum(cx, left) && is_signum(cx, right) { + return; + } + + if let Some(name) = get_item_name(cx, expr) { + let name = name.as_str(); + if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") { + return; + } + } + let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); + let (lint, msg) = get_lint_and_message( + is_named_constant(cx, left) || is_named_constant(cx, right), + is_comparing_arrays, + ); + span_lint_and_then(cx, lint, expr.span, msg, |diag| { + let lhs = Sugg::hir(cx, left, ".."); + let rhs = Sugg::hir(cx, right, ".."); + + if !is_comparing_arrays { + diag.span_suggestion( + expr.span, + "consider comparing them within some margin of error", + format!( + "({}).abs() {} error_margin", + lhs - rhs, + if op == BinOpKind::Eq { '<' } else { '>' } + ), + Applicability::HasPlaceholders, // snippet + ); + } + diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); + }); + } else if op == BinOpKind::Rem { + if is_integer_const(cx, right, 1) { + span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); + } + + if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() { + if is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) { + span_lint( + cx, + MODULO_ONE, + expr.span, + "any number modulo -1 will panic/overflow or result in 0", + ); + } + }; + } +} diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index a799a644e970..42f97b2ac497 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -6,7 +6,6 @@ use crate::utils::sugg::Sugg; use crate::utils::{ higher, is_expn_of, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg, }; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; @@ -198,13 +197,9 @@ struct ExpressionInfoWithSpan { } fn is_unary_not(e: &Expr<'_>) -> (bool, Span) { - if_chain! { - if let ExprKind::Unary(unop, operand) = e.kind; - if let UnOp::UnNot = unop; - then { - return (true, operand.span); - } - }; + if let ExprKind::Unary(UnOp::UnNot, operand) = e.kind { + return (true, operand.span); + } (false, e.span) } diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 31b03ecd101c..359620cc0797 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -66,7 +66,7 @@ declare_clippy_lint! { /// ``` pub UNREACHABLE, restriction, - "`unreachable!` should not be present in production code" + "usage of the `unreachable!` macro" } declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]); @@ -85,12 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { } else if is_expn_of(expr.span, "todo").is_some() { span_lint(cx, TODO, span, "`todo` should not be present in production code"); } else if is_expn_of(expr.span, "unreachable").is_some() { - span_lint( - cx, - UNREACHABLE, - span, - "`unreachable` should not be present in production code", - ); + span_lint(cx, UNREACHABLE, span, "usage of the `unreachable!` macro"); } else if is_expn_of(expr.span, "panic").is_some() { span_lint(cx, PANIC, span, "`panic` should not be present in production code"); } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index d9b280b7a859..b91233ac5828 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -176,8 +176,7 @@ impl QuestionMark { if block.stmts.len() == 1; if let Some(expr) = block.stmts.iter().last(); if let StmtKind::Semi(ref expr) = expr.kind; - if let ExprKind::Ret(ret_expr) = expr.kind; - if let Some(ret_expr) = ret_expr; + if let ExprKind::Ret(Some(ret_expr)) = expr.kind; then { return Some(ret_expr); diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 49cb2ffc4e37..f398b3fff25a 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { cx: &'a LateContext<'tcx>, path: &'tcx hir::Path<'tcx>, count: usize, - }; + } impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { type Map = Map<'tcx>; @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap { hir_visit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) } - }; + } let mut closure_usage_count = ClosureUsageCount { cx, path, count: 0 }; closure_usage_count.visit_block(block); closure_usage_count.count diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs new file mode 100644 index 000000000000..ea7a76146f52 --- /dev/null +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -0,0 +1,145 @@ +//! Lint on use of `size_of` or `size_of_val` of T in an expression +//! expecting a count of T + +use crate::utils::{match_def_path, paths, span_lint_and_help}; +use if_chain::if_chain; +use rustc_hir::BinOpKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty, TyS, TypeAndMut}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Detects expressions where + /// `size_of::` or `size_of_val::` is used as a + /// count of elements of type `T` + /// + /// **Why is this bad?** These functions expect a count + /// of `T` and not a number of bytes + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,no_run + /// # use std::ptr::copy_nonoverlapping; + /// # use std::mem::size_of; + /// const SIZE: usize = 128; + /// let x = [2u8; SIZE]; + /// let mut y = [2u8; SIZE]; + /// unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + /// ``` + pub SIZE_OF_IN_ELEMENT_COUNT, + correctness, + "using `size_of::` or `size_of_val::` where a count of elements of `T` is expected" +} + +declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]); + +fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { + match expr.kind { + ExprKind::Call(count_func, _func_args) => { + if_chain! { + if let ExprKind::Path(ref count_func_qpath) = count_func.kind; + if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::MEM_SIZE_OF) + || match_def_path(cx, def_id, &paths::MEM_SIZE_OF_VAL); + then { + cx.typeck_results().node_substs(count_func.hir_id).types().next() + } else { + None + } + } + }, + ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node || BinOpKind::Div == op.node => { + get_size_of_ty(cx, left).or_else(|| get_size_of_ty(cx, right)) + }, + ExprKind::Cast(expr, _) => get_size_of_ty(cx, expr), + _ => None, + } +} + +fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { + const FUNCTIONS: [&[&str]; 8] = [ + &paths::COPY_NONOVERLAPPING, + &paths::COPY, + &paths::WRITE_BYTES, + &paths::PTR_SWAP_NONOVERLAPPING, + &paths::PTR_SLICE_FROM_RAW_PARTS, + &paths::PTR_SLICE_FROM_RAW_PARTS_MUT, + &paths::SLICE_FROM_RAW_PARTS, + &paths::SLICE_FROM_RAW_PARTS_MUT, + ]; + const METHODS: [&str; 11] = [ + "write_bytes", + "copy_to", + "copy_from", + "copy_to_nonoverlapping", + "copy_from_nonoverlapping", + "add", + "wrapping_add", + "sub", + "wrapping_sub", + "offset", + "wrapping_offset", + ]; + + if_chain! { + // Find calls to ptr::{copy, copy_nonoverlapping} + // and ptr::{swap_nonoverlapping, write_bytes}, + if let ExprKind::Call(func, [.., count]) = expr.kind; + if let ExprKind::Path(ref func_qpath) = func.kind; + if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); + if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path)); + + // Get the pointee type + if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); + then { + return Some((pointee_ty, count)); + } + }; + if_chain! { + // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods + if let ExprKind::MethodCall(method_path, _, [ptr_self, .., count], _) = expr.kind; + let method_ident = method_path.ident.as_str(); + if METHODS.iter().any(|m| *m == &*method_ident); + + // Get the pointee type + if let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) = + cx.typeck_results().expr_ty(ptr_self).kind(); + then { + return Some((pointee_ty, count)); + } + }; + None +} + +impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + const HELP_MSG: &str = "use a count of elements instead of a count of bytes\ + , it already gets multiplied by the size of the type"; + + const LINT_MSG: &str = "found a count of bytes \ + instead of a count of elements of `T`"; + + if_chain! { + // Find calls to functions with an element count parameter and get + // the pointee type and count parameter expression + if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr); + + // Find a size_of call in the count parameter expression and + // check that it's the same type + if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr); + if TyS::same_type(pointee_ty, ty_used_for_size_of); + then { + span_lint_and_help( + cx, + SIZE_OF_IN_ELEMENT_COUNT, + count_expr.span, + LINT_MSG, + None, + HELP_MSG + ); + } + }; + } +} diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index ede37624f71a..77e790733789 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -2,6 +2,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -11,7 +12,7 @@ use if_chain::if_chain; use crate::utils::SpanlessEq; use crate::utils::{ get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint, - span_lint_and_sugg, + span_lint_and_help, span_lint_and_sugg, }; declare_clippy_lint! { @@ -221,8 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if method_names[0] == sym!(as_bytes); // Check for slicer - if let ExprKind::Struct(ref path, _, _) = right.kind; - if let QPath::LangItem(LangItem::Range, _) = path; + if let ExprKind::Struct(QPath::LangItem(LangItem::Range, _), _, _) = right.kind; then { let mut applicability = Applicability::MachineApplicable; @@ -289,3 +289,100 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } } } + +declare_clippy_lint! { + /// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. + /// + /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string. + /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better + /// expressed with `.to_owned()`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // example code where clippy issues a warning + /// let _ = "str".to_string(); + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// let _ = "str".to_owned(); + /// ``` + pub STR_TO_STRING, + restriction, + "using `to_string()` on a `&str`, which should be `to_owned()`" +} + +declare_lint_pass!(StrToString => [STR_TO_STRING]); + +impl LateLintPass<'_> for StrToString { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; + if path.ident.name == sym!(to_string); + let ty = cx.typeck_results().expr_ty(&args[0]); + if let ty::Ref(_, ty, ..) = ty.kind(); + if *ty.kind() == ty::Str; + then { + span_lint_and_help( + cx, + STR_TO_STRING, + expr.span, + "`to_string()` called on a `&str`", + None, + "consider using `.to_owned()`", + ); + } + } + } +} + +declare_clippy_lint! { + /// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. + /// + /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string. + /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // example code where clippy issues a warning + /// let msg = String::from("Hello World"); + /// let _ = msg.to_string(); + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// let msg = String::from("Hello World"); + /// let _ = msg.clone(); + /// ``` + pub STRING_TO_STRING, + restriction, + "using `to_string()` on a `String`, which should be `clone()`" +} + +declare_lint_pass!(StringToString => [STRING_TO_STRING]); + +impl LateLintPass<'_> for StringToString { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; + if path.ident.name == sym!(to_string); + let ty = cx.typeck_results().expr_ty(&args[0]); + if is_type_diagnostic_item(cx, ty, sym!(string_type)); + then { + span_lint_and_help( + cx, + STRING_TO_STRING, + expr.span, + "`to_string()` called on a `String`", + None, + "consider using `.clone()`", + ); + } + } + } +} diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs new file mode 100644 index 000000000000..cccd24ccf940 --- /dev/null +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -0,0 +1,693 @@ +use crate::utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use core::ops::{Add, AddAssign}; +use if_chain::if_chain; +use rustc_ast::ast::{BinOpKind, Expr, ExprKind, StmtKind}; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; +use rustc_span::symbol::Ident; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** + /// Checks for unlikely usages of binary operators that are almost + /// certainly typos and/or copy/paste errors, given the other usages + /// of binary operators nearby. + /// **Why is this bad?** + /// They are probably bugs and if they aren't then they look like bugs + /// and you should add a comment explaining why you are doing such an + /// odd set of operations. + /// **Known problems:** + /// There may be some false positives if you are trying to do something + /// unusual that happens to look like a typo. + /// + /// **Example:** + /// + /// ```rust + /// struct Vec3 { + /// x: f64, + /// y: f64, + /// z: f64, + /// } + /// + /// impl Eq for Vec3 {} + /// + /// impl PartialEq for Vec3 { + /// fn eq(&self, other: &Self) -> bool { + /// // This should trigger the lint because `self.x` is compared to `other.y` + /// self.x == other.y && self.y == other.y && self.z == other.z + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// # struct Vec3 { + /// # x: f64, + /// # y: f64, + /// # z: f64, + /// # } + /// // same as above except: + /// impl PartialEq for Vec3 { + /// fn eq(&self, other: &Self) -> bool { + /// // Note we now compare other.x to self.x + /// self.x == other.x && self.y == other.y && self.z == other.z + /// } + /// } + /// ``` + pub SUSPICIOUS_OPERATION_GROUPINGS, + style, + "groupings of binary operations that look suspiciously like typos" +} + +declare_lint_pass!(SuspiciousOperationGroupings => [SUSPICIOUS_OPERATION_GROUPINGS]); + +impl EarlyLintPass for SuspiciousOperationGroupings { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if expr.span.from_expansion() { + return; + } + + if let Some(binops) = extract_related_binops(&expr.kind) { + check_binops(cx, &binops.iter().collect::>()); + + let mut op_types = Vec::with_capacity(binops.len()); + // We could use a hashmap, etc. to avoid being O(n*m) here, but + // we want the lints to be emitted in a consistent order. Besides, + // m, (the number of distinct `BinOpKind`s in `binops`) + // will often be small, and does have an upper limit. + binops.iter().map(|b| b.op).for_each(|op| { + if !op_types.contains(&op) { + op_types.push(op); + } + }); + + for op_type in op_types { + let ops: Vec<_> = binops.iter().filter(|b| b.op == op_type).collect(); + + check_binops(cx, &ops); + } + } + } +} + +fn check_binops(cx: &EarlyContext<'_>, binops: &[&BinaryOp<'_>]) { + let binop_count = binops.len(); + if binop_count < 2 { + // Single binary operation expressions would likely be false + // positives. + return; + } + + let mut one_ident_difference_count = 0; + let mut no_difference_info = None; + let mut double_difference_info = None; + let mut expected_ident_loc = None; + + let mut paired_identifiers = FxHashSet::default(); + + for (i, BinaryOp { left, right, op, .. }) in binops.iter().enumerate() { + match ident_difference_expr(left, right) { + IdentDifference::NoDifference => { + if is_useless_with_eq_exprs(*op) { + // The `eq_op` lint should catch this in this case. + return; + } + + no_difference_info = Some(i); + }, + IdentDifference::Single(ident_loc) => { + one_ident_difference_count += 1; + if let Some(previous_expected) = expected_ident_loc { + if previous_expected != ident_loc { + // This expression doesn't match the form we're + // looking for. + return; + } + } else { + expected_ident_loc = Some(ident_loc); + } + + // If there was only a single difference, all other idents + // must have been the same, and thus were paired. + for id in skip_index(IdentIter::from(*left), ident_loc.index) { + paired_identifiers.insert(id); + } + }, + IdentDifference::Double(ident_loc1, ident_loc2) => { + double_difference_info = Some((i, ident_loc1, ident_loc2)); + }, + IdentDifference::Multiple | IdentDifference::NonIdent => { + // It's too hard to know whether this is a bug or not. + return; + }, + } + } + + let mut applicability = Applicability::MachineApplicable; + + if let Some(expected_loc) = expected_ident_loc { + match (no_difference_info, double_difference_info) { + (Some(i), None) => attempt_to_emit_no_difference_lint(cx, binops, i, expected_loc), + (None, Some((double_difference_index, ident_loc1, ident_loc2))) => { + if_chain! { + if one_ident_difference_count == binop_count - 1; + if let Some(binop) = binops.get(double_difference_index); + then { + let changed_loc = if ident_loc1 == expected_loc { + ident_loc2 + } else if ident_loc2 == expected_loc { + ident_loc1 + } else { + // This expression doesn't match the form we're + // looking for. + return; + }; + + if let Some(sugg) = ident_swap_sugg( + cx, + &paired_identifiers, + binop, + changed_loc, + &mut applicability, + ) { + emit_suggestion( + cx, + binop.span, + sugg, + applicability, + ); + } + } + } + }, + _ => {}, + } + } +} + +fn attempt_to_emit_no_difference_lint( + cx: &EarlyContext<'_>, + binops: &[&BinaryOp<'_>], + i: usize, + expected_loc: IdentLocation, +) { + if let Some(binop) = binops.get(i).cloned() { + // We need to try and figure out which identifier we should + // suggest using instead. Since there could be multiple + // replacement candidates in a given expression, and we're + // just taking the first one, we may get some bad lint + // messages. + let mut applicability = Applicability::MaybeIncorrect; + + // We assume that the correct ident is one used elsewhere in + // the other binops, in a place that there was a single + // difference between idents before. + let old_left_ident = get_ident(binop.left, expected_loc); + let old_right_ident = get_ident(binop.right, expected_loc); + + for b in skip_index(binops.iter(), i) { + if_chain! { + if let (Some(old_ident), Some(new_ident)) = + (old_left_ident, get_ident(b.left, expected_loc)); + if old_ident != new_ident; + if let Some(sugg) = suggestion_with_swapped_ident( + cx, + binop.left, + expected_loc, + new_ident, + &mut applicability, + ); + then { + emit_suggestion( + cx, + binop.span, + replace_left_sugg(cx, &binop, &sugg, &mut applicability), + applicability, + ); + return; + } + } + + if_chain! { + if let (Some(old_ident), Some(new_ident)) = + (old_right_ident, get_ident(b.right, expected_loc)); + if old_ident != new_ident; + if let Some(sugg) = suggestion_with_swapped_ident( + cx, + binop.right, + expected_loc, + new_ident, + &mut applicability, + ); + then { + emit_suggestion( + cx, + binop.span, + replace_right_sugg(cx, &binop, &sugg, &mut applicability), + applicability, + ); + return; + } + } + } + } +} + +fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicability: Applicability) { + span_lint_and_sugg( + cx, + SUSPICIOUS_OPERATION_GROUPINGS, + span, + "This sequence of operators looks suspiciously like a bug.", + "I think you meant", + sugg, + applicability, + ) +} + +fn ident_swap_sugg( + cx: &EarlyContext<'_>, + paired_identifiers: &FxHashSet, + binop: &BinaryOp<'_>, + location: IdentLocation, + applicability: &mut Applicability, +) -> Option { + let left_ident = get_ident(&binop.left, location)?; + let right_ident = get_ident(&binop.right, location)?; + + let sugg = match ( + paired_identifiers.contains(&left_ident), + paired_identifiers.contains(&right_ident), + ) { + (true, true) | (false, false) => { + // We don't have a good guess of what ident should be + // used instead, in these cases. + *applicability = Applicability::MaybeIncorrect; + + // We arbitraily choose one side to suggest changing, + // since we don't have a better guess. If the user + // ends up duplicating a clause, the `logic_bug` lint + // should catch it. + + let right_suggestion = + suggestion_with_swapped_ident(cx, &binop.right, location, left_ident, applicability)?; + + replace_right_sugg(cx, binop, &right_suggestion, applicability) + }, + (false, true) => { + // We haven't seen a pair involving the left one, so + // it's probably what is wanted. + + let right_suggestion = + suggestion_with_swapped_ident(cx, &binop.right, location, left_ident, applicability)?; + + replace_right_sugg(cx, binop, &right_suggestion, applicability) + }, + (true, false) => { + // We haven't seen a pair involving the right one, so + // it's probably what is wanted. + let left_suggestion = suggestion_with_swapped_ident(cx, &binop.left, location, right_ident, applicability)?; + + replace_left_sugg(cx, binop, &left_suggestion, applicability) + }, + }; + + Some(sugg) +} + +fn replace_left_sugg( + cx: &EarlyContext<'_>, + binop: &BinaryOp<'_>, + left_suggestion: &str, + applicability: &mut Applicability, +) -> String { + format!( + "{} {} {}", + left_suggestion, + binop.op.to_string(), + snippet_with_applicability(cx, binop.right.span, "..", applicability), + ) +} + +fn replace_right_sugg( + cx: &EarlyContext<'_>, + binop: &BinaryOp<'_>, + right_suggestion: &str, + applicability: &mut Applicability, +) -> String { + format!( + "{} {} {}", + snippet_with_applicability(cx, binop.left.span, "..", applicability), + binop.op.to_string(), + right_suggestion, + ) +} + +#[derive(Clone, Debug)] +struct BinaryOp<'exprs> { + op: BinOpKind, + span: Span, + left: &'exprs Expr, + right: &'exprs Expr, +} + +impl BinaryOp<'exprs> { + fn new(op: BinOpKind, span: Span, (left, right): (&'exprs Expr, &'exprs Expr)) -> Self { + Self { op, span, left, right } + } +} + +fn strip_non_ident_wrappers(expr: &Expr) -> &Expr { + let mut output = expr; + loop { + output = match &output.kind { + ExprKind::Paren(ref inner) | ExprKind::Unary(_, ref inner) => inner, + _ => { + return output; + }, + }; + } +} + +fn extract_related_binops(kind: &ExprKind) -> Option>> { + append_opt_vecs(chained_binops(kind), if_statment_binops(kind)) +} + +fn if_statment_binops(kind: &ExprKind) -> Option>> { + match kind { + ExprKind::If(ref condition, _, _) => chained_binops(&condition.kind), + ExprKind::Paren(ref e) => if_statment_binops(&e.kind), + ExprKind::Block(ref block, _) => { + let mut output = None; + for stmt in &block.stmts { + match stmt.kind { + StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => { + output = append_opt_vecs(output, if_statment_binops(&e.kind)); + }, + _ => {}, + } + } + output + }, + _ => None, + } +} + +fn append_opt_vecs(target_opt: Option>, source_opt: Option>) -> Option> { + match (target_opt, source_opt) { + (Some(mut target), Some(mut source)) => { + target.reserve(source.len()); + for op in source.drain(..) { + target.push(op); + } + Some(target) + }, + (Some(v), None) | (None, Some(v)) => Some(v), + (None, None) => None, + } +} + +fn chained_binops(kind: &ExprKind) -> Option>> { + match kind { + ExprKind::Binary(_, left_outer, right_outer) => chained_binops_helper(left_outer, right_outer), + ExprKind::Paren(ref e) | ExprKind::Unary(_, ref e) => chained_binops(&e.kind), + _ => None, + } +} + +fn chained_binops_helper(left_outer: &'expr Expr, right_outer: &'expr Expr) -> Option>> { + match (&left_outer.kind, &right_outer.kind) { + ( + ExprKind::Paren(ref left_e) | ExprKind::Unary(_, ref left_e), + ExprKind::Paren(ref right_e) | ExprKind::Unary(_, ref right_e), + ) => chained_binops_helper(left_e, right_e), + (ExprKind::Paren(ref left_e) | ExprKind::Unary(_, ref left_e), _) => chained_binops_helper(left_e, right_outer), + (_, ExprKind::Paren(ref right_e) | ExprKind::Unary(_, ref right_e)) => { + chained_binops_helper(left_outer, right_e) + }, + ( + ExprKind::Binary(Spanned { node: left_op, .. }, ref left_left, ref left_right), + ExprKind::Binary(Spanned { node: right_op, .. }, ref right_left, ref right_right), + ) => match ( + chained_binops_helper(left_left, left_right), + chained_binops_helper(right_left, right_right), + ) { + (Some(mut left_ops), Some(mut right_ops)) => { + left_ops.reserve(right_ops.len()); + for op in right_ops.drain(..) { + left_ops.push(op); + } + Some(left_ops) + }, + (Some(mut left_ops), _) => { + left_ops.push(BinaryOp::new(*right_op, right_outer.span, (right_left, right_right))); + Some(left_ops) + }, + (_, Some(mut right_ops)) => { + right_ops.insert(0, BinaryOp::new(*left_op, left_outer.span, (left_left, left_right))); + Some(right_ops) + }, + (None, None) => Some(vec![ + BinaryOp::new(*left_op, left_outer.span, (left_left, left_right)), + BinaryOp::new(*right_op, right_outer.span, (right_left, right_right)), + ]), + }, + _ => None, + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] +struct IdentLocation { + index: usize, +} + +impl Add for IdentLocation { + type Output = IdentLocation; + + fn add(self, other: Self) -> Self::Output { + Self { + index: self.index + other.index, + } + } +} + +impl AddAssign for IdentLocation { + fn add_assign(&mut self, other: Self) { + *self = *self + other + } +} + +#[derive(Clone, Copy, Debug)] +enum IdentDifference { + NoDifference, + Single(IdentLocation), + Double(IdentLocation, IdentLocation), + Multiple, + NonIdent, +} + +impl Add for IdentDifference { + type Output = IdentDifference; + + fn add(self, other: Self) -> Self::Output { + match (self, other) { + (Self::NoDifference, output) | (output, Self::NoDifference) => output, + (Self::Multiple, _) + | (_, Self::Multiple) + | (Self::Double(_, _), Self::Single(_)) + | (Self::Single(_) | Self::Double(_, _), Self::Double(_, _)) => Self::Multiple, + (Self::NonIdent, _) | (_, Self::NonIdent) => Self::NonIdent, + (Self::Single(il1), Self::Single(il2)) => Self::Double(il1, il2), + } + } +} + +impl AddAssign for IdentDifference { + fn add_assign(&mut self, other: Self) { + *self = *self + other + } +} + +impl IdentDifference { + /// Returns true if learning about more differences will not change the value + /// of this `IdentDifference`, and false otherwise. + fn is_complete(&self) -> bool { + match self { + Self::NoDifference | Self::Single(_) | Self::Double(_, _) => false, + Self::Multiple | Self::NonIdent => true, + } + } +} + +fn ident_difference_expr(left: &Expr, right: &Expr) -> IdentDifference { + ident_difference_expr_with_base_location(left, right, IdentLocation::default()).0 +} + +fn ident_difference_expr_with_base_location( + left: &Expr, + right: &Expr, + mut base: IdentLocation, +) -> (IdentDifference, IdentLocation) { + // Ideally, this function should not use IdentIter because it should return + // early if the expressions have any non-ident differences. We want that early + // return because if without that restriction the lint would lead to false + // positives. + // + // But, we cannot (easily?) use a `rustc_ast::visit::Visitor`, since we need + // the two expressions to be walked in lockstep. And without a `Visitor`, we'd + // have to do all the AST traversal ourselves, which is a lot of work, since to + // do it properly we'd need to be able to handle more or less every possible + // AST node since `Item`s can be written inside `Expr`s. + // + // In practice, it seems likely that expressions, above a certain size, that + // happen to use the exact same idents in the exact same order, and which are + // not structured the same, would be rare. Therefore it seems likely that if + // we do only the first layer of matching ourselves and eventually fallback on + // IdentIter, then the output of this function will be almost always be correct + // in practice. + // + // If it turns out that problematic cases are more prelavent than we assume, + // then we should be able to change this function to do the correct traversal, + // without needing to change the rest of the code. + + #![allow(clippy::enum_glob_use)] + use ExprKind::*; + + match ( + &strip_non_ident_wrappers(left).kind, + &strip_non_ident_wrappers(right).kind, + ) { + (Yield(_), Yield(_)) + | (Try(_), Try(_)) + | (Paren(_), Paren(_)) + | (Repeat(_, _), Repeat(_, _)) + | (Struct(_, _, _), Struct(_, _, _)) + | (MacCall(_), MacCall(_)) + | (LlvmInlineAsm(_), LlvmInlineAsm(_)) + | (InlineAsm(_), InlineAsm(_)) + | (Ret(_), Ret(_)) + | (Continue(_), Continue(_)) + | (Break(_, _), Break(_, _)) + | (AddrOf(_, _, _), AddrOf(_, _, _)) + | (Path(_, _), Path(_, _)) + | (Range(_, _, _), Range(_, _, _)) + | (Index(_, _), Index(_, _)) + | (Field(_, _), Field(_, _)) + | (AssignOp(_, _, _), AssignOp(_, _, _)) + | (Assign(_, _, _), Assign(_, _, _)) + | (TryBlock(_), TryBlock(_)) + | (Await(_), Await(_)) + | (Async(_, _, _), Async(_, _, _)) + | (Block(_, _), Block(_, _)) + | (Closure(_, _, _, _, _, _), Closure(_, _, _, _, _, _)) + | (Match(_, _), Match(_, _)) + | (Loop(_, _), Loop(_, _)) + | (ForLoop(_, _, _, _), ForLoop(_, _, _, _)) + | (While(_, _, _), While(_, _, _)) + | (If(_, _, _), If(_, _, _)) + | (Let(_, _), Let(_, _)) + | (Type(_, _), Type(_, _)) + | (Cast(_, _), Cast(_, _)) + | (Lit(_), Lit(_)) + | (Unary(_, _), Unary(_, _)) + | (Binary(_, _, _), Binary(_, _, _)) + | (Tup(_), Tup(_)) + | (MethodCall(_, _, _), MethodCall(_, _, _)) + | (Call(_, _), Call(_, _)) + | (ConstBlock(_), ConstBlock(_)) + | (Array(_), Array(_)) + | (Box(_), Box(_)) => { + // keep going + }, + _ => { + return (IdentDifference::NonIdent, base); + }, + } + + let mut difference = IdentDifference::NoDifference; + + for (left_attr, right_attr) in left.attrs.iter().zip(right.attrs.iter()) { + let (new_difference, new_base) = + ident_difference_via_ident_iter_with_base_location(left_attr, right_attr, base); + base = new_base; + difference += new_difference; + if difference.is_complete() { + return (difference, base); + } + } + + let (new_difference, new_base) = ident_difference_via_ident_iter_with_base_location(left, right, base); + base = new_base; + difference += new_difference; + + (difference, base) +} + +fn ident_difference_via_ident_iter_with_base_location>( + left: Iterable, + right: Iterable, + mut base: IdentLocation, +) -> (IdentDifference, IdentLocation) { + // See the note in `ident_difference_expr_with_base_location` about `IdentIter` + let mut difference = IdentDifference::NoDifference; + + let mut left_iterator = left.into(); + let mut right_iterator = right.into(); + + loop { + match (left_iterator.next(), right_iterator.next()) { + (Some(left_ident), Some(right_ident)) => { + if !eq_id(left_ident, right_ident) { + difference += IdentDifference::Single(base); + if difference.is_complete() { + return (difference, base); + } + } + }, + (Some(_), None) | (None, Some(_)) => { + return (IdentDifference::NonIdent, base); + }, + (None, None) => { + return (difference, base); + }, + } + base += IdentLocation { index: 1 }; + } +} + +fn get_ident(expr: &Expr, location: IdentLocation) -> Option { + IdentIter::from(expr).nth(location.index) +} + +fn suggestion_with_swapped_ident( + cx: &EarlyContext<'_>, + expr: &Expr, + location: IdentLocation, + new_ident: Ident, + applicability: &mut Applicability, +) -> Option { + get_ident(expr, location).and_then(|current_ident| { + if eq_id(current_ident, new_ident) { + // We never want to suggest a non-change + return None; + } + + Some(format!( + "{}{}{}", + snippet_with_applicability(cx, expr.span.with_hi(current_ident.span.lo()), "..", applicability), + new_ident.to_string(), + snippet_with_applicability(cx, expr.span.with_lo(current_ident.span.hi()), "..", applicability), + )) + }) +} + +fn skip_index(iter: Iter, index: usize) -> impl Iterator +where + Iter: Iterator, +{ + iter.enumerate() + .filter_map(move |(i, a)| if i == index { None } else { Some(a) }) +} diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index d4acf8df46d8..daff5f81e8c3 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -168,8 +168,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { if_chain! { if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; if !in_macro(bound_predicate.span); - if let TyKind::Path(ref path) = bound_predicate.bounded_ty.kind; - if let QPath::Resolved(_, Path { ref segments, .. }) = path; + if let TyKind::Path(QPath::Resolved(_, Path { ref segments, .. })) = bound_predicate.bounded_ty.kind; if let Some(segment) = segments.first(); if let Some(trait_resolutions_direct) = map.get(&segment.ident); then { diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index d60306336c6e..6b171a0fa1af 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -48,8 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { if_chain! { if let ExprKind::Path(ref _qpath) = args[0].kind; let x = const_eval_context.expr(&args[0]); - if let Some(constant) = x; - if let Constant::RawPtr(0) = constant; + if let Some(Constant::RawPtr(0)) = x; then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index f0e10e374e11..74ba53e6a9a0 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -8,6 +8,7 @@ use if_chain::if_chain; use rustc_ast::{FloatTy, IntTy, LitFloatType, LitIntType, LitKind, UintTy}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; +use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericBounds, GenericParamKind, HirId, @@ -737,8 +738,7 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool { fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option> { if_chain! { if let Some(did) = qpath_res(cx, qpath, id).opt_def_id(); - if let Some(node) = cx.tcx.hir().get_if_local(did); - if let Node::GenericParam(generic_param) = node; + if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did); if let GenericParamKind::Type { synthetic, .. } = generic_param.kind; if synthetic == Some(SyntheticTyParamKind::ImplTrait); then { @@ -1469,8 +1469,7 @@ fn check_loss_of_sign(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast // don't lint for positive constants let const_val = constant(cx, &cx.typeck_results(), op); if_chain! { - if let Some((const_val, _)) = const_val; - if let Constant::Int(n) = const_val; + if let Some((Constant::Int(n), _)) = const_val; if let ty::Int(ity) = *cast_from.kind(); if sext(cx.tcx, n, ity) >= 0; then { @@ -1632,7 +1631,14 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if expr.span.from_expansion() { return; } - if let ExprKind::Cast(ref ex, _) = expr.kind { + if let ExprKind::Cast(ref ex, cast_to) = expr.kind { + if let TyKind::Path(QPath::Resolved(_, path)) = cast_to.kind { + if let Res::Def(_, def_id) = path.res { + if cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr) { + return; + } + } + } let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr)); lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to); if let Some(lit) = get_numeric_literal(ex) { @@ -1711,7 +1717,7 @@ fn show_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &st expr.span, &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to), "try", - format!("{}_{}", literal_str, cast_to), + format!("{}_{}", literal_str.trim_end_matches('.'), cast_to), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 25ecc7a82f18..5d801511a0b1 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,5 +1,5 @@ use crate::utils::{ - in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, + contains_return, in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, visitors::find_all_ret_expressions, }; use if_chain::if_chain; @@ -95,6 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if let ExprKind::Path(ref qpath) = func.kind; if match_qpath(qpath, path); if args.len() == 1; + if !contains_return(&args[0]); then { suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string())); true @@ -134,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { diag.multipart_suggestion( "...and change the returning expressions", suggs, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); }, ); diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index fcf7a4b1367e..31b4e25411bd 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -10,6 +10,17 @@ use rustc_ast::{self as ast, *}; use rustc_span::symbol::Ident; use std::mem; +pub mod ident_iter; +pub use ident_iter::IdentIter; + +pub fn is_useless_with_eq_exprs(kind: BinOpKind) -> bool { + use BinOpKind::*; + matches!( + kind, + Sub | Div | Eq | Lt | Le | Gt | Ge | Ne | And | Or | BitXor | BitAnd | BitOr + ) +} + /// Checks if each element in the first slice is contained within the latter as per `eq_fn`. pub fn unordered_over(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { left.len() == right.len() && left.iter().all(|l| right.iter().any(|r| eq_fn(l, r))) diff --git a/clippy_lints/src/utils/ast_utils/ident_iter.rs b/clippy_lints/src/utils/ast_utils/ident_iter.rs new file mode 100644 index 000000000000..eefcbabd835d --- /dev/null +++ b/clippy_lints/src/utils/ast_utils/ident_iter.rs @@ -0,0 +1,45 @@ +use core::iter::FusedIterator; +use rustc_ast::visit::{walk_attribute, walk_expr, Visitor}; +use rustc_ast::{Attribute, Expr}; +use rustc_span::symbol::Ident; + +pub struct IdentIter(std::vec::IntoIter); + +impl Iterator for IdentIter { + type Item = Ident; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +impl FusedIterator for IdentIter {} + +impl From<&Expr> for IdentIter { + fn from(expr: &Expr) -> Self { + let mut visitor = IdentCollector::default(); + + walk_expr(&mut visitor, expr); + + IdentIter(visitor.0.into_iter()) + } +} + +impl From<&Attribute> for IdentIter { + fn from(attr: &Attribute) -> Self { + let mut visitor = IdentCollector::default(); + + walk_attribute(&mut visitor, attr); + + IdentIter(visitor.0.into_iter()) + } +} + +#[derive(Default)] +struct IdentCollector(Vec); + +impl Visitor<'_> for IdentCollector { + fn visit_ident(&mut self, ident: Ident) { + self.0.push(ident); + } +} diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index e6d41341a55f..24052a243af8 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -21,6 +21,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[ DeprecationStatus::Replaced("cognitive_complexity"), ), ("dump", DeprecationStatus::None), + ("msrv", DeprecationStatus::None), ]; pub struct LimitStack { @@ -123,6 +124,24 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' } } +pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'static str) -> Option { + let mut unique_attr = None; + for attr in get_attr(sess, attrs, name) { + match attr.style { + ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()), + ast::AttrStyle::Inner => { + sess.struct_span_err(attr.span, &format!("`{}` is defined multiple times", name)) + .span_note(unique_attr.as_ref().unwrap().span, "first definition found here") + .emit(); + }, + ast::AttrStyle::Outer => { + sess.span_err(attr.span, &format!("`{}` cannot be an outer attribute", name)); + }, + } + } + unique_attr +} + /// Return true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool { diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 0ac8fff69f05..6403ff6dad18 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -106,6 +106,8 @@ macro_rules! define_Conf { pub use self::helpers::Conf; define_Conf! { + /// Lint: MANUAL_NON_EXHAUSTIVE, MANUAL_STRIP, OPTION_AS_REF_DEREF, MATCH_LIKE_MATCHES_MACRO. The minimum rust version that the project supports + (msrv, "msrv": Option, None), /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses (blacklisted_names, "blacklisted_names": Vec, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()), /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have @@ -168,6 +170,8 @@ define_Conf! { (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false), /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses (disallowed_methods, "disallowed_methods": Vec, Vec::::new()), + /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators. + (unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true), } impl Default for Conf { diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index 0a58231558ed..a7a6b5855b75 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -186,7 +186,9 @@ pub fn span_lint_hir_and_then( /// | /// = note: `-D fold-any` implied by `-D warnings` /// ``` -#[allow(clippy::collapsible_span_lint_calls)] + +#[allow(clippy::unknown_clippy_lints)] +#[cfg_attr(feature = "internal-lints", allow(clippy::collapsible_span_lint_calls))] pub fn span_lint_and_sugg<'a, T: LintContext>( cx: &'a T, lint: &'static Lint, diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 6d7c5058b4f3..01ffac5b5599 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -162,8 +162,7 @@ pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr< if let hir::Block { expr: Some(expr), .. } = &**block; if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind; if let hir::ExprKind::DropTemps(cond) = &cond.kind; - if let [arm, ..] = &arms[..]; - if let hir::Arm { body, .. } = arm; + if let [hir::Arm { body, .. }, ..] = &arms[..]; then { return Some((cond, body)); } diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index e4ad105c3513..d847d22275e8 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -81,7 +81,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { } } - match (&left.kind, &right.kind) { + match (&reduce_exprkind(&left.kind), &reduce_exprkind(&right.kind)) { (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => { lb == rb && l_mut == r_mut && self.eq_expr(le, re) }, @@ -306,6 +306,32 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { } } +/// Some simple reductions like `{ return }` => `return` +fn reduce_exprkind<'hir>(kind: &'hir ExprKind<'hir>) -> &ExprKind<'hir> { + if let ExprKind::Block(block, _) = kind { + match (block.stmts, block.expr) { + // `{}` => `()` + ([], None) => &ExprKind::Tup(&[]), + ([], Some(expr)) => match expr.kind { + // `{ return .. }` => `return ..` + ExprKind::Ret(..) => &expr.kind, + _ => kind, + }, + ([stmt], None) => match stmt.kind { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind { + // `{ return ..; }` => `return ..` + ExprKind::Ret(..) => &expr.kind, + _ => kind, + }, + _ => kind, + }, + _ => kind, + } + } else { + kind + } +} + fn swap_binop<'a>( binop: BinOpKind, lhs: &'a Expr<'a>, diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index e9c71e23a670..3a6b64c90e8f 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -14,6 +14,7 @@ pub mod eager_or_lazy; pub mod higher; mod hir_utils; pub mod inspector; +#[cfg(feature = "internal-lints")] pub mod internal_lints; pub mod numeric_literal; pub mod paths; @@ -51,6 +52,8 @@ use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; +use rustc_semver::RustcVersion; +use rustc_session::Session; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::sym as rustc_sym; @@ -62,6 +65,49 @@ use smallvec::SmallVec; use crate::consts::{constant, Constant}; +pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { + if let Ok(version) = RustcVersion::parse(msrv) { + return Some(version); + } else if let Some(sess) = sess { + if let Some(span) = span { + sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv)); + } + } + None +} + +pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool { + msrv.map_or(true, |msrv| msrv.meets(*lint_msrv)) +} + +macro_rules! extract_msrv_attr { + (LateContext) => { + extract_msrv_attr!(@LateContext, ()); + }; + (EarlyContext) => { + extract_msrv_attr!(@EarlyContext); + }; + (@$context:ident$(, $call:tt)?) => { + fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) { + use $crate::utils::get_unique_inner_attr; + match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") { + Some(msrv_attr) => { + if let Some(msrv) = msrv_attr.value_str() { + self.msrv = $crate::utils::parse_msrv( + &msrv.to_string(), + Some(cx.sess$($call)?), + Some(msrv_attr.span), + ); + } else { + cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute"); + } + }, + _ => (), + } + } + }; +} + /// Returns `true` if the two spans come from differing expansions (i.e., one is /// from a macro and one isn't). #[must_use] @@ -527,6 +573,36 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool { cn.result } +/// Returns `true` if `expr` contains a return expression +pub fn contains_return(expr: &hir::Expr<'_>) -> bool { + struct RetCallFinder { + found: bool, + } + + impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { + if self.found { + return; + } + if let hir::ExprKind::Ret(..) = &expr.kind { + self.found = true; + } else { + hir::intravisit::walk_expr(self, expr); + } + } + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::None + } + } + + let mut visitor = RetCallFinder { found: false }; + visitor.visit_expr(expr); + visitor.found +} + /// Converts a span to a code snippet if available, otherwise use default. /// /// This is useful if you want to provide suggestions for your lint or more generally, if you want diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 137f5d18b664..6fdc7b4587f0 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -20,6 +20,8 @@ pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"]; pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"]; pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"]; +pub const COPY: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; +pub const COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy"]; pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"]; @@ -31,6 +33,7 @@ pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"]; pub const DROP: [&str; 3] = ["core", "mem", "drop"]; pub const DURATION: [&str; 3] = ["core", "time", "Duration"]; +#[cfg(feature = "internal-lints")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EXIT: [&str; 3] = ["std", "process", "exit"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; @@ -58,9 +61,13 @@ pub const INTO: [&str; 3] = ["core", "convert", "Into"]; pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; +pub const IPADDR_V4: [&str; 4] = ["std", "net", "IpAddr", "V4"]; +pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"]; pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"]; +#[cfg(feature = "internal-lints")] pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"]; +#[cfg(feature = "internal-lints")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"]; pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"]; @@ -68,6 +75,8 @@ pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "Manua pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"]; pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]; pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"]; +pub const MEM_SIZE_OF: [&str; 3] = ["core", "mem", "size_of"]; +pub const MEM_SIZE_OF_VAL: [&str; 3] = ["core", "mem", "size_of_val"]; pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OPS_MODULE: [&str; 2] = ["core", "ops"]; @@ -90,9 +99,14 @@ pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"]; +pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"]; +pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"]; pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; pub const PTR_NULL: [&str; 3] = ["core", "ptr", "null"]; pub const PTR_NULL_MUT: [&str; 3] = ["core", "ptr", "null_mut"]; +pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"]; +pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"]; +pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"]; pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"]; pub const RC: [&str; 3] = ["alloc", "rc", "Rc"]; @@ -114,6 +128,8 @@ pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGu pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; +pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"]; +pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; @@ -129,6 +145,7 @@ pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "", "starts_with"]; +#[cfg(feature = "internal-lints")] pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"]; pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"]; @@ -146,3 +163,4 @@ pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; +pub const WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"]; diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs index b0837b6c43e7..28b3e79d7a6d 100644 --- a/clippy_lints/src/utils/visitors.rs +++ b/clippy_lints/src/utils/visitors.rs @@ -1,5 +1,7 @@ use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, QPath, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -123,3 +125,54 @@ where !ret_finder.failed } } + +pub struct LocalUsedVisitor { + pub local_hir_id: HirId, + pub used: bool, +} + +impl LocalUsedVisitor { + pub fn new(local_hir_id: HirId) -> Self { + Self { + local_hir_id, + used: false, + } + } + + fn check(&mut self, t: T, visit: fn(&mut Self, T)) -> bool { + visit(self, t); + std::mem::replace(&mut self.used, false) + } + + pub fn check_arm(&mut self, arm: &Arm<'_>) -> bool { + self.check(arm, Self::visit_arm) + } + + pub fn check_expr(&mut self, expr: &Expr<'_>) -> bool { + self.check(expr, Self::visit_expr) + } + + pub fn check_stmt(&mut self, stmt: &Stmt<'_>) -> bool { + self.check(stmt, Self::visit_stmt) + } +} + +impl<'v> Visitor<'v> for LocalUsedVisitor { + type Map = Map<'v>; + + fn visit_expr(&mut self, expr: &'v Expr<'v>) { + if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind { + if let Res::Local(id) = path.res { + if id == self.local_hir_id { + self.used = true; + return; + } + } + } + walk_expr(self, expr); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } +} diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 0e8f7683103d..ec3af94b9ca9 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -12,6 +12,9 @@ use std::path::{Path, PathBuf}; mod cargo; +// whether to run internal tests or not +const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints"); + fn host_lib() -> PathBuf { option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from) } @@ -96,6 +99,16 @@ fn run_mode(cfg: &mut compiletest::Config) { compiletest::run_tests(&cfg); } +fn run_internal_tests(cfg: &mut compiletest::Config) { + // only run internal tests with the internal-tests feature + if !RUN_INTERNAL_TESTS { + return; + } + cfg.mode = TestMode::Ui; + cfg.src_base = Path::new("tests").join("ui-internal"); + compiletest::run_tests(&cfg); +} + fn run_ui_toml(config: &mut compiletest::Config) { fn run_tests(config: &compiletest::Config, mut tests: Vec) -> Result { let mut result = true; @@ -199,7 +212,6 @@ fn run_ui_cargo(config: &mut compiletest::Config) { Some("main.rs") => {}, _ => continue, } - let paths = compiletest::common::TestPaths { file: file_path, base: config.src_base.clone(), @@ -253,4 +265,5 @@ fn compile_test() { run_mode(&mut config); run_ui_toml(&mut config); run_ui_cargo(&mut config); + run_internal_tests(&mut config); } diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 48e0478f1699..a6163a83d768 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -18,7 +18,8 @@ fn dogfood_clippy() { } let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let output = Command::new(&*CLIPPY_PATH) + let mut command = Command::new(&*CLIPPY_PATH); + command .current_dir(root_dir) .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") @@ -27,11 +28,16 @@ fn dogfood_clippy() { .arg("--all-features") .arg("--") .args(&["-D", "clippy::all"]) - .args(&["-D", "clippy::internal"]) .args(&["-D", "clippy::pedantic"]) - .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir - .output() - .unwrap(); + .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir + + // internal lints only exist if we build with the internal-lints feature + if cfg!(feature = "internal-lints") { + command.args(&["-D", "clippy::internal"]); + } + + let output = command.output().unwrap(); + println!("status: {}", output.status); println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); diff --git a/tests/ui/collapsible_span_lint_calls.fixed b/tests/ui-internal/collapsible_span_lint_calls.fixed similarity index 100% rename from tests/ui/collapsible_span_lint_calls.fixed rename to tests/ui-internal/collapsible_span_lint_calls.fixed diff --git a/tests/ui/collapsible_span_lint_calls.rs b/tests/ui-internal/collapsible_span_lint_calls.rs similarity index 100% rename from tests/ui/collapsible_span_lint_calls.rs rename to tests/ui-internal/collapsible_span_lint_calls.rs diff --git a/tests/ui/collapsible_span_lint_calls.stderr b/tests/ui-internal/collapsible_span_lint_calls.stderr similarity index 100% rename from tests/ui/collapsible_span_lint_calls.stderr rename to tests/ui-internal/collapsible_span_lint_calls.stderr diff --git a/tests/ui/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs similarity index 100% rename from tests/ui/custom_ice_message.rs rename to tests/ui-internal/custom_ice_message.rs diff --git a/tests/ui/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr similarity index 100% rename from tests/ui/custom_ice_message.stderr rename to tests/ui-internal/custom_ice_message.stderr diff --git a/tests/ui/default_lint.rs b/tests/ui-internal/default_lint.rs similarity index 100% rename from tests/ui/default_lint.rs rename to tests/ui-internal/default_lint.rs diff --git a/tests/ui/default_lint.stderr b/tests/ui-internal/default_lint.stderr similarity index 100% rename from tests/ui/default_lint.stderr rename to tests/ui-internal/default_lint.stderr diff --git a/tests/ui/invalid_paths.rs b/tests/ui-internal/invalid_paths.rs similarity index 100% rename from tests/ui/invalid_paths.rs rename to tests/ui-internal/invalid_paths.rs diff --git a/tests/ui/invalid_paths.stderr b/tests/ui-internal/invalid_paths.stderr similarity index 100% rename from tests/ui/invalid_paths.stderr rename to tests/ui-internal/invalid_paths.stderr diff --git a/tests/ui/lint_without_lint_pass.rs b/tests/ui-internal/lint_without_lint_pass.rs similarity index 100% rename from tests/ui/lint_without_lint_pass.rs rename to tests/ui-internal/lint_without_lint_pass.rs diff --git a/tests/ui/lint_without_lint_pass.stderr b/tests/ui-internal/lint_without_lint_pass.stderr similarity index 100% rename from tests/ui/lint_without_lint_pass.stderr rename to tests/ui-internal/lint_without_lint_pass.stderr diff --git a/tests/ui/match_type_on_diag_item.rs b/tests/ui-internal/match_type_on_diag_item.rs similarity index 100% rename from tests/ui/match_type_on_diag_item.rs rename to tests/ui-internal/match_type_on_diag_item.rs diff --git a/tests/ui/match_type_on_diag_item.stderr b/tests/ui-internal/match_type_on_diag_item.stderr similarity index 100% rename from tests/ui/match_type_on_diag_item.stderr rename to tests/ui-internal/match_type_on_diag_item.stderr diff --git a/tests/ui/outer_expn_data.fixed b/tests/ui-internal/outer_expn_data.fixed similarity index 100% rename from tests/ui/outer_expn_data.fixed rename to tests/ui-internal/outer_expn_data.fixed diff --git a/tests/ui/outer_expn_data.rs b/tests/ui-internal/outer_expn_data.rs similarity index 100% rename from tests/ui/outer_expn_data.rs rename to tests/ui-internal/outer_expn_data.rs diff --git a/tests/ui/outer_expn_data.stderr b/tests/ui-internal/outer_expn_data.stderr similarity index 100% rename from tests/ui/outer_expn_data.stderr rename to tests/ui-internal/outer_expn_data.stderr diff --git a/tests/ui-toml/invalid_min_rust_version/clippy.toml b/tests/ui-toml/invalid_min_rust_version/clippy.toml new file mode 100644 index 000000000000..088b12b2daca --- /dev/null +++ b/tests/ui-toml/invalid_min_rust_version/clippy.toml @@ -0,0 +1 @@ +msrv = "invalid.version" diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs new file mode 100644 index 000000000000..2ebf28645e51 --- /dev/null +++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs @@ -0,0 +1,3 @@ +#![allow(clippy::redundant_clone)] + +fn main() {} diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr new file mode 100644 index 000000000000..e9d8fd2e0f52 --- /dev/null +++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr @@ -0,0 +1,4 @@ +error: error reading Clippy's configuration file. `invalid.version` is not a valid Rust version + +error: aborting due to previous error + diff --git a/tests/ui-toml/lint_decimal_readability/clippy.toml b/tests/ui-toml/lint_decimal_readability/clippy.toml new file mode 100644 index 000000000000..6feaf7d5c0c1 --- /dev/null +++ b/tests/ui-toml/lint_decimal_readability/clippy.toml @@ -0,0 +1 @@ +unreadable-literal-lint-fractions = false \ No newline at end of file diff --git a/tests/ui-toml/lint_decimal_readability/test.rs b/tests/ui-toml/lint_decimal_readability/test.rs new file mode 100644 index 000000000000..9377eb69b233 --- /dev/null +++ b/tests/ui-toml/lint_decimal_readability/test.rs @@ -0,0 +1,22 @@ +#[deny(clippy::unreadable_literal)] + +fn allow_inconsistent_digit_grouping() { + #![allow(clippy::inconsistent_digit_grouping)] + let _pass1 = 100_200_300.123456789; +} + +fn main() { + allow_inconsistent_digit_grouping(); + + let _pass1 = 100_200_300.100_200_300; + let _pass2 = 1.123456789; + let _pass3 = 1.0; + let _pass4 = 10000.00001; + let _pass5 = 1.123456789e1; + + // due to clippy::inconsistent-digit-grouping + let _fail1 = 100_200_300.123456789; + + // fail due to the integer part + let _fail2 = 100200300.300200100; +} diff --git a/tests/ui-toml/lint_decimal_readability/test.stderr b/tests/ui-toml/lint_decimal_readability/test.stderr new file mode 100644 index 000000000000..9119ef19a7be --- /dev/null +++ b/tests/ui-toml/lint_decimal_readability/test.stderr @@ -0,0 +1,10 @@ +error: digits grouped inconsistently by underscores + --> $DIR/test.rs:18:18 + | +LL | let _fail1 = 100_200_300.123456789; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.123_456_789` + | + = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-toml/min_rust_version/clippy.toml b/tests/ui-toml/min_rust_version/clippy.toml new file mode 100644 index 000000000000..8e17d8074c41 --- /dev/null +++ b/tests/ui-toml/min_rust_version/clippy.toml @@ -0,0 +1 @@ +msrv = "1.0.0" diff --git a/tests/ui-toml/min_rust_version/min_rust_version.rs b/tests/ui-toml/min_rust_version/min_rust_version.rs new file mode 100644 index 000000000000..bc41efa42a17 --- /dev/null +++ b/tests/ui-toml/min_rust_version/min_rust_version.rs @@ -0,0 +1,68 @@ +#![allow(clippy::redundant_clone)] +#![warn(clippy::manual_non_exhaustive)] + +use std::ops::Deref; + +mod enums { + enum E { + A, + B, + #[doc(hidden)] + _C, + } + + // user forgot to remove the marker + #[non_exhaustive] + enum Ep { + A, + B, + #[doc(hidden)] + _C, + } +} + +fn option_as_ref_deref() { + let mut opt = Some(String::from("123")); + + let _ = opt.as_ref().map(String::as_str); + let _ = opt.as_ref().map(|x| x.as_str()); + let _ = opt.as_mut().map(String::as_mut_str); + let _ = opt.as_mut().map(|x| x.as_mut_str()); +} + +fn match_like_matches() { + let _y = match Some(5) { + Some(0) => true, + _ => false, + }; +} + +fn match_same_arms() { + match (1, 2, 3) { + (1, .., 3) => 42, + (.., 3) => 42, //~ ERROR match arms have same body + _ => 0, + }; +} + +fn match_same_arms2() { + let _ = match Some(42) { + Some(_) => 24, + None => 24, //~ ERROR match arms have same body + }; +} + +fn manual_strip_msrv() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } +} + +fn main() { + option_as_ref_deref(); + match_like_matches(); + match_same_arms(); + match_same_arms2(); + manual_strip_msrv(); +} diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index a58e7e918e2f..7b3c476461d5 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs index e01ba0c64df3..cd745feec6d8 100644 --- a/tests/ui/as_conversions.rs +++ b/tests/ui/as_conversions.rs @@ -1,7 +1,19 @@ -#[warn(clippy::as_conversions)] +// aux-build:macro_rules.rs + +#![warn(clippy::as_conversions)] + +#[macro_use] +extern crate macro_rules; + +fn with_external_macro() { + as_conv_with_arg!(0u32 as u64); + as_conv!(); +} fn main() { let i = 0u32 as u64; let j = &i as *const u64 as *mut u64; + + with_external_macro(); } diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr index 312d3a7460eb..f5f75d3aee04 100644 --- a/tests/ui/as_conversions.stderr +++ b/tests/ui/as_conversions.stderr @@ -1,5 +1,5 @@ error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:4:13 + --> $DIR/as_conversions.rs:14:13 | LL | let i = 0u32 as u64; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let i = 0u32 as u64; = help: consider using a safe wrapper for this conversion error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:6:13 + --> $DIR/as_conversions.rs:16:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let j = &i as *const u64 as *mut u64; = help: consider using a safe wrapper for this conversion error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:6:13 + --> $DIR/as_conversions.rs:16:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index 93303865e178..f985a15eda2b 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -70,3 +70,17 @@ macro_rules! ref_arg_function { fn fun_example(ref _x: usize) {} }; } + +#[macro_export] +macro_rules! as_conv_with_arg { + (0u32 as u64) => { + () + }; +} + +#[macro_export] +macro_rules! as_conv { + () => { + 0u32 as u64 + }; +} diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs new file mode 100644 index 000000000000..a83e6c77b12e --- /dev/null +++ b/tests/ui/collapsible_match.rs @@ -0,0 +1,239 @@ +#![warn(clippy::collapsible_match)] +#![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)] + +fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { + // match without block + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + + // match with block + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + + // if let, if let + if let Ok(val) = res_opt { + if let Some(n) = val { + take(n); + } + } + + // if let else, if let else + if let Ok(val) = res_opt { + if let Some(n) = val { + take(n); + } else { + return; + } + } else { + return; + } + + // if let, match + if let Ok(val) = res_opt { + match val { + Some(n) => foo(n), + _ => (), + } + } + + // match, if let + match res_opt { + Ok(val) => { + if let Some(n) = val { + take(n); + } + }, + _ => {}, + } + + // if let else, match + if let Ok(val) = res_opt { + match val { + Some(n) => foo(n), + _ => return, + } + } else { + return; + } + + // match, if let else + match res_opt { + Ok(val) => { + if let Some(n) = val { + take(n); + } else { + return; + } + }, + _ => return, + } + + // None in inner match same as outer wild branch + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + None => return, + }, + _ => return, + } + + // None in outer match same as inner wild branch + match opt_opt { + Some(val) => match val { + Some(n) => foo(n), + _ => return, + }, + None => return, + } +} + +fn negative_cases(res_opt: Result, String>, res_res: Result, String>) { + // no wild pattern in outer match + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => return, + }, + Err(_) => return, + } + + // inner branch is not wild or None + match res_res { + Ok(val) => match val { + Ok(n) => foo(n), + Err(_) => return, + }, + _ => return, + } + + // statement before inner match + match res_opt { + Ok(val) => { + "hi buddy"; + match val { + Some(n) => foo(n), + _ => return, + } + }, + _ => return, + } + + // statement after inner match + match res_opt { + Ok(val) => { + match val { + Some(n) => foo(n), + _ => return, + } + "hi buddy"; + }, + _ => return, + } + + // wild branches do not match + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => { + "sup"; + return; + }, + }, + _ => return, + } + + // binding used in if guard + match res_opt { + Ok(val) if val.is_some() => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + + // binding used in inner match body + match res_opt { + Ok(val) => match val { + Some(_) => take(val), + _ => return, + }, + _ => return, + } + + // if guard on inner match + { + match res_opt { + Ok(val) => match val { + Some(n) if make() => foo(n), + _ => return, + }, + _ => return, + } + match res_opt { + Ok(val) => match val { + _ => make(), + _ if make() => return, + }, + _ => return, + } + } + + // differing macro contexts + { + macro_rules! mac { + ($val:ident) => { + match $val { + Some(n) => foo(n), + _ => return, + } + }; + } + match res_opt { + Ok(val) => mac!(val), + _ => return, + } + } + + // OR pattern + enum E { + A(T), + B(T), + C(T), + }; + match make::>>() { + E::A(val) | E::B(val) => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + match make::>>() { + Some(val) => match val { + E::A(val) | E::B(val) => foo(val), + _ => return, + }, + _ => return, + } +} + +fn make() -> T { + unimplemented!() +} + +fn foo(t: T) -> U { + unimplemented!() +} + +fn take(t: T) {} + +fn main() {} diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr new file mode 100644 index 000000000000..63ac6a1613dc --- /dev/null +++ b/tests/ui/collapsible_match.stderr @@ -0,0 +1,179 @@ +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:7:20 + | +LL | Ok(val) => match val { + | ____________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_________^ + | + = note: `-D clippy::collapsible-match` implied by `-D warnings` +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:7:12 + | +LL | Ok(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:16:20 + | +LL | Ok(val) => match val { + | ____________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:16:12 + | +LL | Ok(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:25:9 + | +LL | / if let Some(n) = val { +LL | | take(n); +LL | | } + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:24:15 + | +LL | if let Ok(val) = res_opt { + | ^^^ Replace this binding +LL | if let Some(n) = val { + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:32:9 + | +LL | / if let Some(n) = val { +LL | | take(n); +LL | | } else { +LL | | return; +LL | | } + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:31:15 + | +LL | if let Ok(val) = res_opt { + | ^^^ Replace this binding +LL | if let Some(n) = val { + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:43:9 + | +LL | / match val { +LL | | Some(n) => foo(n), +LL | | _ => (), +LL | | } + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:42:15 + | +LL | if let Ok(val) = res_opt { + | ^^^ Replace this binding +LL | match val { +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:52:13 + | +LL | / if let Some(n) = val { +LL | | take(n); +LL | | } + | |_____________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:51:12 + | +LL | Ok(val) => { + | ^^^ Replace this binding +LL | if let Some(n) = val { + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:61:9 + | +LL | / match val { +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | } + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:60:15 + | +LL | if let Ok(val) = res_opt { + | ^^^ Replace this binding +LL | match val { +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:72:13 + | +LL | / if let Some(n) = val { +LL | | take(n); +LL | | } else { +LL | | return; +LL | | } + | |_____________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:71:12 + | +LL | Ok(val) => { + | ^^^ Replace this binding +LL | if let Some(n) = val { + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:83:20 + | +LL | Ok(val) => match val { + | ____________________^ +LL | | Some(n) => foo(n), +LL | | None => return, +LL | | }, + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:83:12 + | +LL | Ok(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:92:22 + | +LL | Some(val) => match val { + | ______________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:92:14 + | +LL | Some(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: aborting due to 10 previous errors + diff --git a/tests/ui/collapsible_match2.rs b/tests/ui/collapsible_match2.rs new file mode 100644 index 000000000000..d571ac4ab693 --- /dev/null +++ b/tests/ui/collapsible_match2.rs @@ -0,0 +1,53 @@ +#![warn(clippy::collapsible_match)] +#![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)] + +fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { + // if guards on outer match + { + match res_opt { + Ok(val) if make() => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => return, + }, + _ if make() => return, + _ => return, + } + } + + // macro + { + macro_rules! mac { + ($outer:expr => $pat:pat, $e:expr => $inner_pat:pat, $then:expr) => { + match $outer { + $pat => match $e { + $inner_pat => $then, + _ => return, + }, + _ => return, + } + }; + } + // Lint this since the patterns are not defined by the macro. + // Allows the lint to work on if_chain! for example. + // Fixing the lint requires knowledge of the specific macro, but we optimistically assume that + // there is still a better way to write this. + mac!(res_opt => Ok(val), val => Some(n), foo(n)); + } +} + +fn make() -> T { + unimplemented!() +} + +fn foo(t: T) -> U { + unimplemented!() +} + +fn main() {} diff --git a/tests/ui/collapsible_match2.stderr b/tests/ui/collapsible_match2.stderr new file mode 100644 index 000000000000..490d82d12cd5 --- /dev/null +++ b/tests/ui/collapsible_match2.stderr @@ -0,0 +1,61 @@ +error: Unnecessary nested match + --> $DIR/collapsible_match2.rs:8:34 + | +LL | Ok(val) if make() => match val { + | __________________________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_____________^ + | + = note: `-D clippy::collapsible-match` implied by `-D warnings` +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match2.rs:8:16 + | +LL | Ok(val) if make() => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match2.rs:15:24 + | +LL | Ok(val) => match val { + | ________________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_____________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match2.rs:15:16 + | +LL | Ok(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match2.rs:29:29 + | +LL | $pat => match $e { + | _____________________________^ +LL | | $inner_pat => $then, +LL | | _ => return, +LL | | }, + | |_____________________^ +... +LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); + | ------------------------------------------------- in this macro invocation + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match2.rs:41:28 + | +LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); + | ^^^ ^^^^^^^ with this pattern + | | + | Replace this binding + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 4cbc5630d759..e1ee8dbca2c0 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -1,5 +1,3 @@ -#[warn(clippy::str_to_string)] -#[warn(clippy::string_to_string)] #[warn(clippy::unstable_as_slice)] #[warn(clippy::unstable_as_mut_slice)] #[warn(clippy::misaligned_transmute)] diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index a348d01d734f..edbb891afe07 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -1,88 +1,76 @@ -error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated.rs:1:8 - | -LL | #[warn(clippy::str_to_string)] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` - -error: lint `clippy::string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated.rs:2:8 - | -LL | #[warn(clippy::string_to_string)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` - --> $DIR/deprecated.rs:3:8 + --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::unstable_as_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7` - --> $DIR/deprecated.rs:4:8 + --> $DIR/deprecated.rs:2:8 | LL | #[warn(clippy::unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr` - --> $DIR/deprecated.rs:5:8 + --> $DIR/deprecated.rs:3:8 | LL | #[warn(clippy::misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::unused_collect` has been removed: ``collect` has been marked as #[must_use] in rustc and that covers all cases of this lint` - --> $DIR/deprecated.rs:6:8 + --> $DIR/deprecated.rs:4:8 | LL | #[warn(clippy::unused_collect)] | ^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::invalid_ref` has been removed: `superseded by rustc lint `invalid_value`` - --> $DIR/deprecated.rs:7:8 + --> $DIR/deprecated.rs:5:8 | LL | #[warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ error: lint `clippy::into_iter_on_array` has been removed: `this lint has been uplifted to rustc and is now called `array_into_iter`` - --> $DIR/deprecated.rs:8:8 + --> $DIR/deprecated.rs:6:8 | LL | #[warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::unused_label` has been removed: `this lint has been uplifted to rustc and is now called `unused_labels`` - --> $DIR/deprecated.rs:9:8 + --> $DIR/deprecated.rs:7:8 | LL | #[warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::regex_macro` has been removed: `the regex! macro has been removed from the regex crate in 2018` - --> $DIR/deprecated.rs:10:8 + --> $DIR/deprecated.rs:8:8 | LL | #[warn(clippy::regex_macro)] | ^^^^^^^^^^^^^^^^^^^ error: lint `clippy::drop_bounds` has been removed: `this lint has been uplifted to rustc and is now called `drop_bounds`` - --> $DIR/deprecated.rs:11:8 + --> $DIR/deprecated.rs:9:8 | LL | #[warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ error: lint `clippy::temporary_cstring_as_ptr` has been removed: `this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`` - --> $DIR/deprecated.rs:12:8 + --> $DIR/deprecated.rs:10:8 | LL | #[warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::panic_params` has been removed: `this lint has been uplifted to rustc and is now called `panic_fmt`` - --> $DIR/deprecated.rs:13:8 + --> $DIR/deprecated.rs:11:8 | LL | #[warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` +error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` --> $DIR/deprecated.rs:1:8 | -LL | #[warn(clippy::str_to_string)] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[warn(clippy::unstable_as_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/deprecated_old.rs b/tests/ui/deprecated_old.rs index 2e5c5b7ead12..e89dca4fcfd4 100644 --- a/tests/ui/deprecated_old.rs +++ b/tests/ui/deprecated_old.rs @@ -1,5 +1,3 @@ -#[warn(str_to_string)] -#[warn(string_to_string)] #[warn(unstable_as_slice)] #[warn(unstable_as_mut_slice)] #[warn(misaligned_transmute)] diff --git a/tests/ui/deprecated_old.stderr b/tests/ui/deprecated_old.stderr index ff3e9e8fcf36..2fe1facf0c72 100644 --- a/tests/ui/deprecated_old.stderr +++ b/tests/ui/deprecated_old.stderr @@ -1,40 +1,28 @@ -error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated_old.rs:1:8 - | -LL | #[warn(str_to_string)] - | ^^^^^^^^^^^^^ - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` - -error: lint `string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated_old.rs:2:8 - | -LL | #[warn(string_to_string)] - | ^^^^^^^^^^^^^^^^ - error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` - --> $DIR/deprecated_old.rs:3:8 + --> $DIR/deprecated_old.rs:1:8 | LL | #[warn(unstable_as_slice)] | ^^^^^^^^^^^^^^^^^ + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7` - --> $DIR/deprecated_old.rs:4:8 + --> $DIR/deprecated_old.rs:2:8 | LL | #[warn(unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^ error: lint `misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr` - --> $DIR/deprecated_old.rs:5:8 + --> $DIR/deprecated_old.rs:3:8 | LL | #[warn(misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^ -error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` +error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` --> $DIR/deprecated_old.rs:1:8 | -LL | #[warn(str_to_string)] - | ^^^^^^^^^^^^^ +LL | #[warn(unstable_as_slice)] + | ^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index 4e09d19ea214..7ab23320db6d 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -86,3 +86,12 @@ fn check_ignore_macro() { // checks if the lint ignores macros with `!` operator !bool_macro!(1) && !bool_macro!(""); } + +struct Nested { + inner: ((i32,), (i32,), (i32,)), +} + +fn check_nested(n1: &Nested, n2: &Nested) -> bool { + // `n2.inner.0.0` mistyped as `n1.inner.0.0` + (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 +} diff --git a/tests/ui/eq_op.stderr b/tests/ui/eq_op.stderr index ad81b35a7664..8ef658af8df4 100644 --- a/tests/ui/eq_op.stderr +++ b/tests/ui/eq_op.stderr @@ -162,5 +162,13 @@ error: equal expressions as operands to `/` LL | const D: u32 = A / A; | ^^^^^ -error: aborting due to 27 previous errors +error: equal expressions as operands to `==` + --> $DIR/eq_op.rs:96:5 + | +LL | (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::eq_op)]` on by default + +error: aborting due to 28 previous errors diff --git a/tests/ui/item_after_statement.rs b/tests/ui/item_after_statement.rs index 377e58e44174..d439ca1e4e1a 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/item_after_statement.rs @@ -37,3 +37,16 @@ fn mac() { b!(); println!("{}", a); } + +fn semicolon() { + struct S { + a: u32, + }; + impl S { + fn new(a: u32) -> Self { + Self { a } + } + } + + let _ = S::new(3); +} diff --git a/tests/ui/map_err.rs b/tests/ui/map_err.rs index 05b9949f1021..00e037843f8c 100644 --- a/tests/ui/map_err.rs +++ b/tests/ui/map_err.rs @@ -22,5 +22,9 @@ fn main() -> Result<(), Errors> { println!("{:?}", x.map_err(|_| Errors::Ignored)); + // Should not warn you because you explicitly ignore the parameter + // using a named wildcard value + println!("{:?}", x.map_err(|_foo| Errors::Ignored)); + Ok(()) } diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index 390d7ce2e4e7..8ee2941790d3 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -1,11 +1,11 @@ -error: `map_err(|_|...` ignores the original error +error: `map_err(|_|...` wildcard pattern discards the original error --> $DIR/map_err.rs:23:32 | LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | ^^^ | = note: `-D clippy::map-err-ignore` implied by `-D warnings` - = help: Consider wrapping the error in an enum variant + = help: Consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`) error: aborting due to previous error diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs new file mode 100644 index 000000000000..1026cc40d3b0 --- /dev/null +++ b/tests/ui/min_rust_version_attr.rs @@ -0,0 +1,87 @@ +#![allow(clippy::redundant_clone)] +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.0.0"] + +use std::ops::Deref; + +fn option_as_ref_deref() { + let mut opt = Some(String::from("123")); + + let _ = opt.as_ref().map(String::as_str); + let _ = opt.as_ref().map(|x| x.as_str()); + let _ = opt.as_mut().map(String::as_mut_str); + let _ = opt.as_mut().map(|x| x.as_mut_str()); +} + +fn match_like_matches() { + let _y = match Some(5) { + Some(0) => true, + _ => false, + }; +} + +fn match_same_arms() { + match (1, 2, 3) { + (1, .., 3) => 42, + (.., 3) => 42, //~ ERROR match arms have same body + _ => 0, + }; +} + +fn match_same_arms2() { + let _ = match Some(42) { + Some(_) => 24, + None => 24, //~ ERROR match arms have same body + }; +} + +pub fn manual_strip_msrv() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } +} + +fn main() { + option_as_ref_deref(); + match_like_matches(); + match_same_arms(); + match_same_arms2(); + manual_strip_msrv(); +} + +mod meets_msrv { + #![feature(custom_inner_attributes)] + #![clippy::msrv = "1.45.0"] + + fn main() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } + } +} + +mod just_under_msrv { + #![feature(custom_inner_attributes)] + #![clippy::msrv = "1.46.0"] + + fn main() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } + } +} + +mod just_above_msrv { + #![feature(custom_inner_attributes)] + #![clippy::msrv = "1.44.0"] + + fn main() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } + } +} diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr new file mode 100644 index 000000000000..3e1af046e7a2 --- /dev/null +++ b/tests/ui/min_rust_version_attr.stderr @@ -0,0 +1,37 @@ +error: stripping a prefix manually + --> $DIR/min_rust_version_attr.rs:60:24 + | +LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::manual-strip` implied by `-D warnings` +note: the prefix was tested here + --> $DIR/min_rust_version_attr.rs:59:9 + | +LL | if s.starts_with("hello, ") { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix("hello, ") { +LL | assert_eq!(.to_uppercase(), "WORLD!"); + | + +error: stripping a prefix manually + --> $DIR/min_rust_version_attr.rs:72:24 + | +LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the prefix was tested here + --> $DIR/min_rust_version_attr.rs:71:9 + | +LL | if s.starts_with("hello, ") { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix("hello, ") { +LL | assert_eq!(.to_uppercase(), "WORLD!"); + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/min_rust_version_invalid_attr.rs b/tests/ui/min_rust_version_invalid_attr.rs new file mode 100644 index 000000000000..f20841891a74 --- /dev/null +++ b/tests/ui/min_rust_version_invalid_attr.rs @@ -0,0 +1,4 @@ +#![feature(custom_inner_attributes)] +#![clippy::msrv = "invalid.version"] + +fn main() {} diff --git a/tests/ui/min_rust_version_invalid_attr.stderr b/tests/ui/min_rust_version_invalid_attr.stderr new file mode 100644 index 000000000000..6ff88ca56f8b --- /dev/null +++ b/tests/ui/min_rust_version_invalid_attr.stderr @@ -0,0 +1,8 @@ +error: `invalid.version` is not a valid Rust version + --> $DIR/min_rust_version_invalid_attr.rs:2:1 + | +LL | #![clippy::msrv = "invalid.version"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/min_rust_version_multiple_inner_attr.rs b/tests/ui/min_rust_version_multiple_inner_attr.rs new file mode 100644 index 000000000000..e882d5ccf91a --- /dev/null +++ b/tests/ui/min_rust_version_multiple_inner_attr.rs @@ -0,0 +1,11 @@ +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.40"] +#![clippy::msrv = "=1.35.0"] +#![clippy::msrv = "1.10.1"] + +mod foo { + #![clippy::msrv = "1"] + #![clippy::msrv = "1.0.0"] +} + +fn main() {} diff --git a/tests/ui/min_rust_version_multiple_inner_attr.stderr b/tests/ui/min_rust_version_multiple_inner_attr.stderr new file mode 100644 index 000000000000..e3ff6605cde8 --- /dev/null +++ b/tests/ui/min_rust_version_multiple_inner_attr.stderr @@ -0,0 +1,38 @@ +error: `msrv` is defined multiple times + --> $DIR/min_rust_version_multiple_inner_attr.rs:3:1 + | +LL | #![clippy::msrv = "=1.35.0"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first definition found here + --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1 + | +LL | #![clippy::msrv = "1.40"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `msrv` is defined multiple times + --> $DIR/min_rust_version_multiple_inner_attr.rs:4:1 + | +LL | #![clippy::msrv = "1.10.1"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first definition found here + --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1 + | +LL | #![clippy::msrv = "1.40"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `msrv` is defined multiple times + --> $DIR/min_rust_version_multiple_inner_attr.rs:8:5 + | +LL | #![clippy::msrv = "1.0.0"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first definition found here + --> $DIR/min_rust_version_multiple_inner_attr.rs:7:5 + | +LL | #![clippy::msrv = "1"] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/min_rust_version_no_patch.rs b/tests/ui/min_rust_version_no_patch.rs new file mode 100644 index 000000000000..98fffe1e3512 --- /dev/null +++ b/tests/ui/min_rust_version_no_patch.rs @@ -0,0 +1,14 @@ +#![allow(clippy::redundant_clone)] +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.0"] + +fn manual_strip_msrv() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } +} + +fn main() { + manual_strip_msrv() +} diff --git a/tests/ui/min_rust_version_outer_attr.rs b/tests/ui/min_rust_version_outer_attr.rs new file mode 100644 index 000000000000..551948bd72ef --- /dev/null +++ b/tests/ui/min_rust_version_outer_attr.rs @@ -0,0 +1,4 @@ +#![feature(custom_inner_attributes)] + +#[clippy::msrv = "invalid.version"] +fn main() {} diff --git a/tests/ui/min_rust_version_outer_attr.stderr b/tests/ui/min_rust_version_outer_attr.stderr new file mode 100644 index 000000000000..579ee7a87d23 --- /dev/null +++ b/tests/ui/min_rust_version_outer_attr.stderr @@ -0,0 +1,8 @@ +error: `msrv` cannot be an outer attribute + --> $DIR/min_rust_version_outer_attr.rs:3:1 + | +LL | #[clippy::msrv = "invalid.version"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/modulo_one.rs b/tests/ui/modulo_one.rs index cc8c8e7cdaef..678a312f66e5 100644 --- a/tests/ui/modulo_one.rs +++ b/tests/ui/modulo_one.rs @@ -2,13 +2,22 @@ #![allow(clippy::no_effect, clippy::unnecessary_operation)] static STATIC_ONE: usize = 2 - 1; +static STATIC_NEG_ONE: i64 = 1 - 2; fn main() { 10 % 1; + 10 % -1; 10 % 2; + i32::MIN % (-1); // also caught by rustc const ONE: u32 = 1 * 1; + const NEG_ONE: i64 = 1 - 2; + const INT_MIN: i64 = i64::MIN; 2 % ONE; - 5 % STATIC_ONE; + 5 % STATIC_ONE; // NOT caught by lint + 2 % NEG_ONE; + 5 % STATIC_NEG_ONE; // NOT caught by lint + INT_MIN % NEG_ONE; // also caught by rustc + INT_MIN % STATIC_NEG_ONE; // ONLY caught by rustc } diff --git a/tests/ui/modulo_one.stderr b/tests/ui/modulo_one.stderr index 6bee68360b6f..2b2c69973385 100644 --- a/tests/ui/modulo_one.stderr +++ b/tests/ui/modulo_one.stderr @@ -1,13 +1,45 @@ +error: this arithmetic operation will overflow + --> $DIR/modulo_one.rs:11:5 + | +LL | i32::MIN % (-1); // also caught by rustc + | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/modulo_one.rs:21:5 + | +LL | INT_MIN % NEG_ONE; // also caught by rustc + | ^^^^^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/modulo_one.rs:22:5 + | +LL | INT_MIN % STATIC_NEG_ONE; // ONLY caught by rustc + | ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow + error: any number modulo 1 will be 0 - --> $DIR/modulo_one.rs:7:5 + --> $DIR/modulo_one.rs:8:5 | LL | 10 % 1; | ^^^^^^ | = note: `-D clippy::modulo-one` implied by `-D warnings` +error: any number modulo -1 will panic/overflow or result in 0 + --> $DIR/modulo_one.rs:9:5 + | +LL | 10 % -1; + | ^^^^^^^ + +error: any number modulo -1 will panic/overflow or result in 0 + --> $DIR/modulo_one.rs:11:5 + | +LL | i32::MIN % (-1); // also caught by rustc + | ^^^^^^^^^^^^^^^ + error: the operation is ineffective. Consider reducing it to `1` - --> $DIR/modulo_one.rs:10:22 + --> $DIR/modulo_one.rs:13:22 | LL | const ONE: u32 = 1 * 1; | ^^^^^ @@ -15,16 +47,28 @@ LL | const ONE: u32 = 1 * 1; = note: `-D clippy::identity-op` implied by `-D warnings` error: the operation is ineffective. Consider reducing it to `1` - --> $DIR/modulo_one.rs:10:22 + --> $DIR/modulo_one.rs:13:22 | LL | const ONE: u32 = 1 * 1; | ^^^^^ error: any number modulo 1 will be 0 - --> $DIR/modulo_one.rs:12:5 + --> $DIR/modulo_one.rs:17:5 | LL | 2 % ONE; | ^^^^^^^ -error: aborting due to 4 previous errors +error: any number modulo -1 will panic/overflow or result in 0 + --> $DIR/modulo_one.rs:19:5 + | +LL | 2 % NEG_ONE; + | ^^^^^^^^^^^ + +error: any number modulo -1 will panic/overflow or result in 0 + --> $DIR/modulo_one.rs:21:5 + | +LL | INT_MIN % NEG_ONE; // also caught by rustc + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors diff --git a/tests/ui/needless_collect_indirect.rs b/tests/ui/needless_collect_indirect.rs index 4f6e53577273..0918a6868ab4 100644 --- a/tests/ui/needless_collect_indirect.rs +++ b/tests/ui/needless_collect_indirect.rs @@ -22,4 +22,24 @@ fn main() { let sample = vec![a.clone(), "b".to_string(), "c".to_string()]; let non_copy_contains = sample.into_iter().collect::>(); non_copy_contains.contains(&a); + + // Fix #5991 + let vec_a = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let vec_b = vec_a.iter().collect::>(); + if vec_b.len() > 3 {} + let other_vec = vec![1, 3, 12, 4, 16, 2]; + let we_got_the_same_numbers = other_vec.iter().filter(|item| vec_b.contains(item)).collect::>(); + + // Fix #6297 + let sample = [1; 5]; + let multiple_indirect = sample.iter().collect::>(); + let sample2 = vec![2, 3]; + if multiple_indirect.is_empty() { + // do something + } else { + let found = sample2 + .iter() + .filter(|i| multiple_indirect.iter().any(|s| **s % **i == 0)) + .collect::>(); + } } diff --git a/tests/ui/panicking_macros.stderr b/tests/ui/panicking_macros.stderr index 83234c0ed92c..6028323a3c84 100644 --- a/tests/ui/panicking_macros.stderr +++ b/tests/ui/panicking_macros.stderr @@ -62,7 +62,7 @@ error: `unimplemented` should not be present in production code LL | unimplemented!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `unreachable` should not be present in production code +error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:32:5 | LL | unreachable!(); @@ -70,7 +70,7 @@ LL | unreachable!(); | = note: `-D clippy::unreachable` implied by `-D warnings` -error: `unreachable` should not be present in production code +error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:33:5 | LL | unreachable!("message"); @@ -78,7 +78,7 @@ LL | unreachable!("message"); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: `unreachable` should not be present in production code +error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:34:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); @@ -102,7 +102,7 @@ error: `unimplemented` should not be present in production code LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ -error: `unreachable` should not be present in production code +error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:43:5 | LL | unreachable!(); diff --git a/tests/ui/redundant_pattern_matching_ipaddr.fixed b/tests/ui/redundant_pattern_matching_ipaddr.fixed new file mode 100644 index 000000000000..acc8de5f41ee --- /dev/null +++ b/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -0,0 +1,73 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] + +use std::net::{ + IpAddr::{self, V4, V6}, + Ipv4Addr, Ipv6Addr, +}; + +fn main() { + let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST); + if ipaddr.is_ipv4() {} + + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + while V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + while V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + if let V4(ipaddr) = V4(Ipv4Addr::LOCALHOST) { + println!("{}", ipaddr); + } + + V4(Ipv4Addr::LOCALHOST).is_ipv4(); + + V4(Ipv4Addr::LOCALHOST).is_ipv6(); + + V6(Ipv6Addr::LOCALHOST).is_ipv6(); + + V6(Ipv6Addr::LOCALHOST).is_ipv4(); + + let _ = if V4(Ipv4Addr::LOCALHOST).is_ipv4() { + true + } else { + false + }; + + ipaddr_const(); + + let _ = if gen_ipaddr().is_ipv4() { + 1 + } else if gen_ipaddr().is_ipv6() { + 2 + } else { + 3 + }; +} + +fn gen_ipaddr() -> IpAddr { + V4(Ipv4Addr::LOCALHOST) +} + +const fn ipaddr_const() { + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + while V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + while V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + V4(Ipv4Addr::LOCALHOST).is_ipv4(); + + V6(Ipv6Addr::LOCALHOST).is_ipv6(); +} diff --git a/tests/ui/redundant_pattern_matching_ipaddr.rs b/tests/ui/redundant_pattern_matching_ipaddr.rs new file mode 100644 index 000000000000..678d91ce93ac --- /dev/null +++ b/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -0,0 +1,91 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] + +use std::net::{ + IpAddr::{self, V4, V6}, + Ipv4Addr, Ipv6Addr, +}; + +fn main() { + let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST); + if let V4(_) = &ipaddr {} + + if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + + if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + + while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + + while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + if let V4(ipaddr) = V4(Ipv4Addr::LOCALHOST) { + println!("{}", ipaddr); + } + + match V4(Ipv4Addr::LOCALHOST) { + V4(_) => true, + V6(_) => false, + }; + + match V4(Ipv4Addr::LOCALHOST) { + V4(_) => false, + V6(_) => true, + }; + + match V6(Ipv6Addr::LOCALHOST) { + V4(_) => false, + V6(_) => true, + }; + + match V6(Ipv6Addr::LOCALHOST) { + V4(_) => true, + V6(_) => false, + }; + + let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { + true + } else { + false + }; + + ipaddr_const(); + + let _ = if let V4(_) = gen_ipaddr() { + 1 + } else if let V6(_) = gen_ipaddr() { + 2 + } else { + 3 + }; +} + +fn gen_ipaddr() -> IpAddr { + V4(Ipv4Addr::LOCALHOST) +} + +const fn ipaddr_const() { + if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + + if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + + while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + + while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + + match V4(Ipv4Addr::LOCALHOST) { + V4(_) => true, + V6(_) => false, + }; + + match V6(Ipv6Addr::LOCALHOST) { + V4(_) => false, + V6(_) => true, + }; +} diff --git a/tests/ui/redundant_pattern_matching_ipaddr.stderr b/tests/ui/redundant_pattern_matching_ipaddr.stderr new file mode 100644 index 000000000000..caf458cd862e --- /dev/null +++ b/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -0,0 +1,130 @@ +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:14:12 + | +LL | if let V4(_) = &ipaddr {} + | -------^^^^^---------- help: try this: `if ipaddr.is_ipv4()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:16:12 + | +LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12 + | +LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:20:15 + | +LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:22:15 + | +LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:32:5 + | +LL | / match V4(Ipv4Addr::LOCALHOST) { +LL | | V4(_) => true, +LL | | V6(_) => false, +LL | | }; + | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:37:5 + | +LL | / match V4(Ipv4Addr::LOCALHOST) { +LL | | V4(_) => false, +LL | | V6(_) => true, +LL | | }; + | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:42:5 + | +LL | / match V6(Ipv6Addr::LOCALHOST) { +LL | | V4(_) => false, +LL | | V6(_) => true, +LL | | }; + | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:47:5 + | +LL | / match V6(Ipv6Addr::LOCALHOST) { +LL | | V4(_) => true, +LL | | V6(_) => false, +LL | | }; + | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:52:20 + | +LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { + | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:60:20 + | +LL | let _ = if let V4(_) = gen_ipaddr() { + | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:62:19 + | +LL | } else if let V6(_) = gen_ipaddr() { + | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:74:12 + | +LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:76:12 + | +LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:78:15 + | +LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:80:15 + | +LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:82:5 + | +LL | / match V4(Ipv4Addr::LOCALHOST) { +LL | | V4(_) => true, +LL | | V6(_) => false, +LL | | }; + | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:87:5 + | +LL | / match V6(Ipv6Addr::LOCALHOST) { +LL | | V4(_) => false, +LL | | V6(_) => true, +LL | | }; + | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: aborting due to 18 previous errors + diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 499b975b2bb4..66f580a0a683 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -2,13 +2,7 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow( - clippy::unit_arg, - unused_must_use, - clippy::needless_bool, - clippy::match_like_matches_macro, - deprecated -)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] fn main() { if None::<()>.is_none() {} @@ -43,8 +37,7 @@ fn main() { let _ = None::<()>.is_none(); let opt = Some(false); - let x = if opt.is_some() { true } else { false }; - takes_bool(x); + let _ = if opt.is_some() { true } else { false }; issue6067(); @@ -61,8 +54,6 @@ fn gen_opt() -> Option<()> { None } -fn takes_bool(_: bool) {} - fn foo() {} fn bar() {} diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 2a98435e7902..f18b27b8b95c 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -2,13 +2,7 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow( - clippy::unit_arg, - unused_must_use, - clippy::needless_bool, - clippy::match_like_matches_macro, - deprecated -)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] fn main() { if let None = None::<()> {} @@ -52,8 +46,7 @@ fn main() { }; let opt = Some(false); - let x = if let Some(_) = opt { true } else { false }; - takes_bool(x); + let _ = if let Some(_) = opt { true } else { false }; issue6067(); @@ -70,8 +63,6 @@ fn gen_opt() -> Option<()> { None } -fn takes_bool(_: bool) {} - fn foo() {} fn bar() {} diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index eebb34484913..58482a0ab70d 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:14:12 + --> $DIR/redundant_pattern_matching_option.rs:8:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` @@ -7,43 +7,43 @@ LL | if let None = None::<()> {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:16:12 + --> $DIR/redundant_pattern_matching_option.rs:10:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:18:12 + --> $DIR/redundant_pattern_matching_option.rs:12:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:24:15 + --> $DIR/redundant_pattern_matching_option.rs:18:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:26:15 + --> $DIR/redundant_pattern_matching_option.rs:20:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try this: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:28:15 + --> $DIR/redundant_pattern_matching_option.rs:22:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:31:15 + --> $DIR/redundant_pattern_matching_option.rs:25:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:39:5 + --> $DIR/redundant_pattern_matching_option.rs:33:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:44:5 + --> $DIR/redundant_pattern_matching_option.rs:38:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:49:13 + --> $DIR/redundant_pattern_matching_option.rs:43:13 | LL | let _ = match None::<()> { | _____________^ @@ -71,49 +71,49 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:55:20 + --> $DIR/redundant_pattern_matching_option.rs:49:20 | -LL | let x = if let Some(_) = opt { true } else { false }; +LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:60:20 + --> $DIR/redundant_pattern_matching_option.rs:53:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:62:19 + --> $DIR/redundant_pattern_matching_option.rs:55:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:83:12 + --> $DIR/redundant_pattern_matching_option.rs:74:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:85:12 + --> $DIR/redundant_pattern_matching_option.rs:76:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:87:15 + --> $DIR/redundant_pattern_matching_option.rs:78:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:89:15 + --> $DIR/redundant_pattern_matching_option.rs:80:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:91:5 + --> $DIR/redundant_pattern_matching_option.rs:82:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -122,7 +122,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:96:5 + --> $DIR/redundant_pattern_matching_option.rs:87:5 | LL | / match None::<()> { LL | | Some(_) => false, diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed new file mode 100644 index 000000000000..465aa80dac27 --- /dev/null +++ b/tests/ui/redundant_pattern_matching_poll.fixed @@ -0,0 +1,70 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] + +use std::task::Poll::{self, Pending, Ready}; + +fn main() { + if Pending::<()>.is_pending() {} + + if Ready(42).is_ready() {} + + if Ready(42).is_ready() { + foo(); + } else { + bar(); + } + + while Ready(42).is_ready() {} + + while Ready(42).is_pending() {} + + while Pending::<()>.is_pending() {} + + if Pending::.is_pending() {} + + if Ready(42).is_ready() {} + + Ready(42).is_ready(); + + Pending::<()>.is_pending(); + + let _ = Pending::<()>.is_pending(); + + let poll = Ready(false); + let _ = if poll.is_ready() { true } else { false }; + + poll_const(); + + let _ = if gen_poll().is_ready() { + 1 + } else if gen_poll().is_pending() { + 2 + } else { + 3 + }; +} + +fn gen_poll() -> Poll<()> { + Pending +} + +fn foo() {} + +fn bar() {} + +const fn poll_const() { + if Ready(42).is_ready() {} + + if Pending::<()>.is_pending() {} + + while Ready(42).is_ready() {} + + while Pending::<()>.is_pending() {} + + Ready(42).is_ready(); + + Pending::<()>.is_pending(); +} diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs new file mode 100644 index 000000000000..7891ff353b13 --- /dev/null +++ b/tests/ui/redundant_pattern_matching_poll.rs @@ -0,0 +1,85 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] + +use std::task::Poll::{self, Pending, Ready}; + +fn main() { + if let Pending = Pending::<()> {} + + if let Ready(_) = Ready(42) {} + + if let Ready(_) = Ready(42) { + foo(); + } else { + bar(); + } + + while let Ready(_) = Ready(42) {} + + while let Pending = Ready(42) {} + + while let Pending = Pending::<()> {} + + if Pending::.is_pending() {} + + if Ready(42).is_ready() {} + + match Ready(42) { + Ready(_) => true, + Pending => false, + }; + + match Pending::<()> { + Ready(_) => false, + Pending => true, + }; + + let _ = match Pending::<()> { + Ready(_) => false, + Pending => true, + }; + + let poll = Ready(false); + let _ = if let Ready(_) = poll { true } else { false }; + + poll_const(); + + let _ = if let Ready(_) = gen_poll() { + 1 + } else if let Pending = gen_poll() { + 2 + } else { + 3 + }; +} + +fn gen_poll() -> Poll<()> { + Pending +} + +fn foo() {} + +fn bar() {} + +const fn poll_const() { + if let Ready(_) = Ready(42) {} + + if let Pending = Pending::<()> {} + + while let Ready(_) = Ready(42) {} + + while let Pending = Pending::<()> {} + + match Ready(42) { + Ready(_) => true, + Pending => false, + }; + + match Pending::<()> { + Ready(_) => false, + Pending => true, + }; +} diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr new file mode 100644 index 000000000000..5ffc6c47c90a --- /dev/null +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -0,0 +1,128 @@ +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:10:12 + | +LL | if let Pending = Pending::<()> {} + | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:12:12 + | +LL | if let Ready(_) = Ready(42) {} + | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:14:12 + | +LL | if let Ready(_) = Ready(42) { + | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:20:15 + | +LL | while let Ready(_) = Ready(42) {} + | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:22:15 + | +LL | while let Pending = Ready(42) {} + | ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:24:15 + | +LL | while let Pending = Pending::<()> {} + | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:30:5 + | +LL | / match Ready(42) { +LL | | Ready(_) => true, +LL | | Pending => false, +LL | | }; + | |_____^ help: try this: `Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:35:5 + | +LL | / match Pending::<()> { +LL | | Ready(_) => false, +LL | | Pending => true, +LL | | }; + | |_____^ help: try this: `Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:40:13 + | +LL | let _ = match Pending::<()> { + | _____________^ +LL | | Ready(_) => false, +LL | | Pending => true, +LL | | }; + | |_____^ help: try this: `Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:46:20 + | +LL | let _ = if let Ready(_) = poll { true } else { false }; + | -------^^^^^^^^------- help: try this: `if poll.is_ready()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:50:20 + | +LL | let _ = if let Ready(_) = gen_poll() { + | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:52:19 + | +LL | } else if let Pending = gen_poll() { + | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:68:12 + | +LL | if let Ready(_) = Ready(42) {} + | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:70:12 + | +LL | if let Pending = Pending::<()> {} + | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:72:15 + | +LL | while let Ready(_) = Ready(42) {} + | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:74:15 + | +LL | while let Pending = Pending::<()> {} + | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:76:5 + | +LL | / match Ready(42) { +LL | | Ready(_) => true, +LL | | Pending => false, +LL | | }; + | |_____^ help: try this: `Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:81:5 + | +LL | / match Pending::<()> { +LL | | Ready(_) => false, +LL | | Pending => true, +LL | | }; + | |_____^ help: try this: `Pending::<()>.is_pending()` + +error: aborting due to 18 previous errors + diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching_result.fixed similarity index 98% rename from tests/ui/redundant_pattern_matching.fixed rename to tests/ui/redundant_pattern_matching_result.fixed index aa20512296aa..e94c5704b489 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -3,7 +3,6 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow( - clippy::unit_arg, unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching_result.rs similarity index 99% rename from tests/ui/redundant_pattern_matching.rs rename to tests/ui/redundant_pattern_matching_result.rs index d76f9c288ffd..5d1752942322 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -3,7 +3,6 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow( - clippy::unit_arg, unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching_result.stderr similarity index 80% rename from tests/ui/redundant_pattern_matching.stderr rename to tests/ui/redundant_pattern_matching_result.stderr index aeb309f5ba12..d6a46babb779 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:16:12 + --> $DIR/redundant_pattern_matching_result.rs:15:12 | LL | if let Ok(_) = &result {} | -------^^^^^---------- help: try this: `if result.is_ok()` @@ -7,31 +7,31 @@ LL | if let Ok(_) = &result {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:18:12 + --> $DIR/redundant_pattern_matching_result.rs:17:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:20:12 + --> $DIR/redundant_pattern_matching_result.rs:19:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:22:15 + --> $DIR/redundant_pattern_matching_result.rs:21:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:24:15 + --> $DIR/redundant_pattern_matching_result.rs:23:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:34:5 + --> $DIR/redundant_pattern_matching_result.rs:33:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:39:5 + --> $DIR/redundant_pattern_matching_result.rs:38:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:44:5 + --> $DIR/redundant_pattern_matching_result.rs:43:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:49:5 + --> $DIR/redundant_pattern_matching_result.rs:48:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -67,73 +67,73 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:54:20 + --> $DIR/redundant_pattern_matching_result.rs:53:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:60:20 + --> $DIR/redundant_pattern_matching_result.rs:59:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:62:19 + --> $DIR/redundant_pattern_matching_result.rs:61:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:85:19 + --> $DIR/redundant_pattern_matching_result.rs:84:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:86:16 + --> $DIR/redundant_pattern_matching_result.rs:85:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:92:12 + --> $DIR/redundant_pattern_matching_result.rs:91:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:93:15 + --> $DIR/redundant_pattern_matching_result.rs:92:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:111:12 + --> $DIR/redundant_pattern_matching_result.rs:110:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:113:12 + --> $DIR/redundant_pattern_matching_result.rs:112:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:115:15 + --> $DIR/redundant_pattern_matching_result.rs:114:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:117:15 + --> $DIR/redundant_pattern_matching_result.rs:116:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:119:5 + --> $DIR/redundant_pattern_matching_result.rs:118:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:124:5 + --> $DIR/redundant_pattern_matching_result.rs:123:5 | LL | / match Err::(42) { LL | | Ok(_) => false, diff --git a/tests/ui/size_of_in_element_count.rs b/tests/ui/size_of_in_element_count.rs new file mode 100644 index 000000000000..b13e390705ab --- /dev/null +++ b/tests/ui/size_of_in_element_count.rs @@ -0,0 +1,61 @@ +#![warn(clippy::size_of_in_element_count)] +#![allow(clippy::ptr_offset_with_cast)] + +use std::mem::{size_of, size_of_val}; +use std::ptr::{ + copy, copy_nonoverlapping, slice_from_raw_parts, slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, +}; +use std::slice::{from_raw_parts, from_raw_parts_mut}; + +fn main() { + const SIZE: usize = 128; + const HALF_SIZE: usize = SIZE / 2; + const DOUBLE_SIZE: usize = SIZE * 2; + let mut x = [2u8; SIZE]; + let mut y = [2u8; SIZE]; + + // Count is size_of (Should trigger the lint) + unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + + unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; + unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; + unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; + unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + + unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; + unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; + + unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; + + slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); + slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); + + unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + + unsafe { y.as_mut_ptr().sub(size_of::()) }; + y.as_ptr().wrapping_sub(size_of::()); + unsafe { y.as_ptr().add(size_of::()) }; + y.as_mut_ptr().wrapping_add(size_of::()); + unsafe { y.as_ptr().offset(size_of::() as isize) }; + y.as_mut_ptr().wrapping_offset(size_of::() as isize); + + // Count expression involving multiplication of size_of (Should trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + + // Count expression involving nested multiplications of size_of (Should trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; + + // Count expression involving divisions of size_of (Should trigger the lint) + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; + + // No size_of calls (Should not trigger the lint) + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; + + // Different types for pointee and size_of (Should not trigger the lint) + unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() / 2 * SIZE) }; +} diff --git a/tests/ui/size_of_in_element_count.stderr b/tests/ui/size_of_in_element_count.stderr new file mode 100644 index 000000000000..8cf3612abda3 --- /dev/null +++ b/tests/ui/size_of_in_element_count.stderr @@ -0,0 +1,195 @@ +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:18:68 + | +LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:19:62 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:21:49 + | +LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:22:64 + | +LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:23:51 + | +LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:24:66 + | +LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:26:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:27:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:29:46 + | +LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:30:47 + | +LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:32:66 + | +LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:34:46 + | +LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:35:38 + | +LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:37:49 + | +LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:38:41 + | +LL | unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:40:33 + | +LL | unsafe { y.as_mut_ptr().sub(size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:41:29 + | +LL | y.as_ptr().wrapping_sub(size_of::()); + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:42:29 + | +LL | unsafe { y.as_ptr().add(size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:43:33 + | +LL | y.as_mut_ptr().wrapping_add(size_of::()); + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:44:32 + | +LL | unsafe { y.as_ptr().offset(size_of::() as isize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:45:36 + | +LL | y.as_mut_ptr().wrapping_offset(size_of::() as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:48:62 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:51:62 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/size_of_in_element_count.rs:54:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: aborting due to 24 previous errors + diff --git a/tests/ui/str_to_string.rs b/tests/ui/str_to_string.rs new file mode 100644 index 000000000000..08f734025181 --- /dev/null +++ b/tests/ui/str_to_string.rs @@ -0,0 +1,7 @@ +#![warn(clippy::str_to_string)] + +fn main() { + let hello = "hello world".to_string(); + let msg = &hello[..]; + msg.to_string(); +} diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr new file mode 100644 index 000000000000..b1f73eda5d26 --- /dev/null +++ b/tests/ui/str_to_string.stderr @@ -0,0 +1,19 @@ +error: `to_string()` called on a `&str` + --> $DIR/str_to_string.rs:4:17 + | +LL | let hello = "hello world".to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::str-to-string` implied by `-D warnings` + = help: consider using `.to_owned()` + +error: `to_string()` called on a `&str` + --> $DIR/str_to_string.rs:6:5 + | +LL | msg.to_string(); + | ^^^^^^^^^^^^^^^ + | + = help: consider using `.to_owned()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/string_to_string.rs b/tests/ui/string_to_string.rs new file mode 100644 index 000000000000..4c66855f7094 --- /dev/null +++ b/tests/ui/string_to_string.rs @@ -0,0 +1,7 @@ +#![warn(clippy::string_to_string)] +#![allow(clippy::redundant_clone)] + +fn main() { + let mut message = String::from("Hello"); + let mut v = message.to_string(); +} diff --git a/tests/ui/string_to_string.stderr b/tests/ui/string_to_string.stderr new file mode 100644 index 000000000000..1ebd17999bd8 --- /dev/null +++ b/tests/ui/string_to_string.stderr @@ -0,0 +1,11 @@ +error: `to_string()` called on a `String` + --> $DIR/string_to_string.rs:6:17 + | +LL | let mut v = message.to_string(); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::string-to-string` implied by `-D warnings` + = help: consider using `.clone()` + +error: aborting due to previous error + diff --git a/tests/ui/suspicious_operation_groupings.rs b/tests/ui/suspicious_operation_groupings.rs new file mode 100644 index 000000000000..dd6f4ec7bd9b --- /dev/null +++ b/tests/ui/suspicious_operation_groupings.rs @@ -0,0 +1,207 @@ +#![warn(clippy::suspicious_operation_groupings)] + +struct Vec3 { + x: f64, + y: f64, + z: f64, +} + +impl Eq for Vec3 {} + +impl PartialEq for Vec3 { + fn eq(&self, other: &Self) -> bool { + // This should trigger the lint because `self.x` is compared to `other.y` + self.x == other.y && self.y == other.y && self.z == other.z + } +} + +struct S { + a: i32, + b: i32, + c: i32, + d: i32, +} + +fn buggy_ab_cmp(s1: &S, s2: &S) -> bool { + // There's no `s1.b` + s1.a < s2.a && s1.a < s2.b +} + +struct SAOnly { + a: i32, +} + +impl S { + fn a(&self) -> i32 { + 0 + } +} + +fn do_not_give_bad_suggestions_for_this_unusual_expr(s1: &S, s2: &SAOnly) -> bool { + // This is superficially similar to `buggy_ab_cmp`, but we should not suggest + // `s2.b` since that is invalid. + s1.a < s2.a && s1.a() < s1.b +} + +fn do_not_give_bad_suggestions_for_this_macro_expr(s1: &S, s2: &SAOnly) -> bool { + macro_rules! s1 { + () => { + S { + a: 1, + b: 1, + c: 1, + d: 1, + } + }; + } + + // This is superficially similar to `buggy_ab_cmp`, but we should not suggest + // `s2.b` since that is invalid. + s1.a < s2.a && s1!().a < s1.b +} + +fn do_not_give_bad_suggestions_for_this_incorrect_expr(s1: &S, s2: &SAOnly) -> bool { + // There's two `s1.b`, but we should not suggest `s2.b` since that is invalid + s1.a < s2.a && s1.b < s1.b +} + +fn permissable(s1: &S, s2: &S) -> bool { + // Something like this seems like it might actually be what is desired. + s1.a == s2.b +} + +fn non_boolean_operators(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d +} + +fn odd_number_of_pairs(s1: &S, s2: &S) -> i32 { + // There's no `s2.b` + s1.a * s2.a + s1.b * s2.c + s1.c * s2.c +} + +fn not_caught_by_eq_op_middle_change_left(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + s1.a * s2.a + s2.b * s2.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_middle_change_right(s1: &S, s2: &S) -> i32 { + // There's no `s2.b` + s1.a * s2.a + s1.b * s1.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_start(s1: &S, s2: &S) -> i32 { + // There's no `s2.a` + s1.a * s1.a + s1.b * s2.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_end(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + s1.a * s2.a + s1.b * s2.b + s1.c * s1.c +} + +fn the_cross_product_should_not_lint(s1: &S, s2: &S) -> (i32, i32, i32) { + ( + s1.b * s2.c - s1.c * s2.b, + s1.c * s2.a - s1.a * s2.c, + s1.a * s2.b - s1.b * s2.a, + ) +} + +fn outer_parens_simple(s1: &S, s2: &S) -> i32 { + // There's no `s2.b` + (s1.a * s2.a + s1.b * s1.b) +} + +fn outer_parens(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) +} + +fn inner_parens(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) +} + +fn outer_and_some_inner_parens(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) +} + +fn all_parens_balanced_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) +} + +fn all_parens_left_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) +} + +fn all_parens_right_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) +} + +fn inside_other_binop_expression(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + (s1.a * s2.a + s2.b * s2.b) / 2 +} + +fn inside_function_call(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) +} + +fn inside_larger_boolean_expression(s1: &S, s2: &S) -> bool { + // There's no `s1.c` + s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d +} + +fn inside_larger_boolean_expression_with_unsorted_ops(s1: &S, s2: &S) -> bool { + // There's no `s1.c` + s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d +} + +struct Nested { + inner: ((i32,), (i32,), (i32,)), +} + +fn changed_middle_ident(n1: &Nested, n2: &Nested) -> bool { + // There's no `n2.inner.2.0` + (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 +} + +// `eq_op` should catch this one. +fn changed_initial_ident(n1: &Nested, n2: &Nested) -> bool { + // There's no `n2.inner.0.0` + (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 +} + +fn inside_fn_with_similar_expression(s1: &S, s2: &S, strict: bool) -> bool { + if strict { + s1.a < s2.a && s1.b < s2.b + } else { + // There's no `s1.b` in this subexpression + s1.a <= s2.a && s1.a <= s2.b + } +} + +fn inside_an_if_statement(s1: &S, s2: &S) { + // There's no `s1.b` + if s1.a < s2.a && s1.a < s2.b { + s1.c = s2.c; + } +} + +fn maximum_unary_minus_right_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) +} + +fn unary_minus_and_an_if_expression(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) +} + +fn main() {} diff --git a/tests/ui/suspicious_operation_groupings.stderr b/tests/ui/suspicious_operation_groupings.stderr new file mode 100644 index 000000000000..ce7108217f18 --- /dev/null +++ b/tests/ui/suspicious_operation_groupings.stderr @@ -0,0 +1,166 @@ +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:14:9 + | +LL | self.x == other.y && self.y == other.y && self.z == other.z + | ^^^^^^^^^^^^^^^^^ help: I think you meant: `self.x == other.x` + | + = note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:14:9 + | +LL | self.x == other.y && self.y == other.y && self.z == other.z + | ^^^^^^^^^^^^^^^^^ help: I think you meant: `self.x == other.x` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:27:20 + | +LL | s1.a < s2.a && s1.a < s2.b + | ^^^^^^^^^^^ help: I think you meant: `s1.b < s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:75:33 + | +LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:80:19 + | +LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:80:19 + | +LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:85:19 + | +LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:90:19 + | +LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:95:5 + | +LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.a * s2.a` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:100:33 + | +LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:113:20 + | +LL | (s1.a * s2.a + s1.b * s1.b) + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:118:34 + | +LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:123:38 + | +LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:128:39 + | +LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:133:42 + | +LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:133:42 + | +LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:138:40 + | +LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:143:40 + | +LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:148:20 + | +LL | (s1.a * s2.a + s2.b * s2.b) / 2 + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:153:35 + | +LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:158:29 + | +LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d + | ^^^^^^^^^^^^ help: I think you meant: `s1.c == s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:163:17 + | +LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d + | ^^^^^^^^^^^^ help: I think you meant: `s1.c == s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:172:77 + | +LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: I think you meant: `(n1.inner.2).0 == (n2.inner.2).0` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:186:25 + | +LL | s1.a <= s2.a && s1.a <= s2.b + | ^^^^^^^^^^^^ help: I think you meant: `s1.b <= s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:192:23 + | +LL | if s1.a < s2.a && s1.a < s2.b { + | ^^^^^^^^^^^ help: I think you meant: `s1.b < s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:199:48 + | +LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) + | ^^^^^^^^^^^^^ help: I think you meant: `-s1.c * -s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:204:27 + | +LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) + | ^^^^^^^^^^^^^ help: I think you meant: `-s1.b < -s2.b` + +error: aborting due to 27 previous errors + diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index df9b227eeb3f..e8f2fb466659 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -20,4 +20,7 @@ fn main() { foo!(a, i32); foo!(b, f32); foo!(c, f64); + + // do not lint cast to cfg-dependant type + 1 as std::os::raw::c_char; } diff --git a/tests/ui/unnecessary_cast_fixable.fixed b/tests/ui/unnecessary_cast_fixable.fixed index 350da4965d11..7fbce58a82f8 100644 --- a/tests/ui/unnecessary_cast_fixable.fixed +++ b/tests/ui/unnecessary_cast_fixable.fixed @@ -11,6 +11,8 @@ fn main() { let _ = -100_f32; let _ = -100_f64; let _ = -100_f64; + 100_f32; + 100_f64; // Should not trigger #[rustfmt::skip] let v = vec!(1); diff --git a/tests/ui/unnecessary_cast_fixable.rs b/tests/ui/unnecessary_cast_fixable.rs index ad2fb2e62892..a71363ea4d26 100644 --- a/tests/ui/unnecessary_cast_fixable.rs +++ b/tests/ui/unnecessary_cast_fixable.rs @@ -11,6 +11,8 @@ fn main() { let _ = -100 as f32; let _ = -100 as f64; let _ = -100_i32 as f64; + 100. as f32; + 100. as f64; // Should not trigger #[rustfmt::skip] let v = vec!(1); diff --git a/tests/ui/unnecessary_cast_fixable.stderr b/tests/ui/unnecessary_cast_fixable.stderr index 5a210fc89097..3695a8f819c4 100644 --- a/tests/ui/unnecessary_cast_fixable.stderr +++ b/tests/ui/unnecessary_cast_fixable.stderr @@ -36,59 +36,71 @@ error: casting integer literal to `f64` is unnecessary LL | let _ = -100_i32 as f64; | ^^^^^^^^^^^^^^^ help: try: `-100_f64` +error: casting float literal to `f32` is unnecessary + --> $DIR/unnecessary_cast_fixable.rs:14:5 + | +LL | 100. as f32; + | ^^^^^^^^^^^ help: try: `100_f32` + +error: casting float literal to `f64` is unnecessary + --> $DIR/unnecessary_cast_fixable.rs:15:5 + | +LL | 100. as f64; + | ^^^^^^^^^^^ help: try: `100_f64` + error: casting integer literal to `u32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:25:5 + --> $DIR/unnecessary_cast_fixable.rs:27:5 | LL | 1 as u32; | ^^^^^^^^ help: try: `1_u32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:26:5 + --> $DIR/unnecessary_cast_fixable.rs:28:5 | LL | 0x10 as i32; | ^^^^^^^^^^^ help: try: `0x10_i32` error: casting integer literal to `usize` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:27:5 + --> $DIR/unnecessary_cast_fixable.rs:29:5 | LL | 0b10 as usize; | ^^^^^^^^^^^^^ help: try: `0b10_usize` error: casting integer literal to `u16` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:28:5 + --> $DIR/unnecessary_cast_fixable.rs:30:5 | LL | 0o73 as u16; | ^^^^^^^^^^^ help: try: `0o73_u16` error: casting integer literal to `u32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:29:5 + --> $DIR/unnecessary_cast_fixable.rs:31:5 | LL | 1_000_000_000 as u32; | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` error: casting float literal to `f64` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:31:5 + --> $DIR/unnecessary_cast_fixable.rs:33:5 | LL | 1.0 as f64; | ^^^^^^^^^^ help: try: `1.0_f64` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:32:5 + --> $DIR/unnecessary_cast_fixable.rs:34:5 | LL | 0.5 as f32; | ^^^^^^^^^^ help: try: `0.5_f32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:36:13 + --> $DIR/unnecessary_cast_fixable.rs:38:13 | LL | let _ = -1 as i32; | ^^^^^^^^^ help: try: `-1_i32` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:37:13 + --> $DIR/unnecessary_cast_fixable.rs:39:13 | LL | let _ = -1.0 as f32; | ^^^^^^^^^^^ help: try: `-1.0_f32` -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/unnecessary_wraps.rs b/tests/ui/unnecessary_wraps.rs index a53dec8f91ac..a4570098d716 100644 --- a/tests/ui/unnecessary_wraps.rs +++ b/tests/ui/unnecessary_wraps.rs @@ -109,6 +109,13 @@ impl B for A { } } +fn issue_6384(s: &str) -> Option<&str> { + Some(match s { + "a" => "A", + _ => return None, + }) +} + fn main() { // method calls are not linted func1(true, true); diff --git a/tests/ui/unreadable_literal.fixed b/tests/ui/unreadable_literal.fixed index 4043d53299f6..c2e38037addd 100644 --- a/tests/ui/unreadable_literal.fixed +++ b/tests/ui/unreadable_literal.fixed @@ -10,6 +10,14 @@ macro_rules! foo { }; } +struct Bar(f32); + +macro_rules! bar { + () => { + Bar(100200300400.100200300400500) + }; +} + fn main() { let _good = ( 0b1011_i64, @@ -26,10 +34,12 @@ fn main() { let _good_sci = 1.1234e1; let _bad_sci = 1.123_456e1; - let _fail9 = 0x00ab_cdef; - let _fail10: u32 = 0xBAFE_BAFE; - let _fail11 = 0x0abc_deff; - let _fail12: i128 = 0x00ab_cabc_abca_bcab_cabc; + let _fail1 = 0x00ab_cdef; + let _fail2: u32 = 0xBAFE_BAFE; + let _fail3 = 0x0abc_deff; + let _fail4: i128 = 0x00ab_cabc_abca_bcab_cabc; + let _fail5 = 1.100_300_400; let _ = foo!(); + let _ = bar!(); } diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index e658a5f28c90..8296945b25eb 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -10,6 +10,14 @@ macro_rules! foo { }; } +struct Bar(f32); + +macro_rules! bar { + () => { + Bar(100200300400.100200300400500) + }; +} + fn main() { let _good = ( 0b1011_i64, @@ -26,10 +34,12 @@ fn main() { let _good_sci = 1.1234e1; let _bad_sci = 1.123456e1; - let _fail9 = 0xabcdef; - let _fail10: u32 = 0xBAFEBAFE; - let _fail11 = 0xabcdeff; - let _fail12: i128 = 0xabcabcabcabcabcabc; + let _fail1 = 0xabcdef; + let _fail2: u32 = 0xBAFEBAFE; + let _fail3 = 0xabcdeff; + let _fail4: i128 = 0xabcabcabcabcabcabc; + let _fail5 = 1.100300400; let _ = foo!(); + let _ = bar!(); } diff --git a/tests/ui/unreadable_literal.stderr b/tests/ui/unreadable_literal.stderr index 8645cabeabbb..8436aac17acf 100644 --- a/tests/ui/unreadable_literal.stderr +++ b/tests/ui/unreadable_literal.stderr @@ -1,5 +1,5 @@ error: digits of hex or binary literal not grouped by four - --> $DIR/unreadable_literal.rs:17:9 + --> $DIR/unreadable_literal.rs:25:9 | LL | 0x1_234_567, | ^^^^^^^^^^^ help: consider: `0x0123_4567` @@ -7,7 +7,7 @@ LL | 0x1_234_567, = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:25:17 + --> $DIR/unreadable_literal.rs:33:17 | LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `0b11_0110_i64` @@ -15,52 +15,58 @@ LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); = note: `-D clippy::unreadable-literal` implied by `-D warnings` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:25:31 + --> $DIR/unreadable_literal.rs:33:31 | LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^^^^^ help: consider: `0xcafe_babe_usize` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:25:49 + --> $DIR/unreadable_literal.rs:33:49 | LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^ help: consider: `123_456_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:25:61 + --> $DIR/unreadable_literal.rs:33:61 | LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `1.234_567_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:27:20 + --> $DIR/unreadable_literal.rs:35:20 | LL | let _bad_sci = 1.123456e1; | ^^^^^^^^^^ help: consider: `1.123_456e1` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:29:18 + --> $DIR/unreadable_literal.rs:37:18 | -LL | let _fail9 = 0xabcdef; +LL | let _fail1 = 0xabcdef; | ^^^^^^^^ help: consider: `0x00ab_cdef` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:30:24 + --> $DIR/unreadable_literal.rs:38:23 | -LL | let _fail10: u32 = 0xBAFEBAFE; - | ^^^^^^^^^^ help: consider: `0xBAFE_BAFE` +LL | let _fail2: u32 = 0xBAFEBAFE; + | ^^^^^^^^^^ help: consider: `0xBAFE_BAFE` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:31:19 + --> $DIR/unreadable_literal.rs:39:18 | -LL | let _fail11 = 0xabcdeff; - | ^^^^^^^^^ help: consider: `0x0abc_deff` +LL | let _fail3 = 0xabcdeff; + | ^^^^^^^^^ help: consider: `0x0abc_deff` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:32:25 + --> $DIR/unreadable_literal.rs:40:24 | -LL | let _fail12: i128 = 0xabcabcabcabcabcabc; - | ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc` +LL | let _fail4: i128 = 0xabcabcabcabcabcabc; + | ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc` -error: aborting due to 10 previous errors +error: long literal lacking separators + --> $DIR/unreadable_literal.rs:41:18 + | +LL | let _fail5 = 1.100300400; + | ^^^^^^^^^^^ help: consider: `1.100_300_400` + +error: aborting due to 11 previous errors diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed index b1e5742b7853..c266f684a36f 100644 --- a/tests/ui/wildcard_enum_match_arm.fixed +++ b/tests/ui/wildcard_enum_match_arm.fixed @@ -7,7 +7,8 @@ dead_code, clippy::single_match, clippy::wildcard_in_or_patterns, - clippy::unnested_or_patterns, clippy::diverging_sub_expression + clippy::unnested_or_patterns, + clippy::diverging_sub_expression )] use std::io::ErrorKind; diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs index cd3ec3ea8d26..2dbf726d5d07 100644 --- a/tests/ui/wildcard_enum_match_arm.rs +++ b/tests/ui/wildcard_enum_match_arm.rs @@ -7,7 +7,8 @@ dead_code, clippy::single_match, clippy::wildcard_in_or_patterns, - clippy::unnested_or_patterns, clippy::diverging_sub_expression + clippy::unnested_or_patterns, + clippy::diverging_sub_expression )] use std::io::ErrorKind; diff --git a/tests/ui/wildcard_enum_match_arm.stderr b/tests/ui/wildcard_enum_match_arm.stderr index e03b3be43ed2..0da2b68ba0b2 100644 --- a/tests/ui/wildcard_enum_match_arm.stderr +++ b/tests/ui/wildcard_enum_match_arm.stderr @@ -1,5 +1,5 @@ error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:38:9 + --> $DIR/wildcard_enum_match_arm.rs:39:9 | LL | _ => eprintln!("Not red"), | ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` @@ -11,25 +11,25 @@ LL | #![deny(clippy::wildcard_enum_match_arm)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:42:9 + --> $DIR/wildcard_enum_match_arm.rs:43:9 | LL | _not_red => eprintln!("Not red"), | ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:46:9 + --> $DIR/wildcard_enum_match_arm.rs:47:9 | LL | not_red => format!("{:?}", not_red), | ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:62:9 + --> $DIR/wildcard_enum_match_arm.rs:63:9 | LL | _ => "No red", | ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` error: match on non-exhaustive enum doesn't explicitly match all known variants - --> $DIR/wildcard_enum_match_arm.rs:79:9 + --> $DIR/wildcard_enum_match_arm.rs:80:9 | LL | _ => {}, | ^ help: try this: `std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _` From 4255a5afd5d55532fda11f43ded5339ad27ea27e Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 19:01:03 +0100 Subject: [PATCH 107/719] Moved failing test to src/test/ui/ Still have not figured out how to make it work --- library/core/tests/mem.rs | 11 +------ src/test/ui/assume-type-intrinsics.rs | 13 ++++++++ src/test/ui/assume-type-intrinsics.stderr | 37 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/assume-type-intrinsics.rs create mode 100644 src/test/ui/assume-type-intrinsics.stderr diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 4ebcf27e1734..268c2ed283f6 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -131,18 +131,9 @@ fn test_discriminant_send_sync() { } #[test] +#[cfg(not(bootstrap))] fn assume_init_good() { const TRUE: bool = unsafe { MaybeUninit::::new(true).assume_init() }; assert!(TRUE); } - -#[test] -fn assume_init_bad() { - const _BAD: () = unsafe { - MaybeUninit::::uninit().assume_init(); - //~^ ERROR the type `!` does not permit being left uninitialized - //~| ERROR this code causes undefined behavior when executed - //~| ERROR help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - }; -} diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/assume-type-intrinsics.rs new file mode 100644 index 000000000000..95562f3134fc --- /dev/null +++ b/src/test/ui/assume-type-intrinsics.rs @@ -0,0 +1,13 @@ +#![feature(never_type)] +#![feature(const_maybe_uninit_assume_init)] + +fn main() { + use std::mem::MaybeUninit; + + const _BAD: () = unsafe { + MaybeUninit::::uninit().assume_init(); + //~^ ERROR: the type `!` does not permit being left uninitialized + //~| this code causes undefined behavior when executed + //~| WARN: the type `!` does not permit being left uninitialized + }; +} diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/assume-type-intrinsics.stderr new file mode 100644 index 000000000000..be45d1ba384e --- /dev/null +++ b/src/test/ui/assume-type-intrinsics.stderr @@ -0,0 +1,37 @@ +error: any use of this value will cause an error + --> $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL + | +LL | intrinsics::assert_inhabited::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | attempted to instantiate uninhabited type `!` + | inside `MaybeUninit::::assume_init` at $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL + | inside `_BAD` at $DIR/assume-type-intrinsics.rs:8:9 + | + ::: $DIR/assume-type-intrinsics.rs:7:5 + | +LL | / const _BAD: () = unsafe { +LL | | MaybeUninit::::uninit().assume_init(); +LL | | +LL | | +LL | | +LL | | +LL | | }; + | |______- + | + = note: `#[deny(const_err)]` on by default + +warning: the type `!` does not permit being left uninitialized + --> $DIR/assume-type-intrinsics.rs:8:9 + | +LL | MaybeUninit::::uninit().assume_init(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: `#[warn(invalid_value)]` on by default + = note: the `!` type has no valid value + +error: aborting due to previous error; 1 warning emitted + From 3282b549acbb5922889329cddecd3dec700c54c2 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 19:29:35 +0100 Subject: [PATCH 108/719] Tests finally working --- src/test/ui/assume-type-intrinsics.rs | 4 +--- src/test/ui/assume-type-intrinsics.stderr | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/assume-type-intrinsics.rs index 95562f3134fc..8e9cb3345274 100644 --- a/src/test/ui/assume-type-intrinsics.rs +++ b/src/test/ui/assume-type-intrinsics.rs @@ -6,8 +6,6 @@ fn main() { const _BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); - //~^ ERROR: the type `!` does not permit being left uninitialized - //~| this code causes undefined behavior when executed - //~| WARN: the type `!` does not permit being left uninitialized + //~^ WARN: the type `!` does not permit being left uninitialized }; } diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/assume-type-intrinsics.stderr index be45d1ba384e..b776915affdb 100644 --- a/src/test/ui/assume-type-intrinsics.stderr +++ b/src/test/ui/assume-type-intrinsics.stderr @@ -13,9 +13,6 @@ LL | intrinsics::assert_inhabited::(); LL | / const _BAD: () = unsafe { LL | | MaybeUninit::::uninit().assume_init(); LL | | -LL | | -LL | | -LL | | LL | | }; | |______- | From 345f230df98cb695ee092bdec5ce8d4154668c0f Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 20:25:13 +0100 Subject: [PATCH 109/719] Fix comments related to abort() --- compiler/rustc_mir/src/const_eval/machine.rs | 4 ++++ compiler/rustc_mir/src/interpret/intrinsics.rs | 2 +- compiler/rustc_mir/src/interpret/machine.rs | 6 ++---- compiler/rustc_mir/src/interpret/terminator.rs | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index c72089ec55a9..03ad2607692d 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -333,6 +333,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Err(ConstEvalErrKind::AssertFailure(err).into()) } + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + Err(ConstEvalErrKind::Abort(msg).into()) + } + fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> { Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into()) } diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 18abf4291b1e..c25a312bb5af 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -126,7 +126,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { None => match intrinsic_name { sym::transmute => throw_ub_format!("transmuting to uninhabited type"), sym::unreachable => throw_ub!(Unreachable), - sym::abort => M::abort(self, "aborted execution".to_owned())?, + sym::abort => M::abort(self, "the program aborted execution".to_owned())?, // Unsupported diverging intrinsic. _ => return Ok(false), }, diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 1c13cdbc6e67..2626afdf0330 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -176,10 +176,8 @@ pub trait Machine<'mir, 'tcx>: Sized { ) -> InterpResult<'tcx>; /// Called to evaluate `Abort` MIR terminator. - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { - use crate::const_eval::ConstEvalErrKind; - - Err(ConstEvalErrKind::Abort(msg).into()) + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> { + throw_unsup_format!("aborting execution is not supported") } /// Called for all binary operations where the LHS has pointer type. diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index 18079488c891..a2931325a286 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Abort => { - M::abort(self, "aborted execution".to_owned())?; + M::abort(self, "the program aborted execution".to_owned())?; } // When we encounter Resume, we've finished unwinding From 0e527baf775221dc25cba5c48cbf44d28893d8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 27 Nov 2020 00:00:00 +0000 Subject: [PATCH 110/719] Retain assembly operands span when lowering AST to HIR --- clippy_lints/src/loops.rs | 2 +- clippy_lints/src/utils/hir_utils.rs | 2 +- clippy_lints/src/utils/inspector.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 400148ab81dd..1bd96b2b4c89 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -768,7 +768,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { ExprKind::InlineAsm(ref asm) => asm .operands .iter() - .map(|o| match o { + .map(|(o, _)| match o { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } | InlineAsmOperand::Const { expr } diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index d847d22275e8..d942d4e12b10 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -517,7 +517,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } asm.options.hash(&mut self.s); - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { InlineAsmOperand::In { reg, expr } => { reg.hash(&mut self.s); diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 8f0ef9150d45..323d87455388 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -293,7 +293,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template)); println!("{}options: {:?}", ind, asm.options); println!("{}operands:", ind); - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::InOut { expr, .. } From 76c68aa182e75bc6b47d8e05995fb7e9bc71cbb3 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Sat, 21 Nov 2020 04:52:18 -0500 Subject: [PATCH 111/719] Writeback min_capture map to TypeckResults - Derive TypeFoldable on `hir::place::Place` and associated structs, to them to be written into typeck results. Co-authored-by: Jennifer Wills Co-authored-by: Logan Mosier --- compiler/rustc_middle/src/hir/place.rs | 43 ++++++++++++-- compiler/rustc_middle/src/ty/mod.rs | 25 +++++--- compiler/rustc_typeck/src/check/writeback.rs | 32 ++++++++++ compiler/rustc_typeck/src/expr_use_visitor.rs | 58 ++----------------- 4 files changed, 94 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 5da4be4e9827..143b3867d9fc 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -4,7 +4,18 @@ use crate::ty::Ty; use rustc_hir::HirId; use rustc_target::abi::VariantIdx; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub enum PlaceBase { /// A temporary variable Rvalue, @@ -16,7 +27,18 @@ pub enum PlaceBase { Upvar(ty::UpvarId), } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub enum ProjectionKind { /// A dereference of a pointer, reference or `Box` of the given type Deref, @@ -36,7 +58,18 @@ pub enum ProjectionKind { Subslice, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub struct Projection<'tcx> { /// Type after the projection is being applied. pub ty: Ty<'tcx>, @@ -48,7 +81,7 @@ pub struct Projection<'tcx> { /// A `Place` represents how a value is located in memory. /// /// This is an HIR version of `mir::Place` -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct Place<'tcx> { /// The type of the `PlaceBase` pub base_ty: Ty<'tcx>, @@ -61,7 +94,7 @@ pub struct Place<'tcx> { /// A `PlaceWithHirId` represents how a value is located in memory. /// /// This is an HIR version of `mir::Place` -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct PlaceWithHirId<'tcx> { /// `HirId` of the expression or pattern producing this value. pub hir_id: HirId, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5d8edcf70bfd..1a9a6a33fefd 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -672,7 +672,18 @@ impl<'a, 'tcx> HashStable> for TyS<'tcx> { #[rustc_diagnostic_item = "Ty"] pub type Ty<'tcx> = &'tcx TyS<'tcx>; -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub struct UpvarPath { pub hir_id: hir::HirId, } @@ -680,7 +691,7 @@ pub struct UpvarPath { /// Upvars do not get their own `NodeId`. Instead, we use the pair of /// the original var ID (that is, the root variable that is referenced /// by the upvar) and the ID of the closure expression. -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct UpvarId { pub var_path: UpvarPath, pub closure_expr_id: LocalDefId, @@ -692,7 +703,7 @@ impl UpvarId { } } -#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)] +#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. ImmBorrow, @@ -746,7 +757,7 @@ pub enum BorrowKind { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub enum UpvarCapture<'tcx> { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases @@ -763,7 +774,7 @@ pub enum UpvarCapture<'tcx> { ByRef(UpvarBorrow<'tcx>), } -#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct UpvarBorrow<'tcx> { /// The kind of borrow: by-ref upvars have access to shared /// immutable borrows, which are not part of the normal language @@ -790,7 +801,7 @@ pub type RootVariableMinCaptureList<'tcx> = FxIndexMap = Vec>; /// A `Place` and the corresponding `CaptureInfo`. -#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct CapturedPlace<'tcx> { pub place: HirPlace<'tcx>, pub info: CaptureInfo<'tcx>, @@ -799,7 +810,7 @@ pub struct CapturedPlace<'tcx> { /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move) /// for a particular capture as well as identifying the part of the source code /// that triggered this capture to occur. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct CaptureInfo<'tcx> { /// Expr Id pointing to use that resulted in selecting the current capture kind /// diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 68b85a4da34f..7c9cfe69fc94 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -55,6 +55,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), } wbcx.visit_body(body); + wbcx.visit_min_capture_map(); wbcx.visit_upvar_capture_map(); wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); @@ -331,6 +332,37 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { } impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { + fn visit_min_capture_map(&mut self) { + let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher( + self.fcx.typeck_results.borrow().closure_min_captures.len(), + Default::default(), + ); + for (closure_def_id, root_min_captures) in + self.fcx.typeck_results.borrow().closure_min_captures.iter() + { + let mut root_var_map_wb = ty::RootVariableMinCaptureList::with_capacity_and_hasher( + root_min_captures.len(), + Default::default(), + ); + for (var_hir_id, min_list) in root_min_captures.iter() { + let min_list_wb = min_list + .iter() + .map(|captured_place| { + let locatable = captured_place.info.expr_id.unwrap_or( + self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local()), + ); + + self.resolve(captured_place.clone(), &locatable) + }) + .collect(); + root_var_map_wb.insert(*var_hir_id, min_list_wb); + } + min_captures_wb.insert(*closure_def_id, root_var_map_wb); + } + + self.typeck_results.closure_min_captures = min_captures_wb; + } + fn visit_upvar_capture_map(&mut self) { for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() { let new_upvar_capture = match *upvar_capture { diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 1b51d5e0182f..8a324807417d 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -15,7 +15,6 @@ use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::ProjectionKind; use rustc_middle::ty::{self, adjustment, TyCtxt}; -use rustc_span::Span; use rustc_target::abi::VariantIdx; use crate::mem_categorization as mc; @@ -571,38 +570,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { })); } - /// Walk closure captures but using `closure_caputes` instead - /// of `closure_min_captures`. - /// - /// This is needed because clippy uses `ExprUseVisitor` after TypeckResults - /// are written back. We don't currently writeback min_captures to - /// TypeckResults. - fn walk_captures_closure_captures(&mut self, closure_expr: &hir::Expr<'_>) { - // FIXME(arora-aman): Remove this function once rust-lang/project-rfc-2229#18 - // is completed. - debug!("walk_captures_closure_captures({:?}), ", closure_expr); - - let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); - let cl_span = self.tcx().hir().span(closure_expr.hir_id); - - let captures = &self.mc.typeck_results.closure_captures[&closure_def_id]; - - for (&var_id, &upvar_id) in captures { - let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id); - let captured_place = - return_if_err!(self.cat_captured_var(closure_expr.hir_id, cl_span, var_id)); - match upvar_capture { - ty::UpvarCapture::ByValue(_) => { - let mode = copy_or_move(&self.mc, &captured_place); - self.delegate.consume(&captured_place, captured_place.hir_id, mode); - } - ty::UpvarCapture::ByRef(upvar_borrow) => { - self.delegate.borrow(&captured_place, captured_place.hir_id, upvar_borrow.kind); - } - } - } - } - /// Handle the case where the current body contains a closure. /// /// When the current body being handled is a closure, then we must make sure that @@ -646,16 +613,18 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let place = &captured_place.place; let capture_info = captured_place.info; - let upvar_id = if body_owner_is_closure { + let place_base = if body_owner_is_closure { // Mark the place to be captured by the enclosing closure - ty::UpvarId::new(*var_hir_id, self.body_owner) + PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.body_owner)) } else { - ty::UpvarId::new(*var_hir_id, closure_def_id.expect_local()) + // If the body owner isn't a closure then the variable must + // be a local variable + PlaceBase::Local(*var_hir_id) }; let place_with_id = PlaceWithHirId::new( capture_info.expr_id.unwrap_or(closure_expr.hir_id), place.base_ty, - PlaceBase::Upvar(upvar_id), + place_base, place.projections.clone(), ); @@ -674,23 +643,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } } - } else if self.mc.typeck_results.closure_captures.contains_key(&closure_def_id) { - // Handle the case where clippy calls ExprUseVisitor after - self.walk_captures_closure_captures(closure_expr) } } - - fn cat_captured_var( - &mut self, - closure_hir_id: hir::HirId, - closure_span: Span, - var_id: hir::HirId, - ) -> mc::McResult> { - // Create the place for the variable being borrowed, from the - // perspective of the creator (parent) of the closure. - let var_ty = self.mc.node_ty(var_id)?; - self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id)) - } } fn copy_or_move<'a, 'tcx>( From 6e5cca79fcaaa80fbaaa23ba9f9c806f2ae8f41e Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Wed, 25 Nov 2020 23:56:55 -0500 Subject: [PATCH 112/719] Use min_captures for creating UpvarSusbts::tupled_upvar_tys - final_upvar_tys now reads types from places instead of using `node_ty` Co-authored-by: Roxane Fruytier --- compiler/rustc_middle/src/ty/context.rs | 13 +++++++++ compiler/rustc_typeck/src/check/upvar.rs | 37 +++++++++++------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1b3416e112ba..a8d007c0be27 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -624,6 +624,19 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } + /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured + /// by the closure. + pub fn closure_min_captures_flattened( + &self, + closure_def_id: DefId, + ) -> impl Iterator> { + self.closure_min_captures + .get(&closure_def_id) + .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter())) + .into_iter() + .flatten() + } + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> { self.upvar_capture_map[&upvar_id] } diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 019fa78fb1e0..30b4682296c6 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -202,7 +202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // inference algorithm will reject it). // Equate the type variables for the upvars with the actual types. - let final_upvar_tys = self.final_upvar_tys(closure_hir_id); + let final_upvar_tys = self.final_upvar_tys(closure_def_id); debug!( "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", closure_hir_id, substs, final_upvar_tys @@ -222,36 +222,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Returns a list of `Ty`s for each upvar. - fn final_upvar_tys(&self, closure_id: hir::HirId) -> Vec> { + fn final_upvar_tys(&self, closure_id: DefId) -> Vec> { // Presently an unboxed closure type cannot "escape" out of a // function, so we will only encounter ones that originated in the // local crate or were inlined into it along with some function. // This may change if abstract return types of some sort are // implemented. let tcx = self.tcx; - let closure_def_id = tcx.hir().local_def_id(closure_id); self.typeck_results .borrow() - .closure_captures - .get(&closure_def_id.to_def_id()) - .iter() - .flat_map(|upvars| { - upvars.iter().map(|(&var_hir_id, _)| { - let upvar_ty = self.node_ty(var_hir_id); - let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id); - let capture = self.typeck_results.borrow().upvar_capture(upvar_id); + .closure_min_captures_flattened(closure_id) + .map(|captured_place| { + let upvar_ty = captured_place.place.ty(); + let capture = captured_place.info.capture_kind; - debug!("var_id={:?} upvar_ty={:?} capture={:?}", var_hir_id, upvar_ty, capture); + debug!( + "place={:?} upvar_ty={:?} capture={:?}", + captured_place.place, upvar_ty, capture + ); - match capture { - ty::UpvarCapture::ByValue(_) => upvar_ty, - ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( - borrow.region, - ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() }, - ), - } - }) + match capture { + ty::UpvarCapture::ByValue(_) => upvar_ty, + ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( + borrow.region, + ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() }, + ), + } }) .collect() } From d0a1e40eae2bb02b23b65c33918fce20e9ed4ae4 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 22:29:13 +0100 Subject: [PATCH 113/719] Remove unused feature gate --- library/core/tests/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 9e7a8189c816..2aa3598a0d94 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -54,7 +54,6 @@ #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] -#![feature(const_assert_type)] #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(option_unwrap_none)] From d9523622ff68e9a91d9cc6b225dc479d7cc8f0c7 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Wed, 18 Nov 2020 22:54:31 -0500 Subject: [PATCH 114/719] Move handling UpvarRef to PlaceBuilder - This allows us to delay figuring out the index of a capture in the closure structure when all projections to atleast form a capture have been applied to the builder Co-authored-by: Roxane Fruytier --- .../src/build/expr/as_place.rs | 285 +++++++++++++----- 1 file changed, 207 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index e6263e5d6cf9..2ab733fabb8c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -4,6 +4,8 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::thir::*; +use rustc_hir::def_id::DefId; +use rustc_hir::HirId; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; @@ -12,6 +14,50 @@ use rustc_span::Span; use rustc_index::vec::Idx; +/// The "outermost" place that holds this value. +#[derive(Copy, Clone)] +pub enum PlaceBase { + /// Denotes the start of a `Place`. + Local(Local), + + /// When building place for an expression within a closure, the place might start off a + /// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture + /// index (within the desugared closure) of the captured path until most of the projections + /// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the + /// captured path starts, the closure the capture belongs to and the trait the closure + /// implements. + /// + /// Once we have figured out the capture index, we can convert the place builder to start from + /// `PlaceBase::Local`. + /// + /// Consider the following example + /// ```rust + /// let t = (10, (10, (10, 10))); + /// + /// let c = || { + /// println!("{}", t.0.0.0); + /// }; + /// ``` + /// Here the THIR expression for `t.0.0.0` will be something like + /// + /// ``` + /// * Field(0) + /// * Field(0) + /// * Field(0) + /// * UpvarRef(t) + /// ``` + /// + /// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to + /// figure out that it is captured until all the `Field` projections are applied. + Upvar { + /// HirId of the upvar + var_hir_id: HirId, + /// DefId of the closure + closure_def_id: DefId, + /// The trait closure implements, `Fn`, `FnMut`, `FnOnce` + closure_kind: ty::ClosureKind }, +} + /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a /// place by pushing more and more projections onto the end, and then convert the final set into a /// place using the `into_place` method. @@ -20,13 +66,131 @@ use rustc_index::vec::Idx; /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. #[derive(Clone)] struct PlaceBuilder<'tcx> { - local: Local, + base: PlaceBase, projection: Vec>, } +fn capture_matching_projections<'a, 'tcx>( + typeck_results: &'a ty::TypeckResults<'tcx>, + var_hir_id: HirId, + closure_def_id: DefId, + _projections: &Vec>, +) -> Option<(usize, ty::UpvarCapture<'tcx>)> { + typeck_results + .closure_captures + .get(&closure_def_id) + .and_then(|captures| captures.get_full(&var_hir_id)) + .and_then(|(capture_index, _, _)|{ + let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local()); + let capture_kind = typeck_results.upvar_capture(upvar_id); + Some((capture_index, capture_kind)) + }) +} + +/// Takes a PlaceBuilder and resolves the upvar (if any) within it, +/// so that the PlaceBuilder now starts from PlaceBase::Local. +/// +/// Returns a Result with the error being the HirId of the +/// Upvar that was not found. +fn to_upvars_resolved_place_builder<'a, 'tcx>( + from_builder: PlaceBuilder<'tcx>, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, +) -> Result, HirId> { + match from_builder.base { + PlaceBase::Local(_) => Ok(from_builder), + PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => { + // Captures are represented using fields inside a structure. + // This represents accessing self in the closure structure + let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1)); + match closure_kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { + upvar_resolved_place_builder = upvar_resolved_place_builder.deref(); + } + ty::ClosureKind::FnOnce => {} + } + + let (capture_index, capture_kind) = + if let Some(capture_details) = capture_matching_projections( + typeck_results, + var_hir_id, + closure_def_id, + &from_builder.projection, + ) { + capture_details + } else { + if !tcx.features().capture_disjoint_fields { + bug!( + "No associated capture found for {:?}[{:#?}] even though \ + capture_disjoint_fields isn't enabled", + var_hir_id, + from_builder.projection + ) + } else { + // FIXME(project-rfc-2229#24): Handle this case properly + debug!( + "No associated capture found for {:?}[{:#?}]", + var_hir_id, + from_builder.projection, + ); + } + return Err(var_hir_id); + }; + + let closure_ty = + typeck_results.node_type(tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local())); + + let substs = match closure_ty.kind() { + ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), + ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), + _ => bug!("Lowering capture for non-closure type {:?}", closure_ty), + }; + + // Access the capture by accessing the field within the Closure struct. + // + // We must have inferred the capture types since we are building MIR, therefore + // it's safe to call `upvar_tys` and we can unwrap here because + // we know that the capture exists and is the `capture_index`-th capture. + let var_ty = substs.upvar_tys().nth(capture_index).unwrap(); + + upvar_resolved_place_builder = upvar_resolved_place_builder.field(Field::new(capture_index), var_ty); + + // If the variable is captured via ByRef(Immutable/Mutable) Borrow, + // we need to deref it + upvar_resolved_place_builder = match capture_kind { + ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(), + ty::UpvarCapture::ByValue(_) => upvar_resolved_place_builder, + }; + + let next_projection = 0; + let mut curr_projections = from_builder.projection; + upvar_resolved_place_builder.projection.extend( + curr_projections.drain(next_projection..)); + + Ok(upvar_resolved_place_builder) + } + } +} + impl<'tcx> PlaceBuilder<'tcx> { - fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> { - Place { local: self.local, projection: tcx.intern_place_elems(&self.projection) } + fn into_place<'a>( + self, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + ) -> Place<'tcx> { + if let PlaceBase::Local(local) = self.base { + Place { local, projection: tcx.intern_place_elems(&self.projection) } + } else { + self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results) + } + } + + fn expect_upvars_resolved<'a>( + self, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + ) -> PlaceBuilder<'tcx> { + to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() } fn field(self, f: Field, ty: Ty<'tcx>) -> Self { @@ -49,7 +213,13 @@ impl<'tcx> PlaceBuilder<'tcx> { impl<'tcx> From for PlaceBuilder<'tcx> { fn from(local: Local) -> Self { - Self { local, projection: Vec::new() } + Self { base: PlaceBase::Local(local), projection: Vec::new() } + } +} + +impl<'tcx> From for PlaceBuilder<'tcx> { + fn from(base: PlaceBase) -> Self { + Self { base, projection: Vec::new() } } } @@ -71,7 +241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place(self.hir.tcx())) + block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results())) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -98,7 +268,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); - block.and(place_builder.into_place(self.hir.tcx())) + block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results())) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -161,27 +331,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, ), ExprKind::UpvarRef { closure_def_id, var_hir_id } => { - let capture = this - .hir - .typeck_results - .closure_captures - .get(&closure_def_id) - .and_then(|captures| captures.get_full(&var_hir_id)); - - if capture.is_none() { - if !this.hir.tcx().features().capture_disjoint_fields { - bug!( - "No associated capture found for {:?} even though \ - capture_disjoint_fields isn't enabled", - expr.kind - ) - } - // FIXME(project-rfc-2229#24): Handle this case properly - } - - // Unwrap until the FIXME has been resolved - let (capture_index, _, upvar_id) = capture.unwrap(); - this.lower_closure_capture(block, capture_index, *upvar_id) + let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local()); + this.lower_captured_upvar(block, upvar_id) } ExprKind::VarRef { id } => { @@ -208,7 +359,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: expr.ty, }); - let place = place_builder.clone().into_place(this.hir.tcx()); + let place = + place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results()); this.cfg.push( block, Statement { @@ -293,59 +445,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - /// Lower a closure/generator capture by representing it as a field - /// access within the desugared closure/generator. - /// - /// `capture_index` is the index of the capture within the desugared - /// closure/generator. - fn lower_closure_capture( + /// Lower a captured upvar. Note we might not know the actual capture index, + /// so we create a place starting from `PlaceBase::Upvar`, which will be resolved + /// once all projections that allow us to indentify a capture have been applied. + fn lower_captured_upvar( &mut self, block: BasicBlock, - capture_index: usize, upvar_id: ty::UpvarId, - ) -> BlockAnd> { + ) -> BlockAnd> { let closure_ty = self .hir .typeck_results() .node_type(self.hir.tcx().hir().local_def_id_to_hir_id(upvar_id.closure_expr_id)); - // Captures are represented using fields inside a structure. - // This represents accessing self in the closure structure - let mut place_builder = PlaceBuilder::from(Local::new(1)); - - // In case of Fn/FnMut closures we must deref to access the fields - // Generators are considered FnOnce, so we ignore this step for them. - if let ty::Closure(_, closure_substs) = closure_ty.kind() { - match self.hir.infcx().closure_kind(closure_substs).unwrap() { - ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { - place_builder = place_builder.deref(); - } - ty::ClosureKind::FnOnce => {} - } - } - - let substs = match closure_ty.kind() { - ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), - ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), - _ => bug!("Lowering capture for non-closure type {:?}", closure_ty) + let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() { + self.hir.infcx().closure_kind(closure_substs).unwrap() + } else { + // Generators are considered FnOnce. + ty::ClosureKind::FnOnce }; - // Access the capture by accessing the field within the Closure struct. - // - // We must have inferred the capture types since we are building MIR, therefore - // it's safe to call `upvar_tys` and we can unwrap here because - // we know that the capture exists and is the `capture_index`-th capture. - let var_ty = substs.upvar_tys().nth(capture_index).unwrap(); - place_builder = place_builder.field(Field::new(capture_index), var_ty); - - // If the variable is captured via ByRef(Immutable/Mutable) Borrow, - // we need to deref it - match self.hir.typeck_results.upvar_capture(upvar_id) { - ty::UpvarCapture::ByRef(_) => { - block.and(place_builder.deref()) - } - ty::UpvarCapture::ByValue(_) => block.and(place_builder), - } + block.and(PlaceBuilder::from(PlaceBase::Upvar { + var_hir_id: upvar_id.var_path.hir_id, + closure_def_id: upvar_id.closure_expr_id.to_def_id(), + closure_kind, + })) } /// Lower an index expression @@ -373,7 +497,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let is_outermost_index = fake_borrow_temps.is_none(); let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps); - let base_place = + let mut base_place = unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),)); // Making this a *fresh* temporary means we do not have to worry about @@ -383,7 +507,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = self.bounds_check( block, - base_place.clone().into_place(self.hir.tcx()), + base_place.clone().into_place(self.hir.tcx(), self.hir.typeck_results()), idx, expr_span, source_info, @@ -392,6 +516,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if is_outermost_index { self.read_fake_borrows(block, fake_borrow_temps, source_info) } else { + base_place = base_place.expect_upvars_resolved(self.hir.tcx(), self.hir.typeck_results()); self.add_fake_borrows_of_base( &base_place, block, @@ -441,8 +566,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: SourceInfo, ) { let tcx = self.hir.tcx(); - let place_ty = - Place::ty_from(base_place.local, &base_place.projection, &self.local_decls, tcx); + let local = match base_place.base { + PlaceBase::Local(local) => local, + PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar") + }; + + let place_ty = Place::ty_from(local, &base_place.projection, &self.local_decls, tcx); if let ty::Slice(_) = place_ty.ty.kind() { // We need to create fake borrows to ensure that the bounds // check that we just did stays valid. Since we can't assign to @@ -452,7 +581,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match elem { ProjectionElem::Deref => { let fake_borrow_deref_ty = Place::ty_from( - base_place.local, + local, &base_place.projection[..idx], &self.local_decls, tcx, @@ -470,14 +599,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Ref( tcx.lifetimes.re_erased, BorrowKind::Shallow, - Place { local: base_place.local, projection }, + Place { local, projection }, ), ); fake_borrow_temps.push(fake_borrow_temp); } ProjectionElem::Index(_) => { let index_ty = Place::ty_from( - base_place.local, + local, &base_place.projection[..idx], &self.local_decls, tcx, From 7208a01cdf8dd23264ac3236012e881402ccbbd5 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 24 Oct 2020 10:42:40 +0200 Subject: [PATCH 115/719] Turn quadratic time on number of impl blocks into linear time Previously, if you had a lot of inherent impl blocks on a type like: struct Foo; impl Foo { fn foo_1() {} } ... impl Foo { fn foo_100_000() {} } The compiler would be very slow at processing it, because an internal algorithm would run in O(n^2), where n is the number of impl blocks. Now, we add a new algorithm that allocates but is faster asymptotically. If there is an overlap between multiple impl blocks in terms of identifiers, we still run a O(m^2) algorithm on groups of impl blocks that have overlaps, but that m refers to the size of the connected component, which is hopefully smaller than the n that refers to the sum of all connected components. --- .../src/coherence/inherent_impls_overlap.rs | 152 +++++++++++++++++- 1 file changed, 147 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs index 2d1ea7d200ce..4efb2a6273be 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs @@ -1,10 +1,13 @@ +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::Symbol; use rustc_trait_selection::traits::{self, SkipLeakCheck}; use smallvec::SmallVec; +use std::collections::hash_map::Entry; pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) { assert_eq!(crate_num, LOCAL_CRATE); @@ -45,7 +48,7 @@ impl InherentOverlapChecker<'tcx> { false } - fn compare_hygienically(&self, item1: &'tcx ty::AssocItem, item2: &'tcx ty::AssocItem) -> bool { + fn compare_hygienically(&self, item1: &ty::AssocItem, item2: &ty::AssocItem) -> bool { // Symbols and namespace match, compare hygienically. item1.kind.namespace() == item2.kind.namespace() && item1.ident.normalize_to_macros_2_0() == item2.ident.normalize_to_macros_2_0() @@ -134,10 +137,149 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { .map(|impl_def_id| (impl_def_id, self.tcx.associated_items(*impl_def_id))) .collect::>(); - for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() { - for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] { - if self.impls_have_common_items(impl_items1, impl_items2) { - self.check_for_overlapping_inherent_impls(impl1_def_id, impl2_def_id); + // Perform a O(n^2) algorithm for small n, + // otherwise switch to an allocating algorithm with + // faster asymptotic runtime. + if impls.len() < 30 { + for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() { + for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] { + if self.impls_have_common_items(impl_items1, impl_items2) { + self.check_for_overlapping_inherent_impls( + impl1_def_id, + impl2_def_id, + ); + } + } + } + } else { + // Build a set of connected regions of impl blocks. + // Two impl blocks are regarded as connected if they share + // an item with the same unhygienic identifier. + // After we have assembled the connected regions, + // run the O(n^2) algorithm on each connected region. + // This is advantageous to running the algorithm over the + // entire graph when there are many connected regions. + + struct ConnectedRegion { + idents: SmallVec<[Symbol; 8]>, + impl_blocks: FxHashSet, + } + // Highest connected region id + let mut highest_region_id = 0; + let mut connected_region_ids = FxHashMap::default(); + let mut connected_regions = FxHashMap::default(); + + for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() { + if impl_items.len() == 0 { + continue; + } + // First obtain a list of existing connected region ids + let mut idents_to_add = SmallVec::<[Symbol; 8]>::new(); + let ids = impl_items + .in_definition_order() + .filter_map(|item| { + let entry = connected_region_ids.entry(item.ident.name); + if let Entry::Occupied(e) = &entry { + Some(*e.get()) + } else { + idents_to_add.push(item.ident.name); + None + } + }) + .collect::>(); + match ids.len() { + 0 | 1 => { + let id_to_set = if ids.len() == 0 { + // Create a new connected region + let region = ConnectedRegion { + idents: idents_to_add, + impl_blocks: std::iter::once(i).collect(), + }; + connected_regions.insert(highest_region_id, region); + (highest_region_id, highest_region_id += 1).0 + } else { + // Take the only id inside the list + let id_to_set = *ids.iter().next().unwrap(); + let region = connected_regions.get_mut(&id_to_set).unwrap(); + region.impl_blocks.insert(i); + region.idents.extend_from_slice(&idents_to_add); + id_to_set + }; + let (_id, region) = connected_regions.iter().next().unwrap(); + // Update the connected region ids + for ident in region.idents.iter() { + connected_region_ids.insert(*ident, id_to_set); + } + } + _ => { + // We have multiple connected regions to merge. + // In the worst case this might add impl blocks + // one by one and can thus be O(n^2) in the size + // of the resulting final connected region, but + // this is no issue as the final step to check + // for overlaps runs in O(n^2) as well. + + // Take the smallest id from the list + let id_to_set = *ids.iter().min().unwrap(); + + // Sort the id list so that the algorithm is deterministic + let mut ids = ids.into_iter().collect::>(); + ids.sort(); + + let mut region = connected_regions.remove(&id_to_set).unwrap(); + region.idents.extend_from_slice(&idents_to_add); + region.impl_blocks.insert(i); + + for &id in ids.iter() { + if id == id_to_set { + continue; + } + let r = connected_regions.remove(&id).unwrap(); + // Update the connected region ids + for ident in r.idents.iter() { + connected_region_ids.insert(*ident, id_to_set); + } + region.idents.extend_from_slice(&r.idents); + region.impl_blocks.extend(r.impl_blocks); + } + connected_regions.insert(id_to_set, region); + } + } + } + + debug!( + "churning through {} components (sum={}, avg={}, var={}, max={})", + connected_regions.len(), + impls.len(), + impls.len() / connected_regions.len(), + { + let avg = impls.len() / connected_regions.len(); + let s = connected_regions + .iter() + .map(|r| r.1.impl_blocks.len() as isize - avg as isize) + .map(|v| v.abs() as usize) + .sum::(); + s / connected_regions.len() + }, + connected_regions.iter().map(|r| r.1.impl_blocks.len()).max().unwrap() + ); + // List of connected regions is built. Now, run the overlap check + // for each pair of impl blocks in the same connected region. + for (_id, region) in connected_regions.into_iter() { + let mut impl_blocks = + region.impl_blocks.into_iter().collect::>(); + impl_blocks.sort(); + for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() { + let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx]; + for &impl2_items_idx in impl_blocks[(i + 1)..].iter() { + let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx]; + if self.impls_have_common_items(impl_items1, impl_items2) { + self.check_for_overlapping_inherent_impls( + impl1_def_id, + impl2_def_id, + ); + } + } } } } From 73a7d935dc55b4757706a966179459670e386582 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 7 Dec 2020 01:44:04 +0100 Subject: [PATCH 116/719] Add tests --- .../src/coherence/inherent_impls_overlap.rs | 3 +- .../auxiliary/repeat.rs | 54 ++++++++++++++ .../no-overlap.rs | 34 +++++++++ .../inherent-impls-overlap-check/overlap.rs | 71 +++++++++++++++++++ .../overlap.stderr | 47 ++++++++++++ 5 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/inherent-impls-overlap-check/auxiliary/repeat.rs create mode 100644 src/test/ui/inherent-impls-overlap-check/no-overlap.rs create mode 100644 src/test/ui/inherent-impls-overlap-check/overlap.rs create mode 100644 src/test/ui/inherent-impls-overlap-check/overlap.stderr diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs index 4efb2a6273be..50d886743281 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs @@ -140,7 +140,8 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { // Perform a O(n^2) algorithm for small n, // otherwise switch to an allocating algorithm with // faster asymptotic runtime. - if impls.len() < 30 { + const ALLOCATING_ALGO_THRESHOLD: usize = 500; + if impls.len() < ALLOCATING_ALGO_THRESHOLD { for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() { for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] { if self.impls_have_common_items(impl_items1, impl_items2) { diff --git a/src/test/ui/inherent-impls-overlap-check/auxiliary/repeat.rs b/src/test/ui/inherent-impls-overlap-check/auxiliary/repeat.rs new file mode 100644 index 000000000000..42ed5d19deb8 --- /dev/null +++ b/src/test/ui/inherent-impls-overlap-check/auxiliary/repeat.rs @@ -0,0 +1,54 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::{Ident, Group, TokenStream, TokenTree as Tt}; + +// This constant has to be above the ALLOCATING_ALGO_THRESHOLD +// constant in inherent_impls_overlap.rs +const REPEAT_COUNT: u32 = 501; + +#[proc_macro] +/// Repeats the input many times, while replacing idents +/// named "IDENT" with "id_$v", where v is a counter. +pub fn repeat_with_idents(input: TokenStream) -> TokenStream { + let mut res = Vec::new(); + fn visit_stream(res: &mut Vec, stream :TokenStream, v: u32) { + let mut stream_iter = stream.into_iter(); + while let Some(tt) = stream_iter.next() { + match tt { + Tt::Group(group) => { + let tt = Tt::Group(visit_group(group, v)); + res.push(tt); + }, + Tt::Ident(id) => { + let id = if &id.to_string() == "IDENT" { + Ident::new(&format!("id_{}", v), id.span()) + } else { + id + }; + res.push(Tt::Ident(id)); + }, + Tt::Punct(p) => { + res.push(Tt::Punct(p)); + }, + Tt::Literal(lit) => { + res.push(Tt::Literal(lit)); + }, + } + } + } + fn visit_group(group :Group, v: u32) -> Group { + let mut res = Vec::new(); + visit_stream(&mut res, group.stream(), v); + let stream = res.into_iter().collect(); + let delim = group.delimiter(); + Group::new(delim, stream) + } + for v in 0 .. REPEAT_COUNT { + visit_stream(&mut res, input.clone(), v) + } + res.into_iter().collect() +} diff --git a/src/test/ui/inherent-impls-overlap-check/no-overlap.rs b/src/test/ui/inherent-impls-overlap-check/no-overlap.rs new file mode 100644 index 000000000000..341bfc7b605f --- /dev/null +++ b/src/test/ui/inherent-impls-overlap-check/no-overlap.rs @@ -0,0 +1,34 @@ +// run-pass +// aux-build:repeat.rs + +// This tests the allocating algo branch of the +// inherent impls overlap checker. +// This branch was added by PR: +// https://github.com/rust-lang/rust/pull/78317 +// In this test, we repeat many impl blocks +// to trigger the allocating branch. + +#![allow(unused)] + +extern crate repeat; + +// Simple case where each impl block is distinct + +struct Foo {} + +repeat::repeat_with_idents!(impl Foo { fn IDENT() {} }); + +// There are overlapping impl blocks but due to generics, +// they may overlap. + +struct Bar(T); + +struct A; +struct B; + +repeat::repeat_with_idents!(impl Bar { fn IDENT() {} }); + +impl Bar { fn foo() {} } +impl Bar { fn foo() {} } + +fn main() {} diff --git a/src/test/ui/inherent-impls-overlap-check/overlap.rs b/src/test/ui/inherent-impls-overlap-check/overlap.rs new file mode 100644 index 000000000000..6f2801197e90 --- /dev/null +++ b/src/test/ui/inherent-impls-overlap-check/overlap.rs @@ -0,0 +1,71 @@ +// aux-build:repeat.rs + +#![allow(unused)] + +// This tests the allocating algo branch of the +// inherent impls overlap checker. +// This branch was added by PR: +// https://github.com/rust-lang/rust/pull/78317 +// In this test, we repeat many impl blocks +// to trigger the allocating branch. + +// Simple overlap + +extern crate repeat; + +struct Foo {} + +repeat::repeat_with_idents!(impl Foo { fn IDENT() {} }); + +impl Foo { fn hello() {} } //~ERROR duplicate definitions with name `hello` +impl Foo { fn hello() {} } + +// Transitive overlap + +struct Foo2 {} + +repeat::repeat_with_idents!(impl Foo2 { fn IDENT() {} }); + +impl Foo2 { + fn bar() {} + fn hello2() {} //~ERROR duplicate definitions with name `hello2` +} + +impl Foo2 { + fn baz() {} + fn hello2() {} +} + +// Slightly stronger transitive overlap + +struct Foo3 {} + +repeat::repeat_with_idents!(impl Foo3 { fn IDENT() {} }); + +impl Foo3 { + fn bar() {} //~ERROR duplicate definitions with name `bar` + fn hello3() {} //~ERROR duplicate definitions with name `hello3` +} + +impl Foo3 { + fn bar() {} + fn hello3() {} +} + +// Generic overlap + +struct Bar(T); + +struct A; +struct B; + +repeat::repeat_with_idents!(impl Bar { fn IDENT() {} }); + +impl Bar { fn foo() {} fn bar2() {} } +impl Bar { + fn foo() {} + fn bar2() {} //~ERROR duplicate definitions with name `bar2` +} +impl Bar { fn bar2() {} } + +fn main() {} diff --git a/src/test/ui/inherent-impls-overlap-check/overlap.stderr b/src/test/ui/inherent-impls-overlap-check/overlap.stderr new file mode 100644 index 000000000000..3dd2793712f5 --- /dev/null +++ b/src/test/ui/inherent-impls-overlap-check/overlap.stderr @@ -0,0 +1,47 @@ +error[E0592]: duplicate definitions with name `hello` + --> $DIR/overlap.rs:20:12 + | +LL | impl Foo { fn hello() {} } + | ^^^^^^^^^^ duplicate definitions for `hello` +LL | impl Foo { fn hello() {} } + | ---------- other definition for `hello` + +error[E0592]: duplicate definitions with name `hello2` + --> $DIR/overlap.rs:31:5 + | +LL | fn hello2() {} + | ^^^^^^^^^^^ duplicate definitions for `hello2` +... +LL | fn hello2() {} + | ----------- other definition for `hello2` + +error[E0592]: duplicate definitions with name `bar` + --> $DIR/overlap.rs:46:5 + | +LL | fn bar() {} + | ^^^^^^^^ duplicate definitions for `bar` +... +LL | fn bar() {} + | -------- other definition for `bar` + +error[E0592]: duplicate definitions with name `hello3` + --> $DIR/overlap.rs:47:5 + | +LL | fn hello3() {} + | ^^^^^^^^^^^ duplicate definitions for `hello3` +... +LL | fn hello3() {} + | ----------- other definition for `hello3` + +error[E0592]: duplicate definitions with name `bar2` + --> $DIR/overlap.rs:67:5 + | +LL | fn bar2() {} + | ^^^^^^^^^ duplicate definitions for `bar2` +LL | } +LL | impl Bar { fn bar2() {} } + | --------- other definition for `bar2` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0592`. From 01aec8d18556be5e8d498c2f331b9015b7befde2 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 30 May 2020 15:02:32 -0400 Subject: [PATCH 117/719] [mir-opt] Allow debuginfo to be generated for a constant or a Place Prior to this commit, debuginfo was always generated by mapping a name to a Place. This has the side-effect that `SimplifyLocals` cannot remove locals that are only used for debuginfo because their other uses have been const-propagated. To allow these locals to be removed, we now allow debuginfo to point to a constant value. The `ConstProp` pass detects when debuginfo points to a local with a known constant value and replaces it with the value. This allows the later `SimplifyLocals` pass to remove the local. --- .../src/debuginfo/metadata.rs | 5 +- .../rustc_codegen_ssa/src/mir/constant.rs | 4 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 105 +++++++++++----- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 21 +++- compiler/rustc_middle/src/mir/visit.rs | 16 ++- compiler/rustc_mir/src/borrow_check/mod.rs | 26 ++-- .../src/transform/const_debuginfo.rs | 98 +++++++++++++++ compiler/rustc_mir/src/transform/mod.rs | 2 + .../rustc_mir/src/transform/simplify_try.rs | 41 ++++--- compiler/rustc_mir/src/util/graphviz.rs | 2 +- compiler/rustc_mir/src/util/pretty.rs | 2 +- .../rustc_mir_build/src/build/matches/mod.rs | 4 +- compiler/rustc_mir_build/src/build/mod.rs | 6 +- .../incremental/hashes/let_expressions.rs | 4 +- .../const_debuginfo.main.ConstDebugInfo.diff | 115 ++++++++++++++++++ src/test/mir-opt/const_debuginfo.rs | 24 ++++ ...riable.main.SimplifyLocals.after.32bit.mir | 18 +-- ...riable.main.SimplifyLocals.after.64bit.mir | 18 +-- ...ine_scopes_parenting.main.Inline.after.mir | 6 +- ...wer_intrinsics.f_u64.PreCodegen.before.mir | 2 +- ...hange_loop_body.PreCodegen.after.32bit.mir | 6 +- ...hange_loop_body.PreCodegen.after.64bit.mir | 6 +- 23 files changed, 406 insertions(+), 127 deletions(-) create mode 100644 compiler/rustc_mir/src/transform/const_debuginfo.rs create mode 100644 src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff create mode 100644 src/test/mir-opt/const_debuginfo.rs diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 96484034da7c..31e43893ac8b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1409,10 +1409,11 @@ fn generator_layout_and_saved_local_names( let state_arg = mir::Local::new(1); for var in &body.var_debug_info { - if var.place.local != state_arg { + let place = if let mir::VarDebugInfoContents::Place(p) = var.value { p } else { continue }; + if place.local != state_arg { continue; } - match var.place.projection[..] { + match place.projection[..] { [ // Deref of the `Pin<&mut Self>` state argument. mir::ProjectionElem::Field(..), diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index c8001b8daf0d..3a85c268e0ea 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -11,7 +11,7 @@ use super::FunctionCx; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn eval_mir_constant_to_operand( - &mut self, + &self, bx: &mut Bx, constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { @@ -21,7 +21,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } pub fn eval_mir_constant( - &mut self, + &self, constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { match self.monomorphize(constant.literal).val { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index c4191a4e23d9..d5b2cbaa5584 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; use rustc_target::abi::{LayoutOf, Size}; -use super::operand::OperandValue; +use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; use super::{FunctionCx, LocalRef}; @@ -116,6 +116,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { span } + fn spill_operand_to_stack( + operand: &OperandRef<'tcx, Bx::Value>, + name: Option, + bx: &mut Bx, + ) -> PlaceRef<'tcx, Bx::Value> { + // "Spill" the value onto the stack, for debuginfo, + // without forcing non-debuginfo uses of the local + // to also load from the stack every single time. + // FIXME(#68817) use `llvm.dbg.value` instead, + // at least for the cases which LLVM handles correctly. + let spill_slot = PlaceRef::alloca(bx, operand.layout); + if let Some(name) = name { + bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill")); + } + operand.val.store(bx, spill_slot); + spill_slot + } + /// Apply debuginfo and/or name, after creating the `alloca` for a local, /// or initializing the local with an operand (whichever applies). pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { @@ -226,17 +244,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - // "Spill" the value onto the stack, for debuginfo, - // without forcing non-debuginfo uses of the local - // to also load from the stack every single time. - // FIXME(#68817) use `llvm.dbg.value` instead, - // at least for the cases which LLVM handles correctly. - let spill_slot = PlaceRef::alloca(bx, operand.layout); - if let Some(name) = name { - bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill")); - } - operand.val.store(bx, spill_slot); - spill_slot + Self::spill_operand_to_stack(operand, name, bx) } LocalRef::Place(place) => *place, @@ -308,6 +316,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`. pub fn compute_per_local_var_debug_info( &self, + bx: &mut Bx, ) -> Option>>> { let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full; @@ -322,31 +331,63 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { None }; - let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let place = var.place; - let var_ty = self.monomorphized_place_ty(place.as_ref()); - let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg - && place.projection.is_empty() - && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE - { - let arg_index = place.local.index() - 1; - // FIXME(eddyb) shouldn't `ArgumentVariable` indices be - // offset in closures to account for the hidden environment? - // Also, is this `+ 1` needed at all? - VariableKind::ArgumentVariable(arg_index + 1) - } else { - VariableKind::LocalVariable + let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { + let (var_ty, var_kind) = match var.value { + mir::VarDebugInfoContents::Place(place) => { + let var_ty = self.monomorphized_place_ty(place.as_ref()); + let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg + && place.projection.is_empty() + && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE + { + let arg_index = place.local.index() - 1; + + // FIXME(eddyb) shouldn't `ArgumentVariable` indices be + // offset in closures to account for the hidden environment? + // Also, is this `+ 1` needed at all? + VariableKind::ArgumentVariable(arg_index + 1) + } else { + VariableKind::LocalVariable + }; + (var_ty, var_kind) + } + mir::VarDebugInfoContents::Const(c) => { + let ty = self.monomorphize(c.literal.ty); + (ty, VariableKind::LocalVariable) + } }; + self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) }); - per_local[var.place.local].push(PerLocalVarDebugInfo { - name: var.name, - source_info: var.source_info, - dbg_var, - projection: var.place.projection, - }); + match var.value { + mir::VarDebugInfoContents::Place(place) => { + per_local[place.local].push(PerLocalVarDebugInfo { + name: var.name, + source_info: var.source_info, + dbg_var, + projection: place.projection, + }); + } + mir::VarDebugInfoContents::Const(c) => { + if let Some(dbg_var) = dbg_var { + let dbg_loc = match self.dbg_loc(var.source_info) { + Some(dbg_loc) => dbg_loc, + None => continue, + }; + + if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) { + let base = Self::spill_operand_to_stack( + &operand, + Some(var.name.to_string()), + bx, + ); + + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[]); + } + } + } + } } Some(per_local) } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 640f805d5e88..285140060be4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -186,7 +186,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( caller_location: None, }; - fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(); + fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx); for const_ in &mir.required_consts { if let Err(err) = fx.eval_mir_constant(const_) { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 814f91b04310..b54930e8d595 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1060,6 +1060,23 @@ impl<'tcx> LocalDecl<'tcx> { } } +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +pub enum VarDebugInfoContents<'tcx> { + /// NOTE(eddyb) There's an unenforced invariant that this `Place` is + /// based on a `Local`, not a `Static`, and contains no indexing. + Place(Place<'tcx>), + Const(Constant<'tcx>), +} + +impl<'tcx> Debug for VarDebugInfoContents<'tcx> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + match self { + VarDebugInfoContents::Const(c) => write!(fmt, "{}", c), + VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p), + } + } +} + /// Debug information pertaining to a user variable. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] pub struct VarDebugInfo<'tcx> { @@ -1071,9 +1088,7 @@ pub struct VarDebugInfo<'tcx> { pub source_info: SourceInfo, /// Where the data for this user variable is to be found. - /// NOTE(eddyb) There's an unenforced invariant that this `Place` is - /// based on a `Local`, not a `Static`, and contains no indexing. - pub place: Place<'tcx>, + pub value: VarDebugInfoContents<'tcx>, } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 7538818b8afc..e281010eb06e 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -829,16 +829,20 @@ macro_rules! make_mir_visitor { let VarDebugInfo { name: _, source_info, - place, + value, } = var_debug_info; self.visit_source_info(source_info); let location = START_BLOCK.start_location(); - self.visit_place( - place, - PlaceContext::NonUse(NonUseContext::VarDebugInfo), - location, - ); + match value { + VarDebugInfoContents::Const(c) => self.visit_constant(c, location), + VarDebugInfoContents::Place(place) => + self.visit_place( + place, + PlaceContext::NonUse(NonUseContext::VarDebugInfo), + location + ), + } } fn super_source_scope(&mut self, diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index de54c5582e04..3a6316b1ed35 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -11,7 +11,7 @@ use rustc_index::vec::IndexVec; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, - PlaceRef, + PlaceRef, VarDebugInfoContents, }; use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; @@ -133,19 +133,21 @@ fn do_mir_borrowck<'a, 'tcx>( let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); for var_debug_info in &input_body.var_debug_info { - if let Some(local) = var_debug_info.place.as_local() { - if let Some(prev_name) = local_names[local] { - if var_debug_info.name != prev_name { - span_bug!( - var_debug_info.source_info.span, - "local {:?} has many names (`{}` vs `{}`)", - local, - prev_name, - var_debug_info.name - ); + if let VarDebugInfoContents::Place(place) = var_debug_info.value { + if let Some(local) = place.as_local() { + if let Some(prev_name) = local_names[local] { + if var_debug_info.name != prev_name { + span_bug!( + var_debug_info.source_info.span, + "local {:?} has many names (`{}` vs `{}`)", + local, + prev_name, + var_debug_info.name + ); + } } + local_names[local] = Some(var_debug_info.name); } - local_names[local] = Some(var_debug_info.name); } } diff --git a/compiler/rustc_mir/src/transform/const_debuginfo.rs b/compiler/rustc_mir/src/transform/const_debuginfo.rs new file mode 100644 index 000000000000..ed2c48b35680 --- /dev/null +++ b/compiler/rustc_mir/src/transform/const_debuginfo.rs @@ -0,0 +1,98 @@ +//! Finds locals which are assigned once to a const and unused except for debuginfo and converts +//! their debuginfo to use the const directly, allowing the local to be removed. + +use rustc_middle::{ + mir::{ + visit::{PlaceContext, Visitor}, + Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents, + }, + ty::TyCtxt, +}; + +use crate::transform::MirPass; +use rustc_index::{bit_set::BitSet, vec::IndexVec}; + +pub struct ConstDebugInfo; + +impl<'tcx> MirPass<'tcx> for ConstDebugInfo { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + trace!("running ConstDebugInfo on {:?}", body.source); + + for (local, constant) in find_optimization_oportunities(body) { + for debuginfo in &mut body.var_debug_info { + if let VarDebugInfoContents::Place(p) = debuginfo.value { + if p.local == local && p.projection.is_empty() { + trace!( + "changing debug info for {:?} from place {:?} to constant {:?}", + debuginfo.name, + p, + constant + ); + debuginfo.value = VarDebugInfoContents::Const(constant); + } + } + } + } + } +} + +struct LocalUseVisitor { + local_mutating_uses: IndexVec, + local_assignment_locations: IndexVec>, +} + +fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> { + let mut visitor = LocalUseVisitor { + local_mutating_uses: IndexVec::from_elem(0, &body.local_decls), + local_assignment_locations: IndexVec::from_elem(None, &body.local_decls), + }; + + visitor.visit_body(body); + + let mut locals_to_debuginfo = BitSet::new_empty(body.local_decls.len()); + for debuginfo in &body.var_debug_info { + if let VarDebugInfoContents::Place(p) = debuginfo.value { + if let Some(l) = p.as_local() { + locals_to_debuginfo.insert(l); + } + } + } + + let mut eligable_locals = Vec::new(); + for (local, mutating_uses) in visitor.local_mutating_uses.drain_enumerated(..) { + if mutating_uses != 1 || !locals_to_debuginfo.contains(local) { + continue; + } + + if let Some(location) = visitor.local_assignment_locations[local] { + let bb = &body[location.block]; + + // The value is assigned as the result of a call, not a constant + if bb.statements.len() == location.statement_index { + continue; + } + + if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(box c)))) = + &bb.statements[location.statement_index].kind + { + if let Some(local) = p.as_local() { + eligable_locals.push((local, *c)); + } + } + } + } + + eligable_locals +} + +impl<'tcx> Visitor<'tcx> for LocalUseVisitor { + fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { + if context.is_mutating_use() { + self.local_mutating_uses[*local] = self.local_mutating_uses[*local].saturating_add(1); + + if context.is_place_assignment() { + self.local_assignment_locations[*local] = Some(location); + } + } + } +} diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index e86d11e248fc..809e29fb982d 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -21,6 +21,7 @@ pub mod check_consts; pub mod check_packed_ref; pub mod check_unsafety; pub mod cleanup_post_borrowck; +pub mod const_debuginfo; pub mod const_prop; pub mod coverage; pub mod deaggregator; @@ -408,6 +409,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::new("final"), &nrvo::RenameReturnPlace, + &const_debuginfo::ConstDebugInfo, &simplify::SimplifyLocals, &multiple_return_terminators::MultipleReturnTerminators, ]; diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index 27bb1def726e..bea95bf43d21 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -246,14 +246,19 @@ fn get_arm_identity_info<'a, 'tcx>( tmp_assigned_vars.insert(*r); } - let dbg_info_to_adjust: Vec<_> = - debug_info - .iter() - .enumerate() - .filter_map(|(i, var_info)| { - if tmp_assigned_vars.contains(var_info.place.local) { Some(i) } else { None } - }) - .collect(); + let dbg_info_to_adjust: Vec<_> = debug_info + .iter() + .enumerate() + .filter_map(|(i, var_info)| { + if let VarDebugInfoContents::Place(p) = var_info.value { + if tmp_assigned_vars.contains(p.local) { + return Some(i); + } + } + + None + }) + .collect(); Some(ArmIdentityInfo { local_temp_0: local_tmp_s0, @@ -340,9 +345,11 @@ fn optimization_applies<'tcx>( // Check that debug info only points to full Locals and not projections. for dbg_idx in &opt_info.dbg_info_to_adjust { let dbg_info = &var_debug_info[*dbg_idx]; - if !dbg_info.place.projection.is_empty() { - trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, dbg_info.place); - return false; + if let VarDebugInfoContents::Place(p) = dbg_info.value { + if !p.projection.is_empty() { + trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, p); + return false; + } } } @@ -423,9 +430,15 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { // Fix the debug info to point to the right local for dbg_index in opt_info.dbg_info_to_adjust { let dbg_info = &mut debug_info[dbg_index]; - assert!(dbg_info.place.projection.is_empty()); - dbg_info.place.local = opt_info.local_0; - dbg_info.place.projection = opt_info.dbg_projection; + assert!( + matches!(dbg_info.value, VarDebugInfoContents::Place(_)), + "value was not a Place" + ); + if let VarDebugInfoContents::Place(p) = &mut dbg_info.value { + assert!(p.projection.is_empty()); + p.local = opt_info.local_0; + p.projection = opt_info.dbg_projection; + } } trace!("block is now {:?}", bb.statements); diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index 625f1a3e6844..370010d65f0f 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -220,7 +220,7 @@ fn write_graph_label<'tcx, W: Write>( w, r#"debug {} => {};
"#, var_debug_info.name, - escape(&var_debug_info.place) + escape(&var_debug_info.value), )?; } diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index cd60602b088f..b6a1b652cf6a 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -495,7 +495,7 @@ fn write_scope_tree( let indented_debug_info = format!( "{0:1$}debug {2} => {3:?};", - INDENT, indent, var_debug_info.name, var_debug_info.place, + INDENT, indent, var_debug_info.name, var_debug_info.value, ); writeln!( diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 3ee15248ae28..5e7f9ce87607 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1992,7 +1992,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, - place: for_arm_body.into(), + value: VarDebugInfoContents::Place(for_arm_body.into()), }); let locals = if has_guard.0 { let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> { @@ -2011,7 +2011,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, - place: ref_for_guard.into(), + value: VarDebugInfoContents::Place(ref_for_guard.into()), }); LocalsForNode::ForGuard { ref_for_guard, for_arm_body } } else { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index c50389a850ec..fc872da56bca 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -796,7 +796,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name: ident.name, source_info, - place: arg_local.into(), + value: VarDebugInfoContents::Place(arg_local.into()), }); } } @@ -860,10 +860,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: SourceInfo::outermost(tcx_hir.span(var_id)), - place: Place { + value: VarDebugInfoContents::Place(Place { local: closure_env_arg, projection: tcx.intern_place_elems(&projs), - }, + }), }); mutability diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 918e72582d69..2c37b2e78ffa 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -86,7 +86,7 @@ pub fn change_mutability_of_slot() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] + except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_slot() { let _x: u64 = 0; @@ -166,7 +166,7 @@ pub fn change_mutability_of_binding_in_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] + except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_binding_in_pattern() { let (mut _a, _b) = (99u8, 'q'); diff --git a/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff new file mode 100644 index 000000000000..47c3239b8bf2 --- /dev/null +++ b/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -0,0 +1,115 @@ +- // MIR for `main` before ConstDebugInfo ++ // MIR for `main` after ConstDebugInfo + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/const_debuginfo.rs:8:11: 8:11 + let _1: u8; // in scope 0 at $DIR/const_debuginfo.rs:9:9: 9:10 + let mut _5: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:15: 12:20 + let mut _6: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:15: 12:16 + let mut _7: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:19: 12:20 + let mut _8: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:23: 12:24 + let mut _14: u32; // in scope 0 at $DIR/const_debuginfo.rs:21:13: 21:16 + let mut _15: u32; // in scope 0 at $DIR/const_debuginfo.rs:21:19: 21:22 + scope 1 { +- debug x => _1; // in scope 1 at $DIR/const_debuginfo.rs:9:9: 9:10 ++ debug x => const 1_u8; // in scope 1 at $DIR/const_debuginfo.rs:9:9: 9:10 + let _2: u8; // in scope 1 at $DIR/const_debuginfo.rs:10:9: 10:10 + scope 2 { +- debug y => _2; // in scope 2 at $DIR/const_debuginfo.rs:10:9: 10:10 ++ debug y => const 2_u8; // in scope 2 at $DIR/const_debuginfo.rs:10:9: 10:10 + let _3: u8; // in scope 2 at $DIR/const_debuginfo.rs:11:9: 11:10 + scope 3 { +- debug z => _3; // in scope 3 at $DIR/const_debuginfo.rs:11:9: 11:10 ++ debug z => const 3_u8; // in scope 3 at $DIR/const_debuginfo.rs:11:9: 11:10 + let _4: u8; // in scope 3 at $DIR/const_debuginfo.rs:12:9: 12:12 + scope 4 { +- debug sum => _4; // in scope 4 at $DIR/const_debuginfo.rs:12:9: 12:12 ++ debug sum => const 6_u8; // in scope 4 at $DIR/const_debuginfo.rs:12:9: 12:12 + let _9: &str; // in scope 4 at $DIR/const_debuginfo.rs:14:9: 14:10 + scope 5 { +- debug s => _9; // in scope 5 at $DIR/const_debuginfo.rs:14:9: 14:10 ++ debug s => const "hello, world!"; // in scope 5 at $DIR/const_debuginfo.rs:14:9: 14:10 + let _10: (bool, bool, u32); // in scope 5 at $DIR/const_debuginfo.rs:16:9: 16:10 + scope 6 { + debug f => _10; // in scope 6 at $DIR/const_debuginfo.rs:16:9: 16:10 + let _11: std::option::Option; // in scope 6 at $DIR/const_debuginfo.rs:18:9: 18:10 + scope 7 { + debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:18:9: 18:10 + let _12: Point; // in scope 7 at $DIR/const_debuginfo.rs:20:9: 20:10 + scope 8 { + debug p => _12; // in scope 8 at $DIR/const_debuginfo.rs:20:9: 20:10 + let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:21:9: 21:10 + scope 9 { +- debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:21:9: 21:10 ++ debug a => const 64_u32; // in scope 9 at $DIR/const_debuginfo.rs:21:9: 21:10 + } + } + } + } + } + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/const_debuginfo.rs:9:9: 9:10 + _1 = const 1_u8; // scope 0 at $DIR/const_debuginfo.rs:9:13: 9:16 + StorageLive(_2); // scope 1 at $DIR/const_debuginfo.rs:10:9: 10:10 + _2 = const 2_u8; // scope 1 at $DIR/const_debuginfo.rs:10:13: 10:16 + StorageLive(_3); // scope 2 at $DIR/const_debuginfo.rs:11:9: 11:10 + _3 = const 3_u8; // scope 2 at $DIR/const_debuginfo.rs:11:13: 11:16 + StorageLive(_4); // scope 3 at $DIR/const_debuginfo.rs:12:9: 12:12 + StorageLive(_5); // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:20 + StorageLive(_6); // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:16 + _6 = const 1_u8; // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:16 + StorageLive(_7); // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20 + _7 = const 2_u8; // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20 + _5 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:20 + StorageDead(_7); // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20 + StorageDead(_6); // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20 + StorageLive(_8); // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24 + _8 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24 + _4 = const 6_u8; // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:24 + StorageDead(_8); // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24 + StorageDead(_5); // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24 + StorageLive(_9); // scope 4 at $DIR/const_debuginfo.rs:14:9: 14:10 + _9 = const "hello, world!"; // scope 4 at $DIR/const_debuginfo.rs:14:13: 14:28 + // ty::Const + // + ty: &str + // + val: Value(Slice { data: Allocation { bytes: [104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [8191], len: Size { raw: 13 } }, size: Size { raw: 13 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 13 }) + // mir::Constant + // + span: $DIR/const_debuginfo.rs:14:13: 14:28 + // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [8191], len: Size { raw: 13 } }, size: Size { raw: 13 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 13 }) } + StorageLive(_10); // scope 5 at $DIR/const_debuginfo.rs:16:9: 16:10 + (_10.0: bool) = const true; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34 + (_10.1: bool) = const false; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34 + (_10.2: u32) = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34 + StorageLive(_11); // scope 6 at $DIR/const_debuginfo.rs:18:9: 18:10 + ((_11 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24 + discriminant(_11) = 1; // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24 + StorageLive(_12); // scope 7 at $DIR/const_debuginfo.rs:20:9: 20:10 + (_12.0: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35 + (_12.1: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35 + StorageLive(_13); // scope 8 at $DIR/const_debuginfo.rs:21:9: 21:10 + StorageLive(_14); // scope 8 at $DIR/const_debuginfo.rs:21:13: 21:16 + _14 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:21:13: 21:16 + StorageLive(_15); // scope 8 at $DIR/const_debuginfo.rs:21:19: 21:22 + _15 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:21:19: 21:22 + _13 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:21:13: 21:22 + StorageDead(_15); // scope 8 at $DIR/const_debuginfo.rs:21:21: 21:22 + StorageDead(_14); // scope 8 at $DIR/const_debuginfo.rs:21:21: 21:22 + _0 = const (); // scope 0 at $DIR/const_debuginfo.rs:8:11: 22:2 + StorageDead(_13); // scope 8 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_12); // scope 7 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_11); // scope 6 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_10); // scope 5 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_2); // scope 1 at $DIR/const_debuginfo.rs:22:1: 22:2 + StorageDead(_1); // scope 0 at $DIR/const_debuginfo.rs:22:1: 22:2 + return; // scope 0 at $DIR/const_debuginfo.rs:22:2: 22:2 + } + } + diff --git a/src/test/mir-opt/const_debuginfo.rs b/src/test/mir-opt/const_debuginfo.rs new file mode 100644 index 000000000000..a66d66c60c7a --- /dev/null +++ b/src/test/mir-opt/const_debuginfo.rs @@ -0,0 +1,24 @@ +// compile-flags: -C overflow-checks=no + +struct Point { + x: u32, + y: u32, +} + +fn main() { + let x = 1u8; + let y = 2u8; + let z = 3u8; + let sum = x + y + z; + + let s = "hello, world!"; + + let f = (true, false, 123u32); + + let o = Some(99u16); + + let p = Point { x: 32, y: 32 }; + let a = p.x + p.y; +} + +// EMIT_MIR const_debuginfo.main.ConstDebugInfo.diff diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir index a78a6341c299..e4fbba3abfea 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir @@ -2,30 +2,18 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 - let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 scope 1 { - debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + debug x => const 4_i32; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 - let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + debug y => const 3_i32; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 3 { - debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + debug z => const 42_u32; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 - _2 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 - StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 - _3 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 _0 = const (); // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 - StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir index a78a6341c299..e4fbba3abfea 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir @@ -2,30 +2,18 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 - let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 scope 1 { - debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + debug x => const 4_i32; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 - let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + debug y => const 3_i32; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 3 { - debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + debug z => const 42_u32; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 - _2 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 - StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 - _3 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 _0 = const (); // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 - StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir index 3d386e3b1756..4abbad2c1efc 100644 --- a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir @@ -11,9 +11,8 @@ fn main() -> () { debug f => _1; // in scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10 scope 2 (inlined main::{closure#0}) { // at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 debug x => _5; // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 - let _6: (); // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 scope 3 { - debug y => _6; // in scope 3 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + debug y => const (); // in scope 3 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 } } } @@ -27,10 +26,7 @@ fn main() -> () { (_3.0: ()) = move _4; // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 StorageLive(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 _5 = move (_3.0: ()); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 - StorageLive(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 - _6 = const (); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 _0 = const (); // scope 3 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 - StorageDead(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 StorageDead(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 StorageDead(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:9: 6:10 StorageDead(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:9: 6:10 diff --git a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir index 654dd8275c9d..bd4f148285b1 100644 --- a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir +++ b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir @@ -3,7 +3,7 @@ fn f_u64() -> () { let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:16 scope 1 (inlined f_dispatch::) { // at $DIR/lower_intrinsics.rs:35:5: 35:21 - debug t => _2; // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 + debug t => const 0_u64; // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 let _1: (); // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 let mut _2: u64; // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 scope 2 (inlined std::mem::size_of::) { // at $DIR/lower_intrinsics.rs:35:5: 35:21 diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir index dae0cbb65a4b..cb3632e0fb13 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir +++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir @@ -2,16 +2,12 @@ fn change_loop_body() -> () { let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27 - let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 scope 1 { - debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 + debug _x => const 0_i32; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 } bb0: { - StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 - _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19 _0 = const (); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 - StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir index dae0cbb65a4b..cb3632e0fb13 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir +++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir @@ -2,16 +2,12 @@ fn change_loop_body() -> () { let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27 - let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 scope 1 { - debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 + debug _x => const 0_i32; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 } bb0: { - StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 - _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19 _0 = const (); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 - StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 } } From e90b977a082eac4283a52b53d4da3a507a8ee9a0 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Sun, 22 Nov 2020 22:04:18 +0900 Subject: [PATCH 118/719] Fix FP in `unnecessary_lazy_evaluations` --- clippy_lints/src/utils/usage.rs | 21 ++++++++++++++------- tests/ui/unnecessary_lazy_eval_unfixable.rs | 4 ++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index a7d0ea6ccfbb..fc0db7f64ec9 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -116,20 +116,27 @@ pub struct ParamBindingIdCollector { } impl<'tcx> ParamBindingIdCollector { fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec { - let mut finder = ParamBindingIdCollector { - binding_hir_ids: Vec::new(), - }; - finder.visit_body(body); - finder.binding_hir_ids + let mut hir_ids: Vec = Vec::new(); + for param in body.params.iter() { + let mut finder = ParamBindingIdCollector { + binding_hir_ids: Vec::new(), + }; + finder.visit_param(param); + for hir_id in &finder.binding_hir_ids { + hir_ids.push(*hir_id); + } + } + hir_ids } } impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector { type Map = Map<'tcx>; - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - if let hir::PatKind::Binding(_, hir_id, ..) = param.pat.kind { + fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { + if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind { self.binding_hir_ids.push(hir_id); } + intravisit::walk_pat(self, pat); } fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.rs b/tests/ui/unnecessary_lazy_eval_unfixable.rs index 2e923bc97a2e..b05dd143bfd7 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.rs +++ b/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -15,4 +15,8 @@ fn main() { } let _ = Ok(1).unwrap_or_else(|e::E| 2); let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); + + // Fix #6343 + let arr = [(Some(1),)]; + Some(&0).and_then(|&i| arr[i].0); } From ba1249465c036b2ccc6daf34749ea9d5df77f358 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Mon, 7 Dec 2020 16:45:10 +0900 Subject: [PATCH 119/719] cargo dev fmt --- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 7 ++++--- clippy_lints/src/pass_by_ref_or_value.rs | 7 ++++--- clippy_lints/src/redundant_clone.rs | 5 ++++- clippy_lints/src/types.rs | 4 +++- clippy_lints/src/unnecessary_wraps.rs | 5 ++++- clippy_lints/src/utils/ast_utils.rs | 5 ++++- clippy_lints/src/utils/mod.rs | 2 +- 9 files changed, 26 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index edecba57e44f..55e4755c278a 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -480,7 +480,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, span: Span) { | ItemKind::ForeignMod(..) => return false, // We found a main function ... ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym::main => { - let is_async = matches!(sig.header.asyncness, Async::Yes{..}); + let is_async = matches!(sig.header.asyncness, Async::Yes { .. }); let returns_nothing = match &sig.decl.output { FnRetTy::Default(..) => true, FnRetTy::Ty(ty) if ty.kind.is_unit() => true, diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 25245b3dbf08..38e2ce563eeb 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let has_const_generic_params = generics .params .iter() - .any(|param| matches!(param.kind, GenericParamKind::Const{ .. })); + .any(|param| matches!(param.kind, GenericParamKind::Const { .. })); if already_const(header) || has_const_generic_params { return; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 532c0266946b..5043b7b1fc3c 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -90,9 +90,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { // Exclude non-inherent impls if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { - if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), .. } | - ItemKind::Trait(..)) - { + if matches!( + item.kind, + ItemKind::Impl { of_trait: Some(_), .. } | ItemKind::Trait(..) + ) { return; } } diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index f03facc235e2..6a17d654ac94 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -244,9 +244,10 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { // Exclude non-inherent impls if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { - if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), .. } | - ItemKind::Trait(..)) - { + if matches!( + item.kind, + ItemKind::Impl { of_trait: Some(_), .. } | ItemKind::Trait(..) + ) { return; } } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index f0e507105a6a..06adbb523d70 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -390,7 +390,10 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor { let local = place.local; if local == self.used.0 - && !matches!(ctx, PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_)) + && !matches!( + ctx, + PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_) + ) { self.used.1 = true; } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 74ba53e6a9a0..fd74783335d5 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1104,7 +1104,9 @@ fn is_empty_block(expr: &Expr<'_>) -> bool { expr.kind, ExprKind::Block( Block { - stmts: &[], expr: None, .. + stmts: &[], + expr: None, + .. }, _, ) diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 5d801511a0b1..e763da593d49 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -74,7 +74,10 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { - if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), ..} | ItemKind::Trait(..)) { + if matches!( + item.kind, + ItemKind::Impl { of_trait: Some(_), .. } | ItemKind::Trait(..) + ) { return; } } diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 31b4e25411bd..f0267e4c7928 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -408,7 +408,10 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool { } pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool { - matches!((l, r), (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_))) + matches!( + (l, r), + (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)) + ) } pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 3a6b64c90e8f..007e72d129f7 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1500,7 +1500,7 @@ pub fn is_no_std_crate(krate: &Crate<'_>) -> bool { /// ``` pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool { if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { - matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), .. }) + matches!(item.kind, ItemKind::Impl { of_trait: Some(_), .. }) } else { false } From 97c7022d08fac94c09f671322c0696d65a75cca0 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 7 Dec 2020 17:33:43 +0200 Subject: [PATCH 120/719] rustc_codegen_ssa: use bitcasts instead of type punning for scalar transmutes. --- compiler/rustc_codegen_ssa/src/mir/block.rs | 19 +++++++++++ src/test/codegen/transmute-scalar.rs | 35 +++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/test/codegen/transmute-scalar.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e59832a8eed5..ce56f1635495 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1395,6 +1395,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dst: PlaceRef<'tcx, Bx::Value>, ) { let src = self.codegen_operand(bx, src); + + // Special-case transmutes between scalars as simple bitcasts. + match (&src.layout.abi, &dst.layout.abi) { + (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => { + // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers. + if (src_scalar.value == abi::Pointer) == (dst_scalar.value == abi::Pointer) { + assert_eq!(src.layout.size, dst.layout.size); + + // NOTE(eddyb) the `from_immediate` and `to_immediate_scalar` + // conversions allow handling `bool`s the same as `u8`s. + let src = bx.from_immediate(src.immediate()); + let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout)); + Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst); + return; + } + } + _ => {} + } + let llty = bx.backend_type(src.layout); let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty)); let align = src.layout.align.abi.min(dst.align); diff --git a/src/test/codegen/transmute-scalar.rs b/src/test/codegen/transmute-scalar.rs new file mode 100644 index 000000000000..48aea4a2f086 --- /dev/null +++ b/src/test/codegen/transmute-scalar.rs @@ -0,0 +1,35 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// CHECK: define i32 @f32_to_bits(float %x) +// CHECK: %2 = bitcast float %x to i32 +// CHECK-NEXT: store i32 %2, i32* %0 +// CHECK-NEXT: %3 = load i32, i32* %0 +// CHECK: ret i32 %3 +#[no_mangle] +pub fn f32_to_bits(x: f32) -> u32 { + unsafe { std::mem::transmute(x) } +} + +// CHECK: define i8 @bool_to_byte(i1 zeroext %b) +// CHECK: %1 = zext i1 %b to i8 +// CHECK-NEXT: store i8 %1, i8* %0 +// CHECK-NEXT: %2 = load i8, i8* %0 +// CHECK: ret i8 %2 +#[no_mangle] +pub fn bool_to_byte(b: bool) -> u8 { + unsafe { std::mem::transmute(b) } +} + +// CHECK: define zeroext i1 @byte_to_bool(i8 %byte) +// CHECK: %1 = trunc i8 %byte to i1 +// CHECK-NEXT: %2 = zext i1 %1 to i8 +// CHECK-NEXT: store i8 %2, i8* %0 +// CHECK-NEXT: %3 = load i8, i8* %0 +// CHECK-NEXT: %4 = trunc i8 %3 to i1 +// CHECK: ret i1 %4 +#[no_mangle] +pub unsafe fn byte_to_bool(byte: u8) -> bool { + std::mem::transmute(byte) +} From bdda98aaba493be28569083c5ac57629caf3504d Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Mon, 7 Dec 2020 18:59:10 +0100 Subject: [PATCH 121/719] Add comment for assert_inhabited in compiler/rustc_mir/src/interpret/intrinsics.rs Co-authored-by: Ralf Jung --- compiler/rustc_mir/src/interpret/intrinsics.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index c25a312bb5af..2ffb7a05f25c 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -412,6 +412,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of(ty)?; if layout.abi.is_uninhabited() { + // The run-time intrinsic panics just to get a good backtrace; here we abort + // since there is no problem showing a backtrace even for aborts. M::abort(self, format!("attempted to instantiate uninhabited type `{}`", ty))?; } } From 12db2225b6e82b861597d1a98c018d56100a741c Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Mon, 7 Dec 2020 11:59:24 -0700 Subject: [PATCH 122/719] Dogfood 'str_split_once() with `compiler/` --- compiler/rustc_mir/src/lib.rs | 1 + .../rustc_mir/src/transform/coverage/debug.rs | 48 ++++---- compiler/rustc_session/src/config.rs | 109 ++++++++---------- compiler/rustc_session/src/lib.rs | 1 + compiler/rustc_session/src/options.rs | 7 +- compiler/rustc_target/src/lib.rs | 1 + compiler/rustc_target/src/spec/apple_base.rs | 5 +- 7 files changed, 83 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 2ed115b12971..e6d822086f52 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -28,6 +28,7 @@ Rust MIR: a lowered representation of Rust. #![feature(or_patterns)] #![feature(once_cell)] #![feature(control_flow_enum)] +#![feature(str_split_once)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs index e9528557b333..1347656c23ea 100644 --- a/compiler/rustc_mir/src/transform/coverage/debug.rs +++ b/compiler/rustc_mir/src/transform/coverage/debug.rs @@ -148,23 +148,19 @@ impl DebugOptions { if let Ok(env_debug_options) = std::env::var(RUSTC_COVERAGE_DEBUG_OPTIONS) { for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(',') { - let mut setting = setting_str.splitn(2, '='); - match setting.next() { - Some(option) if option == "allow_unused_expressions" => { - allow_unused_expressions = bool_option_val(option, setting.next()); - debug!( - "{} env option `allow_unused_expressions` is set to {}", - RUSTC_COVERAGE_DEBUG_OPTIONS, allow_unused_expressions - ); - } - Some(option) if option == "counter_format" => { - if let Some(strval) = setting.next() { - counter_format = counter_format_option_val(strval); - debug!( - "{} env option `counter_format` is set to {:?}", - RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format - ); - } else { + let (option, value) = match setting_str.split_once('=') { + None => (setting_str, None), + Some((k, v)) => (k, Some(v)), + }; + if option == "allow_unused_expressions" { + allow_unused_expressions = bool_option_val(option, value); + debug!( + "{} env option `allow_unused_expressions` is set to {}", + RUSTC_COVERAGE_DEBUG_OPTIONS, allow_unused_expressions + ); + } else if option == "counter_format" { + match value { + None => { bug!( "`{}` option in environment variable {} requires one or more \ plus-separated choices (a non-empty subset of \ @@ -173,14 +169,20 @@ impl DebugOptions { RUSTC_COVERAGE_DEBUG_OPTIONS ); } - } - Some("") => {} - Some(invalid) => bug!( + Some(val) => { + counter_format = counter_format_option_val(val); + debug!( + "{} env option `counter_format` is set to {:?}", + RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format + ); + } + }; + } else { + bug!( "Unsupported setting `{}` in environment variable {}", - invalid, + option, RUSTC_COVERAGE_DEBUG_OPTIONS - ), - None => {} + ) } } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b648e14360c0..54abb65dc388 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1296,8 +1296,10 @@ fn parse_output_types( if !debugging_opts.parse_only { for list in matches.opt_strs("emit") { for output_type in list.split(',') { - let mut parts = output_type.splitn(2, '='); - let shorthand = parts.next().unwrap(); + let (shorthand, path) = match output_type.split_once('=') { + None => (output_type, None), + Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))), + }; let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { early_error( error_format, @@ -1308,7 +1310,6 @@ fn parse_output_types( ), ) }); - let path = parts.next().map(PathBuf::from); output_types.insert(output_type, path); } } @@ -1452,11 +1453,10 @@ fn parse_opt_level( let max_c = matches .opt_strs_pos("C") .into_iter() - .flat_map( - |(i, s)| { - if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None } - }, - ) + .flat_map(|(i, s)| { + // NB: This can match a string without `=`. + if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None } + }) .max(); if max_o > max_c { OptLevel::Default @@ -1491,11 +1491,10 @@ fn select_debuginfo( let max_c = matches .opt_strs_pos("C") .into_iter() - .flat_map( - |(i, s)| { - if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None } - }, - ) + .flat_map(|(i, s)| { + // NB: This can match a string without `=`. + if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None } + }) .max(); if max_g > max_c { DebugInfo::Full @@ -1528,23 +1527,26 @@ fn parse_libs( .map(|s| { // Parse string of the form "[KIND=]lib[:new_name]", // where KIND is one of "dylib", "framework", "static". - let mut parts = s.splitn(2, '='); - let kind = parts.next().unwrap(); - let (name, kind) = match (parts.next(), kind) { - (None, name) => (name, NativeLibKind::Unspecified), - (Some(name), "dylib") => (name, NativeLibKind::Dylib), - (Some(name), "framework") => (name, NativeLibKind::Framework), - (Some(name), "static") => (name, NativeLibKind::StaticBundle), - (Some(name), "static-nobundle") => (name, NativeLibKind::StaticNoBundle), - (_, s) => { - early_error( - error_format, - &format!( - "unknown library kind `{}`, expected \ - one of dylib, framework, or static", - s - ), - ); + let (name, kind) = match s.split_once('=') { + None => (s, NativeLibKind::Unspecified), + Some((kind, name)) => { + let kind = match kind { + "dylib" => NativeLibKind::Dylib, + "framework" => NativeLibKind::Framework, + "static" => NativeLibKind::StaticBundle, + "static-nobundle" => NativeLibKind::StaticNoBundle, + s => { + early_error( + error_format, + &format!( + "unknown library kind `{}`, expected \ + one of dylib, framework, or static", + s + ), + ); + } + }; + (name.to_string(), kind) } }; if kind == NativeLibKind::StaticNoBundle @@ -1556,10 +1558,11 @@ fn parse_libs( accepted on the nightly compiler", ); } - let mut name_parts = name.splitn(2, ':'); - let name = name_parts.next().unwrap(); - let new_name = name_parts.next(); - (name.to_owned(), new_name.map(|n| n.to_owned()), kind) + let (name, new_name) = match name.split_once(':') { + None => (name, None), + Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())), + }; + (name, new_name, kind) }) .collect() } @@ -1580,20 +1583,13 @@ pub fn parse_externs( let is_unstable_enabled = debugging_opts.unstable_options; let mut externs: BTreeMap = BTreeMap::new(); for arg in matches.opt_strs("extern") { - let mut parts = arg.splitn(2, '='); - let name = parts - .next() - .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty")); - let path = parts.next().map(|s| s.to_string()); - - let mut name_parts = name.splitn(2, ':'); - let first_part = name_parts.next(); - let second_part = name_parts.next(); - let (options, name) = match (first_part, second_part) { - (Some(opts), Some(name)) => (Some(opts), name), - (Some(name), None) => (None, name), - (None, None) => early_error(error_format, "--extern name must not be empty"), - _ => unreachable!(), + let (name, path) = match arg.split_once('=') { + None => (arg, None), + Some((name, path)) => (name.to_string(), Some(path.to_string())), + }; + let (options, name) = match name.split_once(':') { + None => (None, name), + Some((opts, name)) => (Some(opts), name.to_string()), }; let entry = externs.entry(name.to_owned()); @@ -1682,17 +1678,12 @@ fn parse_remap_path_prefix( matches .opt_strs("remap-path-prefix") .into_iter() - .map(|remap| { - let mut parts = remap.rsplitn(2, '='); // reverse iterator - let to = parts.next(); - let from = parts.next(); - match (from, to) { - (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)), - _ => early_error( - error_format, - "--remap-path-prefix must contain '=' between FROM and TO", - ), - } + .map(|remap| match remap.rsplit_once('=') { + None => early_error( + error_format, + "--remap-path-prefix must contain '=' between FROM and TO", + ), + Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), }) .collect() } diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index d002f5973916..36bf8634c6ee 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,6 +1,7 @@ #![feature(crate_visibility_modifier)] #![feature(once_cell)] #![feature(or_patterns)] +#![feature(str_split_once)] #[macro_use] extern crate bitflags; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 91ebc9a7c82e..74578f2dc179 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -179,9 +179,10 @@ macro_rules! options { { let mut op = $defaultfn(); for option in matches.opt_strs($prefix) { - let mut iter = option.splitn(2, '='); - let key = iter.next().unwrap(); - let value = iter.next(); + let (key, value) = match option.split_once('=') { + None => (option, None), + Some((k, v)) => (k.to_string(), Some(v)), + }; let option_to_lookup = key.replace("-", "_"); let mut found = false; for &(candidate, setter, type_desc, _) in $stat { diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index fb747dfcbd33..1ad57582ebaf 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -15,6 +15,7 @@ #![feature(never_type)] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] +#![feature(str_split_once)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index e271a6dec40d..884223952164 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -54,10 +54,7 @@ fn macos_deployment_target() -> (u32, u32) { let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok(); let version = deployment_target .as_ref() - .and_then(|s| { - let mut i = s.splitn(2, '.'); - i.next().and_then(|a| i.next().map(|b| (a, b))) - }) + .and_then(|s| s.split_once('.')) .and_then(|(a, b)| a.parse::().and_then(|a| b.parse::().map(|b| (a, b))).ok()); version.unwrap_or((10, 7)) From d6baf3875cb9a3bbf3ebd2f7b33ab7f204b5908e Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Mon, 7 Dec 2020 12:54:55 -0700 Subject: [PATCH 123/719] Dogfood 'str_split_once() with Tidy --- src/tools/tidy/src/cargo.rs | 9 +-- src/tools/tidy/src/error_codes_check.rs | 97 ++++++++++++++----------- src/tools/tidy/src/extdeps.rs | 2 +- src/tools/tidy/src/features.rs | 1 + src/tools/tidy/src/lib.rs | 2 + src/tools/tidy/src/ui_tests.rs | 10 +-- 6 files changed, 64 insertions(+), 57 deletions(-) diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs index 7bdd78a91e7d..e06616a59f38 100644 --- a/src/tools/tidy/src/cargo.rs +++ b/src/tools/tidy/src/cargo.rs @@ -59,11 +59,10 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { break; } - let mut parts = line.splitn(2, '='); - let krate = parts.next().unwrap().trim(); - if parts.next().is_none() { - continue; - } + let krate = match line.split_once('=') { + None => continue, + Some((krate, _)) => krate.trim(), + }; // Don't worry about depending on core/std while not writing `extern crate // core/std` -- that's intentional. diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 82a5234ac5b2..1c175901be8d 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -85,47 +85,55 @@ fn extract_error_codes( for line in f.lines() { let s = line.trim(); if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") { - if let Some(err_code) = s.splitn(2, ':').next() { - let err_code = err_code.to_owned(); - if !error_codes.contains_key(&err_code) { - error_codes.insert(err_code.clone(), false); + let err_code = match s.split_once(':') { + None => continue, + Some((err_code, _)) => err_code.to_owned(), + }; + if !error_codes.contains_key(&err_code) { + error_codes.insert(err_code.clone(), false); + } + // Now we extract the tests from the markdown file! + let md_file_name = match s.split_once("include_str!(\"") { + None => continue, + Some((_, md)) => match md.split_once("\")") { + None => continue, + Some((file_name, _)) => file_name, + }, + }; + let path = some_or_continue!(path.parent()) + .join(md_file_name) + .canonicalize() + .expect("failed to canonicalize error explanation file path"); + match read_to_string(&path) { + Ok(content) => { + if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) + && !check_if_error_code_is_test_in_explanation(&content, &err_code) + { + errors.push(format!( + "`{}` doesn't use its own error code in compile_fail example", + path.display(), + )); + } + if check_error_code_explanation(&content, error_codes, err_code) { + errors.push(format!( + "`{}` uses invalid tag `compile-fail` instead of `compile_fail`", + path.display(), + )); + } } - // Now we extract the tests from the markdown file! - let md = some_or_continue!(s.splitn(2, "include_str!(\"").nth(1)); - let md_file_name = some_or_continue!(md.splitn(2, "\")").next()); - let path = some_or_continue!(path.parent()) - .join(md_file_name) - .canonicalize() - .expect("failed to canonicalize error explanation file path"); - match read_to_string(&path) { - Ok(content) => { - if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) - && !check_if_error_code_is_test_in_explanation(&content, &err_code) - { - errors.push(format!( - "`{}` doesn't use its own error code in compile_fail example", - path.display(), - )); - } - if check_error_code_explanation(&content, error_codes, err_code) { - errors.push(format!( - "`{}` uses invalid tag `compile-fail` instead of `compile_fail`", - path.display(), - )); - } - } - Err(e) => { - eprintln!("Couldn't read `{}`: {}", path.display(), e); - } + Err(e) => { + eprintln!("Couldn't read `{}`: {}", path.display(), e); } } } else if reached_no_explanation && s.starts_with('E') { - if let Some(err_code) = s.splitn(2, ',').next() { - let err_code = err_code.to_owned(); - if !error_codes.contains_key(&err_code) { - // this check should *never* fail! - error_codes.insert(err_code, false); - } + let err_code = match s.split_once(',') { + None => s, + Some((err_code, _)) => err_code, + } + .to_string(); + if !error_codes.contains_key(&err_code) { + // this check should *never* fail! + error_codes.insert(err_code, false); } } else if s == ";" { reached_no_explanation = true; @@ -137,12 +145,15 @@ fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap continue, + Some((err_code, _)) => match err_code.split_once('[') { + None => continue, + Some((_, err_code)) => err_code, + }, + }; + let nb = error_codes.entry(err_code.to_owned()).or_insert(false); + *nb = true; } } } diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index 1cf0d24e26ff..93d4d3d8047d 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -23,7 +23,7 @@ pub fn check(root: &Path, bad: &mut bool) { } // Extract source value. - let source = line.splitn(2, '=').nth(1).unwrap().trim(); + let source = line.split_once('=').unwrap().1.trim(); // Ensure source is allowed. if !ALLOWED_SOURCES.contains(&&*source) { diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d8029ea04f0b..3c2880d0d5e2 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -112,6 +112,7 @@ pub fn check( let gate_test_str = "gate-test-"; let feature_name = match line.find(gate_test_str) { + // NB: the `splitn` always succeeds, even if the delimiter is not present. Some(i) => line[i + gate_test_str.len()..].splitn(2, ' ').next().unwrap(), None => continue, }; diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index cc4c43f0468a..e11d293210b0 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -3,6 +3,8 @@ //! This library contains the tidy lints and exposes it //! to be used by tools. +#![feature(str_split_once)] + use std::fs::File; use std::io::Read; use walkdir::{DirEntry, WalkDir}; diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 47b328dae47f..4c8c1d58ed72 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -19,14 +19,8 @@ pub fn check(path: &Path, bad: &mut bool) { // // For now, just make sure that there is a corresponding // `$testname.rs` file. - let testname = file_path - .file_name() - .unwrap() - .to_str() - .unwrap() - .splitn(2, '.') - .next() - .unwrap(); + let testname = + file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0; if !file_path.with_file_name(testname).with_extension("rs").exists() { println!("Stray file with UI testing output: {:?}", file_path); *bad = true; From 69ab0bcabff34b97cd8fe9f0c741748a9ffc8928 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Mon, 7 Dec 2020 21:26:09 +0100 Subject: [PATCH 124/719] Use 'error-pattern' in ui test --- src/test/ui/assume-type-intrinsics.rs | 4 +++- src/test/ui/assume-type-intrinsics.stderr | 19 +++---------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/assume-type-intrinsics.rs index 8e9cb3345274..77370e1ccc59 100644 --- a/src/test/ui/assume-type-intrinsics.rs +++ b/src/test/ui/assume-type-intrinsics.rs @@ -1,11 +1,13 @@ +// error-pattern: any use of this value will cause an error + #![feature(never_type)] #![feature(const_maybe_uninit_assume_init)] +#[allow(invalid_value)] fn main() { use std::mem::MaybeUninit; const _BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); - //~^ WARN: the type `!` does not permit being left uninitialized }; } diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/assume-type-intrinsics.stderr index b776915affdb..6f400086a548 100644 --- a/src/test/ui/assume-type-intrinsics.stderr +++ b/src/test/ui/assume-type-intrinsics.stderr @@ -6,29 +6,16 @@ LL | intrinsics::assert_inhabited::(); | | | attempted to instantiate uninhabited type `!` | inside `MaybeUninit::::assume_init` at $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL - | inside `_BAD` at $DIR/assume-type-intrinsics.rs:8:9 + | inside `_BAD` at $DIR/assume-type-intrinsics.rs:11:9 | - ::: $DIR/assume-type-intrinsics.rs:7:5 + ::: $DIR/assume-type-intrinsics.rs:10:5 | LL | / const _BAD: () = unsafe { LL | | MaybeUninit::::uninit().assume_init(); -LL | | LL | | }; | |______- | = note: `#[deny(const_err)]` on by default -warning: the type `!` does not permit being left uninitialized - --> $DIR/assume-type-intrinsics.rs:8:9 - | -LL | MaybeUninit::::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: `#[warn(invalid_value)]` on by default - = note: the `!` type has no valid value - -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error From 7bd47bd7a14a32be27382677a98d7a031785fc6e Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Mon, 7 Dec 2020 13:39:30 -0700 Subject: [PATCH 125/719] Dogfood 'str_split_once() with linkchecker --- src/tools/linkchecker/main.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index f213944e0ab6..dcfe1bb803fb 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -14,6 +14,8 @@ //! A few exceptions are allowed as there's known bugs in rustdoc, but this //! should catch the majority of "broken link" cases. +#![feature(str_split_once)] + use std::collections::hash_map::Entry; use std::collections::{HashMap, HashSet}; use std::env; @@ -232,11 +234,12 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti { return; } - let mut parts = url.splitn(2, '#'); - let url = parts.next().unwrap(); - let fragment = parts.next(); - let mut parts = url.splitn(2, '?'); - let url = parts.next().unwrap(); + let (url, fragment) = match url.split_once('#') { + None => (url, None), + Some((url, fragment)) => (url, Some(fragment)), + }; + // NB: the `splitn` always succeeds, even if the delimiter is not present. + let url = url.splitn(2, '?').next().unwrap(); // Once we've plucked out the URL, parse it using our base url and // then try to extract a file path. From 85e9ea015220cc74dc54873974ed7138ea22eced Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Mon, 7 Dec 2020 14:00:31 -0700 Subject: [PATCH 126/719] Dogfood 'str_split_once() with librustdoc --- src/librustdoc/config.rs | 15 +++++---------- src/librustdoc/html/render/mod.rs | 6 ++---- src/librustdoc/lib.rs | 1 + src/librustdoc/passes/collect_intra_doc_links.rs | 7 ++++--- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index e60970af0d34..2d58614b1397 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -397,12 +397,9 @@ impl Options { matches .opt_strs("default-setting") .iter() - .map(|s| { - let mut kv = s.splitn(2, '='); - // never panics because `splitn` always returns at least one element - let k = kv.next().unwrap().to_string(); - let v = kv.next().unwrap_or("true").to_string(); - (k, v) + .map(|s| match s.split_once('=') { + None => (s.clone(), "true".to_string()), + Some((k, v)) => (k.to_string(), v.to_string()), }) .collect(), ]; @@ -707,11 +704,9 @@ fn parse_extern_html_roots( ) -> Result, &'static str> { let mut externs = BTreeMap::new(); for arg in &matches.opt_strs("extern-html-root-url") { - let mut parts = arg.splitn(2, '='); - let name = parts.next().ok_or("--extern-html-root-url must not be empty")?; - let url = parts.next().ok_or("--extern-html-root-url must be of the form name=url")?; + let (name, url) = + arg.split_once('=').ok_or("--extern-html-root-url must be of the form name=url")?; externs.insert(name.to_string(), url.to_string()); } - Ok(externs) } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 901f00b21da9..efee4c0be06d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -167,10 +167,8 @@ impl Context { // `style-suffix.min.css`. Path::extension would just return `css` // which would result in `style.min-suffix.css` which isn't what we // want. - let mut iter = filename.splitn(2, '.'); - let base = iter.next().unwrap(); - let ext = iter.next().unwrap(); - let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext,); + let (base, ext) = filename.split_once('.').unwrap(); + let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext); self.dst.join(&filename) } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 26bf4b569ff4..f851d1a23723 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -16,6 +16,7 @@ #![feature(once_cell)] #![feature(type_ascription)] #![feature(split_inclusive)] +#![feature(str_split_once)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 551c086a8d4e..fdbab74be50d 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -435,8 +435,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); - // this can be an `unwrap()` because we ensure the link is never empty - let (item_str, item_name) = split.next().map(|i| (i, Symbol::intern(i))).unwrap(); + // NB: the `splitn`'s first element is always defined, even if the delimiter is not present. + let item_str = split.next().unwrap(); + let item_name = Symbol::intern(item_str); let path_root = split .next() .map(|f| f.to_owned()) @@ -447,7 +448,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ResolutionFailure::NotResolved { module_id, partial_res: None, - unresolved: item_str.into(), + unresolved: path_str.into(), } })?; From d2de69da2e99d43e14a80219b835aaf513c2f0d9 Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Mon, 7 Dec 2020 14:24:05 -0700 Subject: [PATCH 127/719] Dogfood 'str_split_once()` in the std lib --- library/std/src/lib.rs | 1 + library/std/src/sys_common/net.rs | 4 +--- library/test/src/lib.rs | 1 + library/test/src/time.rs | 24 +++++++++--------------- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 6c240cb4c3ed..aba474455639 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -312,6 +312,7 @@ #![feature(stdsimd)] #![feature(stmt_expr_attributes)] #![feature(str_internals)] +#![feature(str_split_once)] #![feature(test)] #![feature(thread_local)] #![feature(thread_local_internals)] diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 48ba4ddfc0b2..47d615142f24 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -177,9 +177,7 @@ impl TryFrom<&str> for LookupHost { } // split the string by ':' and convert the second part to u16 - let mut parts_iter = s.rsplitn(2, ':'); - let port_str = try_opt!(parts_iter.next(), "invalid socket address"); - let host = try_opt!(parts_iter.next(), "invalid socket address"); + let (port_str, host) = try_opt!(s.rsplit_once(':'), "invalid socket address"); let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); (host, port).try_into() diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 5c12a54eef12..656d9669e81d 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -30,6 +30,7 @@ #![feature(termination_trait_lib)] #![feature(test)] #![feature(total_cmp)] +#![feature(str_split_once)] // Public reexports pub use self::bench::{black_box, Bencher}; diff --git a/library/test/src/time.rs b/library/test/src/time.rs index 130792fa5d7e..e0b6eadffa11 100644 --- a/library/test/src/time.rs +++ b/library/test/src/time.rs @@ -105,30 +105,24 @@ impl TimeThreshold { /// value. pub fn from_env_var(env_var_name: &str) -> Option { let durations_str = env::var(env_var_name).ok()?; + let (warn_str, critical_str) = durations_str.split_once(',').unwrap_or_else(|| { + panic!( + "Duration variable {} expected to have 2 numbers separated by comma, but got {}", + env_var_name, durations_str + ) + }); - // Split string into 2 substrings by comma and try to parse numbers. - let mut durations = durations_str.splitn(2, ',').map(|v| { + let parse_u64 = |v| { u64::from_str(v).unwrap_or_else(|_| { panic!( "Duration value in variable {} is expected to be a number, but got {}", env_var_name, v ) }) - }); - - // Callback to be called if the environment variable has unexpected structure. - let panic_on_incorrect_value = || { - panic!( - "Duration variable {} expected to have 2 numbers separated by comma, but got {}", - env_var_name, durations_str - ); }; - let (warn, critical) = ( - durations.next().unwrap_or_else(panic_on_incorrect_value), - durations.next().unwrap_or_else(panic_on_incorrect_value), - ); - + let warn = parse_u64(warn_str); + let critical = parse_u64(critical_str); if warn > critical { panic!("Test execution warn time should be less or equal to the critical time"); } From b81141cfb91cbf39e87e32a27530537f18e85405 Mon Sep 17 00:00:00 2001 From: Josias Date: Sun, 22 Nov 2020 19:02:57 +0100 Subject: [PATCH 128/719] Add lint print_stderr Resolves #6348 Almost identical to print_stdout, this lint applies to the `eprintln!` and `eprint!` macros rather than `println!` and `print!`. --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/write.rs | 23 +++++++++++++++++++++++ tests/ui/print_stderr.rs | 6 ++++++ tests/ui/print_stderr.stderr | 16 ++++++++++++++++ 5 files changed, 48 insertions(+) create mode 100644 tests/ui/print_stderr.rs create mode 100644 tests/ui/print_stderr.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index c7e02aaf4e18..1f2c4f310de2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2006,6 +2006,7 @@ Released 2018-09-13 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal +[`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr [`print_stdout`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout [`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline [`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2b99ed570b14..0e630a352fea 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -934,6 +934,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &wildcard_imports::WILDCARD_IMPORTS, &write::PRINTLN_EMPTY_STRING, &write::PRINT_LITERAL, + &write::PRINT_STDERR, &write::PRINT_STDOUT, &write::PRINT_WITH_NEWLINE, &write::USE_DEBUG, @@ -1247,6 +1248,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::RC_BUFFER), LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT), LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), + LintId::of(&write::PRINT_STDERR), LintId::of(&write::PRINT_STDOUT), LintId::of(&write::USE_DEBUG), ]); diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index ff414f748ef9..2248bc1e32ec 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -75,6 +75,24 @@ declare_clippy_lint! { "printing on stdout" } +declare_clippy_lint! { + /// **What it does:** Checks for printing on *stderr*. The purpose of this lint + /// is to catch debugging remnants. + /// + /// **Why is this bad?** People often print on *stderr* while debugging an + /// application and might forget to remove those prints afterward. + /// + /// **Known problems:** Only catches `eprint!` and `eprintln!` calls. + /// + /// **Example:** + /// ```rust + /// eprintln!("Hello world!"); + /// ``` + pub PRINT_STDERR, + restriction, + "printing on stderr" +} + declare_clippy_lint! { /// **What it does:** Checks for use of `Debug` formatting. The purpose of this /// lint is to catch debugging remnants. @@ -201,6 +219,7 @@ impl_lint_pass!(Write => [ PRINT_WITH_NEWLINE, PRINTLN_EMPTY_STRING, PRINT_STDOUT, + PRINT_STDERR, USE_DEBUG, PRINT_LITERAL, WRITE_WITH_NEWLINE, @@ -260,6 +279,10 @@ impl EarlyLintPass for Write { ); } } + } else if mac.path == sym!(eprintln) { + span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`"); + } else if mac.path == sym!(eprint) { + span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`"); } else if mac.path == sym!(print) { if !is_build_script(cx) { span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`"); diff --git a/tests/ui/print_stderr.rs b/tests/ui/print_stderr.rs new file mode 100644 index 000000000000..e53f46b1c2ff --- /dev/null +++ b/tests/ui/print_stderr.rs @@ -0,0 +1,6 @@ +#![warn(clippy::print_stderr)] + +fn main() { + eprintln!("Hello"); + eprint!("World"); +} diff --git a/tests/ui/print_stderr.stderr b/tests/ui/print_stderr.stderr new file mode 100644 index 000000000000..7252fce72c6e --- /dev/null +++ b/tests/ui/print_stderr.stderr @@ -0,0 +1,16 @@ +error: use of `eprintln!` + --> $DIR/print_stderr.rs:4:5 + | +LL | eprintln!("Hello"); + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::print-stderr` implied by `-D warnings` + +error: use of `eprint!` + --> $DIR/print_stderr.rs:5:5 + | +LL | eprint!("World"); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 51cee15be0f67403eedfe88c0c4ca07f306bef42 Mon Sep 17 00:00:00 2001 From: Josias Date: Sun, 29 Nov 2020 09:55:47 +0100 Subject: [PATCH 129/719] Add negative tests --- tests/ui/print_stderr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/print_stderr.rs b/tests/ui/print_stderr.rs index e53f46b1c2ff..fa07e74a7be4 100644 --- a/tests/ui/print_stderr.rs +++ b/tests/ui/print_stderr.rs @@ -2,5 +2,7 @@ fn main() { eprintln!("Hello"); + println!("This should not do anything"); eprint!("World"); + print!("Nor should this"); } From b04bfbd09b63d978f1bb7f4c9222cb2d37607309 Mon Sep 17 00:00:00 2001 From: Josias Date: Tue, 1 Dec 2020 11:29:49 +0100 Subject: [PATCH 130/719] Fix print_stderr.stderr test --- tests/ui/print_stderr.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/print_stderr.stderr b/tests/ui/print_stderr.stderr index 7252fce72c6e..5af735af6576 100644 --- a/tests/ui/print_stderr.stderr +++ b/tests/ui/print_stderr.stderr @@ -7,7 +7,7 @@ LL | eprintln!("Hello"); = note: `-D clippy::print-stderr` implied by `-D warnings` error: use of `eprint!` - --> $DIR/print_stderr.rs:5:5 + --> $DIR/print_stderr.rs:6:5 | LL | eprint!("World"); | ^^^^^^^^^^^^^^^^ From 7063c36c912990bd67327a41445706a451fe5b48 Mon Sep 17 00:00:00 2001 From: Josias Date: Fri, 4 Dec 2020 15:39:09 +0100 Subject: [PATCH 131/719] Add eprint! to print_with_newline lint --- clippy_lints/src/write.rs | 20 +++++ tests/ui/eprint_with_newline.rs | 49 +++++++++++ tests/ui/eprint_with_newline.stderr | 121 ++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 tests/ui/eprint_with_newline.rs create mode 100644 tests/ui/eprint_with_newline.stderr diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 2248bc1e32ec..0fd56f785724 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -283,6 +283,26 @@ impl EarlyLintPass for Write { span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`"); } else if mac.path == sym!(eprint) { span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`"); + if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { + if check_newlines(&fmt_str) { + span_lint_and_then( + cx, + PRINT_WITH_NEWLINE, + mac.span(), + "using `eprint!()` with a format string that ends in a single newline", + |err| { + err.multipart_suggestion( + "use `eprintln!` instead", + vec![ + (mac.path.span, String::from("eprintln")), + (newline_span(&fmt_str), String::new()), + ], + Applicability::MachineApplicable, + ); + }, + ); + } + } } else if mac.path == sym!(print) { if !is_build_script(cx) { span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`"); diff --git a/tests/ui/eprint_with_newline.rs b/tests/ui/eprint_with_newline.rs new file mode 100644 index 000000000000..8df32649ad94 --- /dev/null +++ b/tests/ui/eprint_with_newline.rs @@ -0,0 +1,49 @@ +#![allow(clippy::print_literal)] +#![warn(clippy::print_with_newline)] + +fn main() { + eprint!("Hello\n"); + eprint!("Hello {}\n", "world"); + eprint!("Hello {} {}\n", "world", "#2"); + eprint!("{}\n", 1265); + eprint!("\n"); + + // these are all fine + eprint!(""); + eprint!("Hello"); + eprintln!("Hello"); + eprintln!("Hello\n"); + eprintln!("Hello {}\n", "world"); + eprint!("Issue\n{}", 1265); + eprint!("{}", 1265); + eprint!("\n{}", 1275); + eprint!("\n\n"); + eprint!("like eof\n\n"); + eprint!("Hello {} {}\n\n", "world", "#2"); + eprintln!("\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126 + eprintln!("\nbla\n\n"); // #3126 + + // Escaping + eprint!("\\n"); // #3514 + eprint!("\\\n"); // should fail + eprint!("\\\\n"); + + // Raw strings + eprint!(r"\n"); // #3778 + + // Literal newlines should also fail + eprint!( + " +" + ); + eprint!( + r" +" + ); + + // Don't warn on CRLF (#4208) + eprint!("\r\n"); + eprint!("foo\r\n"); + eprint!("\\r\n"); //~ ERROR + eprint!("foo\rbar\n") // ~ ERROR +} diff --git a/tests/ui/eprint_with_newline.stderr b/tests/ui/eprint_with_newline.stderr new file mode 100644 index 000000000000..31811d1d92a0 --- /dev/null +++ b/tests/ui/eprint_with_newline.stderr @@ -0,0 +1,121 @@ +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:5:5 + | +LL | eprint!("Hello/n"); + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::print-with-newline` implied by `-D warnings` +help: use `eprintln!` instead + | +LL | eprintln!("Hello"); + | ^^^^^^^^ -- + +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:6:5 + | +LL | eprint!("Hello {}/n", "world"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `eprintln!` instead + | +LL | eprintln!("Hello {}", "world"); + | ^^^^^^^^ -- + +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:7:5 + | +LL | eprint!("Hello {} {}/n", "world", "#2"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `eprintln!` instead + | +LL | eprintln!("Hello {} {}", "world", "#2"); + | ^^^^^^^^ -- + +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:8:5 + | +LL | eprint!("{}/n", 1265); + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `eprintln!` instead + | +LL | eprintln!("{}", 1265); + | ^^^^^^^^ -- + +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:9:5 + | +LL | eprint!("/n"); + | ^^^^^^^^^^^^^ + | +help: use `eprintln!` instead + | +LL | eprintln!(); + | ^^^^^^^^ -- + +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:28:5 + | +LL | eprint!("//n"); // should fail + | ^^^^^^^^^^^^^^^ + | +help: use `eprintln!` instead + | +LL | eprintln!("/"); // should fail + | ^^^^^^^^ -- + +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:35:5 + | +LL | / eprint!( +LL | | " +LL | | " +LL | | ); + | |_____^ + | +help: use `eprintln!` instead + | +LL | eprintln!( +LL | "" + | + +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:39:5 + | +LL | / eprint!( +LL | | r" +LL | | " +LL | | ); + | |_____^ + | +help: use `eprintln!` instead + | +LL | eprintln!( +LL | r"" + | + +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:47:5 + | +LL | eprint!("/r/n"); //~ ERROR + | ^^^^^^^^^^^^^^^^ + | +help: use `eprintln!` instead + | +LL | eprintln!("/r"); //~ ERROR + | ^^^^^^^^ -- + +error: using `eprint!()` with a format string that ends in a single newline + --> $DIR/eprint_with_newline.rs:48:5 + | +LL | eprint!("foo/rbar/n") // ~ ERROR + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `eprintln!` instead + | +LL | eprintln!("foo/rbar") // ~ ERROR + | ^^^^^^^^ -- + +error: aborting due to 10 previous errors + From 174935988f131efcbce3c63924ee056940c36fb5 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 8 Dec 2020 00:05:26 +0100 Subject: [PATCH 132/719] Make assume_init_{ref,mut} const --- library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index fc44a5a55fb5..06195ac62856 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -103,6 +103,7 @@ #![feature(const_likely)] #![feature(const_unreachable_unchecked)] #![feature(const_maybe_uninit_assume_init)] +#![feature(const_maybe_uninit_as_ptr)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index eddfff6f513a..57ebab331886 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -668,13 +668,14 @@ impl MaybeUninit { /// } /// ``` #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn assume_init_ref(&self) -> &T { + pub const unsafe fn assume_init_ref(&self) -> &T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::(); - &*self.value + &*self.as_ptr() } } @@ -790,13 +791,14 @@ impl MaybeUninit { // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make // a final decision about the rules before stabilization. #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn assume_init_mut(&mut self) -> &mut T { + pub const unsafe fn assume_init_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::(); - &mut *self.value + &mut *self.as_mut_ptr() } } From 077527170bd112d97bdbb288ae8771930bcaa5b7 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 8 Dec 2020 00:07:34 +0100 Subject: [PATCH 133/719] Make write and slice_as_[mut_]_ptr const --- library/core/src/mem/maybe_uninit.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 57ebab331886..8800d7714cf4 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -373,8 +373,9 @@ impl MaybeUninit { /// skip running the destructor. For your convenience, this also returns a mutable /// reference to the (now safely initialized) contents of `self`. #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub fn write(&mut self, val: T) -> &mut T { + pub const fn write(&mut self, val: T) -> &mut T { *self = MaybeUninit::new(val); // SAFETY: We just initialized this value. unsafe { self.assume_init_mut() } @@ -846,15 +847,17 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } } From e58c7dd1685cb19e2ec87568cbc2cbd0aba3e2c7 Mon Sep 17 00:00:00 2001 From: Dobe Peter Date: Sat, 31 Oct 2020 20:31:34 +0100 Subject: [PATCH 134/719] panic_in_result_fn: Extend to also check usages of [debug_]assert* macros Also, the macro-finding logic has been moved to the util module, for use by future lints. --- clippy_lints/src/panic_in_result_fn.rs | 68 +++++++++---------- clippy_lints/src/utils/mod.rs | 33 ++++++++- tests/ui/panic_in_result_fn.stderr | 24 +++---- tests/ui/panic_in_result_fn_assertions.rs | 48 +++++++++++++ tests/ui/panic_in_result_fn_assertions.stderr | 57 ++++++++++++++++ .../ui/panic_in_result_fn_debug_assertions.rs | 48 +++++++++++++ ...panic_in_result_fn_debug_assertions.stderr | 57 ++++++++++++++++ 7 files changed, 285 insertions(+), 50 deletions(-) create mode 100644 tests/ui/panic_in_result_fn_assertions.rs create mode 100644 tests/ui/panic_in_result_fn_assertions.stderr create mode 100644 tests/ui/panic_in_result_fn_debug_assertions.rs create mode 100644 tests/ui/panic_in_result_fn_debug_assertions.stderr diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 72dfccc1089e..cdabb0d0dd6e 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,18 +1,16 @@ -use crate::utils::{is_expn_of, is_type_diagnostic_item, return_ty, span_lint_and_then}; +use crate::utils::{find_macro_calls, is_type_diagnostic_item, return_ty, span_lint_and_then}; use rustc_hir as hir; -use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor}; -use rustc_hir::Expr; +use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!` or `unreachable!` in a function of type result. + /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result. /// - /// **Why is this bad?** For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence unimplemented, panic and unreachable should be avoided. + /// **Why is this bad?** For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided. /// - /// **Known problems:** None. + /// **Known problems:** Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked. /// /// **Example:** /// @@ -22,9 +20,15 @@ declare_clippy_lint! { /// panic!("error"); /// } /// ``` + /// Use instead: + /// ```rust + /// fn result_without_panic() -> Result { + /// Err(String::from("error")) + /// } + /// ``` pub PANIC_IN_RESULT_FN, restriction, - "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` " + "functions of type `Result<..>` that contain `panic!()`, `todo!()`, `unreachable()`, `unimplemented()` or assertion" } declare_lint_pass!(PanicInResultFn => [PANIC_IN_RESULT_FN]); @@ -47,43 +51,33 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { } } -struct FindPanicUnimplementedUnreachable { - result: Vec, -} - -impl<'tcx> Visitor<'tcx> for FindPanicUnimplementedUnreachable { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if ["unimplemented", "unreachable", "panic", "todo"] - .iter() - .any(|fun| is_expn_of(expr.span, fun).is_some()) - { - self.result.push(expr.span); - } - // and check sub-expressions - intravisit::walk_expr(self, expr); - } - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } -} - fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { - let mut panics = FindPanicUnimplementedUnreachable { result: Vec::new() }; - panics.visit_expr(&body.value); - if !panics.result.is_empty() { + let panics = find_macro_calls( + vec![ + "unimplemented", + "unreachable", + "panic", + "todo", + "assert", + "assert_eq", + "assert_ne", + "debug_assert", + "debug_assert_eq", + "debug_assert_ne", + ], + body, + ); + if !panics.is_empty() { span_lint_and_then( cx, PANIC_IN_RESULT_FN, impl_span, - "used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`", + "used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`", move |diag| { diag.help( - "`unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing", + "`unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing", ); - diag.span_note(panics.result, "return Err() instead of panicking"); + diag.span_note(panics, "return Err() instead of panicking"); }, ); } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 007e72d129f7..e47d71aac996 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -41,7 +41,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::Node; use rustc_hir::{ def, Arm, Block, Body, Constness, Crate, Expr, ExprKind, FnDecl, HirId, ImplItem, ImplItemKind, Item, ItemKind, @@ -603,6 +603,37 @@ pub fn contains_return(expr: &hir::Expr<'_>) -> bool { visitor.found } +struct FindMacroCalls<'a> { + names: Vec<&'a str>, + result: Vec, +} + +impl<'a, 'tcx> Visitor<'tcx> for FindMacroCalls<'a> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + if self.names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) { + self.result.push(expr.span); + } + // and check sub-expressions + intravisit::walk_expr(self, expr); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } +} + +/// Finds calls of the specified macros in a function body. +pub fn find_macro_calls(names: Vec<&str>, body: &'tcx Body<'tcx>) -> Vec { + let mut fmc = FindMacroCalls { + names, + result: Vec::new(), + }; + fmc.visit_expr(&body.value); + fmc.result +} + /// Converts a span to a code snippet if available, otherwise use default. /// /// This is useful if you want to provide suggestions for your lint or more generally, if you want diff --git a/tests/ui/panic_in_result_fn.stderr b/tests/ui/panic_in_result_fn.stderr index ca73ac5a4111..eb744b0c198f 100644 --- a/tests/ui/panic_in_result_fn.stderr +++ b/tests/ui/panic_in_result_fn.stderr @@ -1,4 +1,4 @@ -error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:7:5 | LL | / fn result_with_panic() -> Result // should emit lint @@ -8,7 +8,7 @@ LL | | } | |_____^ | = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` - = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:9:9 | @@ -16,7 +16,7 @@ LL | panic!("error"); | ^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:12:5 | LL | / fn result_with_unimplemented() -> Result // should emit lint @@ -25,7 +25,7 @@ LL | | unimplemented!(); LL | | } | |_____^ | - = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:14:9 | @@ -33,7 +33,7 @@ LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:17:5 | LL | / fn result_with_unreachable() -> Result // should emit lint @@ -42,7 +42,7 @@ LL | | unreachable!(); LL | | } | |_____^ | - = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:19:9 | @@ -50,7 +50,7 @@ LL | unreachable!(); | ^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:22:5 | LL | / fn result_with_todo() -> Result // should emit lint @@ -59,7 +59,7 @@ LL | | todo!("Finish this"); LL | | } | |_____^ | - = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:24:9 | @@ -67,7 +67,7 @@ LL | todo!("Finish this"); | ^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:53:1 | LL | / fn function_result_with_panic() -> Result // should emit lint @@ -76,7 +76,7 @@ LL | | panic!("error"); LL | | } | |_^ | - = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:55:5 | @@ -84,7 +84,7 @@ LL | panic!("error"); | ^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:68:1 | LL | / fn main() -> Result<(), String> { @@ -93,7 +93,7 @@ LL | | Ok(()) LL | | } | |_^ | - = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:69:5 | diff --git a/tests/ui/panic_in_result_fn_assertions.rs b/tests/ui/panic_in_result_fn_assertions.rs new file mode 100644 index 000000000000..ffdf8288adc7 --- /dev/null +++ b/tests/ui/panic_in_result_fn_assertions.rs @@ -0,0 +1,48 @@ +#![warn(clippy::panic_in_result_fn)] +#![allow(clippy::unnecessary_wraps)] + +struct A; + +impl A { + fn result_with_assert_with_message(x: i32) -> Result // should emit lint + { + assert!(x == 5, "wrong argument"); + Ok(true) + } + + fn result_with_assert_eq(x: i32) -> Result // should emit lint + { + assert_eq!(x, 5); + Ok(true) + } + + fn result_with_assert_ne(x: i32) -> Result // should emit lint + { + assert_ne!(x, 1); + Ok(true) + } + + fn other_with_assert_with_message(x: i32) // should not emit lint + { + assert!(x == 5, "wrong argument"); + } + + fn other_with_assert_eq(x: i32) // should not emit lint + { + assert_eq!(x, 5); + } + + fn other_with_assert_ne(x: i32) // should not emit lint + { + assert_ne!(x, 1); + } + + fn result_without_banned_functions() -> Result // should not emit lint + { + let assert = "assert!"; + println!("No {}", assert); + Ok(true) + } +} + +fn main() {} diff --git a/tests/ui/panic_in_result_fn_assertions.stderr b/tests/ui/panic_in_result_fn_assertions.stderr new file mode 100644 index 000000000000..a17f043737d4 --- /dev/null +++ b/tests/ui/panic_in_result_fn_assertions.stderr @@ -0,0 +1,57 @@ +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` + --> $DIR/panic_in_result_fn_assertions.rs:7:5 + | +LL | / fn result_with_assert_with_message(x: i32) -> Result // should emit lint +LL | | { +LL | | assert!(x == 5, "wrong argument"); +LL | | Ok(true) +LL | | } + | |_____^ + | + = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing +note: return Err() instead of panicking + --> $DIR/panic_in_result_fn_assertions.rs:9:9 + | +LL | assert!(x == 5, "wrong argument"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` + --> $DIR/panic_in_result_fn_assertions.rs:13:5 + | +LL | / fn result_with_assert_eq(x: i32) -> Result // should emit lint +LL | | { +LL | | assert_eq!(x, 5); +LL | | Ok(true) +LL | | } + | |_____^ + | + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing +note: return Err() instead of panicking + --> $DIR/panic_in_result_fn_assertions.rs:15:9 + | +LL | assert_eq!(x, 5); + | ^^^^^^^^^^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` + --> $DIR/panic_in_result_fn_assertions.rs:19:5 + | +LL | / fn result_with_assert_ne(x: i32) -> Result // should emit lint +LL | | { +LL | | assert_ne!(x, 1); +LL | | Ok(true) +LL | | } + | |_____^ + | + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing +note: return Err() instead of panicking + --> $DIR/panic_in_result_fn_assertions.rs:21:9 + | +LL | assert_ne!(x, 1); + | ^^^^^^^^^^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/panic_in_result_fn_debug_assertions.rs b/tests/ui/panic_in_result_fn_debug_assertions.rs new file mode 100644 index 000000000000..b60c79f97c86 --- /dev/null +++ b/tests/ui/panic_in_result_fn_debug_assertions.rs @@ -0,0 +1,48 @@ +#![warn(clippy::panic_in_result_fn)] +#![allow(clippy::unnecessary_wraps)] + +struct A; + +impl A { + fn result_with_debug_assert_with_message(x: i32) -> Result // should emit lint + { + debug_assert!(x == 5, "wrong argument"); + Ok(true) + } + + fn result_with_debug_assert_eq(x: i32) -> Result // should emit lint + { + debug_assert_eq!(x, 5); + Ok(true) + } + + fn result_with_debug_assert_ne(x: i32) -> Result // should emit lint + { + debug_assert_ne!(x, 1); + Ok(true) + } + + fn other_with_debug_assert_with_message(x: i32) // should not emit lint + { + debug_assert!(x == 5, "wrong argument"); + } + + fn other_with_debug_assert_eq(x: i32) // should not emit lint + { + debug_assert_eq!(x, 5); + } + + fn other_with_debug_assert_ne(x: i32) // should not emit lint + { + debug_assert_ne!(x, 1); + } + + fn result_without_banned_functions() -> Result // should not emit lint + { + let debug_assert = "debug_assert!"; + println!("No {}", debug_assert); + Ok(true) + } +} + +fn main() {} diff --git a/tests/ui/panic_in_result_fn_debug_assertions.stderr b/tests/ui/panic_in_result_fn_debug_assertions.stderr new file mode 100644 index 000000000000..ec18e89698c5 --- /dev/null +++ b/tests/ui/panic_in_result_fn_debug_assertions.stderr @@ -0,0 +1,57 @@ +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` + --> $DIR/panic_in_result_fn_debug_assertions.rs:7:5 + | +LL | / fn result_with_debug_assert_with_message(x: i32) -> Result // should emit lint +LL | | { +LL | | debug_assert!(x == 5, "wrong argument"); +LL | | Ok(true) +LL | | } + | |_____^ + | + = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing +note: return Err() instead of panicking + --> $DIR/panic_in_result_fn_debug_assertions.rs:9:9 + | +LL | debug_assert!(x == 5, "wrong argument"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` + --> $DIR/panic_in_result_fn_debug_assertions.rs:13:5 + | +LL | / fn result_with_debug_assert_eq(x: i32) -> Result // should emit lint +LL | | { +LL | | debug_assert_eq!(x, 5); +LL | | Ok(true) +LL | | } + | |_____^ + | + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing +note: return Err() instead of panicking + --> $DIR/panic_in_result_fn_debug_assertions.rs:15:9 + | +LL | debug_assert_eq!(x, 5); + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` + --> $DIR/panic_in_result_fn_debug_assertions.rs:19:5 + | +LL | / fn result_with_debug_assert_ne(x: i32) -> Result // should emit lint +LL | | { +LL | | debug_assert_ne!(x, 1); +LL | | Ok(true) +LL | | } + | |_____^ + | + = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing +note: return Err() instead of panicking + --> $DIR/panic_in_result_fn_debug_assertions.rs:21:9 + | +LL | debug_assert_ne!(x, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + From bdad7900f4558672ca02b24a0a079b05391acaf9 Mon Sep 17 00:00:00 2001 From: dp304 <34493835+dp304@users.noreply.github.com> Date: Thu, 3 Dec 2020 23:07:24 +0100 Subject: [PATCH 135/719] Apply suggestions from code review Use array slice instead of `Vec` in `find_macro_calls` as suggested by @ebroto Co-authored-by: Eduardo Broto --- clippy_lints/src/panic_in_result_fn.rs | 2 +- clippy_lints/src/utils/mod.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index cdabb0d0dd6e..37e2b50def17 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { let panics = find_macro_calls( - vec![ + &[ "unimplemented", "unreachable", "panic", diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index e47d71aac996..e83371f8b99a 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -603,12 +603,12 @@ pub fn contains_return(expr: &hir::Expr<'_>) -> bool { visitor.found } -struct FindMacroCalls<'a> { - names: Vec<&'a str>, +struct FindMacroCalls<'a, 'b> { + names: &'a [&'b str], result: Vec, } -impl<'a, 'tcx> Visitor<'tcx> for FindMacroCalls<'a> { +impl<'a, 'b, 'tcx> Visitor<'tcx> for FindMacroCalls<'a, 'b> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { @@ -625,7 +625,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindMacroCalls<'a> { } /// Finds calls of the specified macros in a function body. -pub fn find_macro_calls(names: Vec<&str>, body: &'tcx Body<'tcx>) -> Vec { +pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec { let mut fmc = FindMacroCalls { names, result: Vec::new(), From 16d0e569248675da54fd892b4f36fd0ebc88eb1b Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Tue, 8 Dec 2020 00:14:05 +0100 Subject: [PATCH 136/719] Update reference file --- tests/ui/panic_in_result_fn_assertions.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/panic_in_result_fn_assertions.stderr b/tests/ui/panic_in_result_fn_assertions.stderr index a17f043737d4..86f61ad718a9 100644 --- a/tests/ui/panic_in_result_fn_assertions.stderr +++ b/tests/ui/panic_in_result_fn_assertions.stderr @@ -14,7 +14,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn_assertions.rs:9:9 | LL | assert!(x == 5, "wrong argument"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` From 891341942ab49c42c991072a4ac27b4dd4f28779 Mon Sep 17 00:00:00 2001 From: Erin Power Date: Mon, 7 Dec 2020 23:45:23 +0000 Subject: [PATCH 137/719] Update RELEASES.md for 1.49.0 --- RELEASES.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 9fd796fd775b..13af6dfe0c9b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,125 @@ +Version 1.49.0 (2020-11-19) +============================ + +Language +----------------------- + +- [Unions now implement `Drop`, and you can now have a field in a union + with `ManuallyDrop`.][77547] +- [You can now cast zero sized enums (0 or 1 variants) integers.][76199] +- [You can now take bind by reference and by move in patterns.][76119] This + allows you to selectively borrow individual components of a type. E.g. + ```rust + #[derive(Debug)] + struct Person { + name: String, + age: u8, + } + + let person = Person { + name: String::from("Alice"), + age: 20, + }; + + // `name` is moved out of person, but `age` is referenced. + let Person { name, ref age } = person; + println!("{} {}", name, age); + ``` +- [Macros that end with a semi-colon are now treated as statements.][78376] + +Compiler +----------------------- + +- [Added tier 1\* support for `aarch64-unknown-linux-gnu`.][78228] +- [Added tier 2 support for `aarch64-apple-darwin`.][75991] +- [Added tier 2 support for `aarch64-pc-windows-msvc`.][75914] +- [Added tier 3 support for `mipsel-unknown-none`.][78676] +- [Raised the minimum supported LLVM version to LLVM 9.][78848] +- [Output from threads spawned in tests is now captured.][78227] +- [TODO: rustc_target: Change os and vendor values to "none" and "unknown" for some targets][78951] + +\* Refer to Rust's [platform support page][forge-platform-support] for more +information on Rust's tiered platform support. + +Libraries +----------------------- + +- [`RangeInclusive` now checks for exhaustion when calling `contains` and indexing.][78109] +- [`ToString::to_string` now no longer shrinks the internal buffer in the default implementation.][77997] +- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989] + +Stabilized APIs +--------------- + +- [`slice::select_nth_unstable`] +- [`slice::select_nth_unstable_by`] +- [`slice::select_nth_unstable_by_key`] + +The following previously stable methods are now `const`. + +- [`Poll::is_ready`] +- [`Poll::is_pending`] + +Cargo +----------------------- +- [Building a crate with `cargo-package` should now be independently reproducible.][cargo/8864] +- [`cargo-tree` now marks proc-macro crates.][cargo/8765] +- [Added `CARGO_PRIMARY_PACKAGE` build-time environment variable.][cargo/8758] This + variable will be set if the crate being built is one the user selected to build, either + with `-p` or through defaults. +- [You can now use glob patterns when specifying packages & targets.][cargo/8752] + + +Compatibility Notes +------------------- + +- [Demoted `i686-unknown-freebsd` to tier 2 support.][78746] +- [Rustc will now check for the validity of attributes on enum variants.][77015] + Previously invalid or unused attributes were ignored. + +Internal Only +------------- +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc and +related tools. + +- [rustc's internal crates are now compiled the `initial-exec` Thread + Local Storage model.][78201] +- [Calculate visibilities once in resolve.][78077] +- [Added `system` to the `llvm-libunwind` bootstrap config option.][77703] +- [Added `--color` for configuring terminal color support to bootstrap.][79004] + + +[75991]: https://github.com/rust-lang/rust/pull/75991 +[78951]: https://github.com/rust-lang/rust/pull/78951 +[78848]: https://github.com/rust-lang/rust/pull/78848 +[78746]: https://github.com/rust-lang/rust/pull/78746 +[78376]: https://github.com/rust-lang/rust/pull/78376 +[78228]: https://github.com/rust-lang/rust/pull/78228 +[78227]: https://github.com/rust-lang/rust/pull/78227 +[78201]: https://github.com/rust-lang/rust/pull/78201 +[78109]: https://github.com/rust-lang/rust/pull/78109 +[78077]: https://github.com/rust-lang/rust/pull/78077 +[77997]: https://github.com/rust-lang/rust/pull/77997 +[77703]: https://github.com/rust-lang/rust/pull/77703 +[77547]: https://github.com/rust-lang/rust/pull/77547 +[77015]: https://github.com/rust-lang/rust/pull/77015 +[76199]: https://github.com/rust-lang/rust/pull/76199 +[76119]: https://github.com/rust-lang/rust/pull/76119 +[75914]: https://github.com/rust-lang/rust/pull/75914 +[74989]: https://github.com/rust-lang/rust/pull/74989 +[79004]: https://github.com/rust-lang/rust/pull/79004 +[78676]: https://github.com/rust-lang/rust/pull/78676 +[cargo/8864]: https://github.com/rust-lang/cargo/pull/8864 +[cargo/8765]: https://github.com/rust-lang/cargo/pull/8765 +[cargo/8758]: https://github.com/rust-lang/cargo/pull/8758 +[cargo/8752]: https://github.com/rust-lang/cargo/pull/8752 +[`slice::select_nth_unstable`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable +[`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by +[`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key +[`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html + + Version 1.48.0 (2020-11-19) ========================== @@ -10,7 +132,7 @@ Language Compiler -------- - [Stabilised the `-C link-self-contained=` compiler flag.][76158] This tells - `rustc` whether to link its own C runtime and libraries or to rely on a external + `rustc` whether to link its own C runtime and libraries or to rely on a external linker to find them. (Supported only on `windows-gnu`, `linux-musl`, and `wasi` platforms.) - [You can now use `-C target-feature=+crt-static` on `linux-gnu` targets.][77386] Note: If you're using cargo you must explicitly pass the `--target` flag. @@ -82,7 +204,7 @@ Compatibility Notes - [Foreign exceptions are now caught by `catch_unwind` and will cause an abort.][70212] Note: This behaviour is not guaranteed and is still considered undefined behaviour, see the [`catch_unwind`] documentation for further information. - + Internal Only @@ -102,7 +224,7 @@ related tools. [76030]: https://github.com/rust-lang/rust/pull/76030/ [70212]: https://github.com/rust-lang/rust/pull/70212/ [27675]: https://github.com/rust-lang/rust/issues/27675/ -[54121]: https://github.com/rust-lang/rust/issues/54121/ +[54121]: https://github.com/rust-lang/rust/issues/54121/ [71274]: https://github.com/rust-lang/rust/pull/71274/ [77386]: https://github.com/rust-lang/rust/pull/77386/ [77153]: https://github.com/rust-lang/rust/pull/77153/ From f68cc68e798edfb1f5cc1913e97b34b10ee8791f Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Mon, 7 Dec 2020 15:07:24 -0700 Subject: [PATCH 138/719] Review feedback for collect_intra_doc_links.rs * Add assertion value is defined. * Simplify comment. * Fix bad change in err message. --- src/librustdoc/passes/collect_intra_doc_links.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fdbab74be50d..5ce64c4cd83c 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -435,8 +435,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); - // NB: the `splitn`'s first element is always defined, even if the delimiter is not present. + // NB: `split`'s first element is always defined, even if the delimiter was not present. let item_str = split.next().unwrap(); + assert!(!item_str.is_empty()); let item_name = Symbol::intern(item_str); let path_root = split .next() @@ -448,7 +449,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ResolutionFailure::NotResolved { module_id, partial_res: None, - unresolved: path_str.into(), + unresolved: item_str.into(), } })?; From a3174de9ffaf2ea9213114a8457f880fbc727347 Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Mon, 7 Dec 2020 15:29:51 -0700 Subject: [PATCH 139/719] Fix net.rs - rsplitn() returns a reverse iterator --- library/std/src/sys_common/net.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 47d615142f24..38ba0d2fbdb6 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -177,9 +177,8 @@ impl TryFrom<&str> for LookupHost { } // split the string by ':' and convert the second part to u16 - let (port_str, host) = try_opt!(s.rsplit_once(':'), "invalid socket address"); + let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address"); let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); - (host, port).try_into() } } From f1b930d57cd9014a4e97c2b0ac366c8fa51f38c7 Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Mon, 7 Dec 2020 21:36:01 -0500 Subject: [PATCH 140/719] Improved documentation for HashMap/BTreeMap Entry's .or_insert_with_key method --- library/alloc/src/collections/btree/map/entry.rs | 9 ++++++--- library/std/src/collections/hash/map.rs | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 77c285ef595b..9dd68e27914b 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -116,9 +116,12 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } } - /// Ensures a value is in the entry by inserting, if empty, the result of the default function, - /// which takes the key as its argument, and returns a mutable reference to the value in the - /// entry. + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call.
+ /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. /// /// # Examples /// diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 323ea5d8244b..ae48d7fe7ee1 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2222,9 +2222,12 @@ impl<'a, K, V> Entry<'a, K, V> { } } - /// Ensures a value is in the entry by inserting, if empty, the result of the default function, - /// which takes the key as its argument, and returns a mutable reference to the value in the - /// entry. + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. /// /// # Examples /// From f115be93abd2634f3d71d91bf1341e9860a87056 Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Mon, 7 Dec 2020 21:59:52 -0500 Subject: [PATCH 141/719] Removed spurious linebreak from new documentation --- library/alloc/src/collections/btree/map/entry.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 9dd68e27914b..6626124a34e4 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -118,7 +118,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting, if empty, the result of the default function. /// This method allows for generating key-derived values for insertion by providing the default - /// function a reference to the key that was moved during the `.entry(key)` method call.
+ /// function a reference to the key that was moved during the `.entry(key)` method call. /// /// The reference to the moved key is provided so that cloning or copying the key is /// unnecessary, unlike with `.or_insert_with(|| ... )`. From 76bd14548910a13049b59b14e09a80cfd3a29b77 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Wed, 18 Nov 2020 12:57:40 +0900 Subject: [PATCH 142/719] Do not inline finish_grow We also change the specialization of `SpecFromIterNested::from_iter` for `TrustedLen` to use `Vec::with_capacity` when the iterator has a proper size hint, instead of `Vec::new`, avoiding calls to `grow_*` and thus `finish_grow` in some fully inlinable cases, which would regress with this change. Fixes #78471. --- library/alloc/src/raw_vec.rs | 1 + library/alloc/src/vec.rs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 522c5bcf5af1..fdf6884794a9 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -471,6 +471,7 @@ impl RawVec { // above `RawVec::grow_amortized` for details. (The `A` parameter isn't // significant, because the number of different `A` types seen in practice is // much smaller than the number of `T` types.) +#[inline(never)] fn finish_grow
( new_layout: Result, current_memory: Option<(NonNull, Layout)>, diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 2c8bc3d53ef7..62398b826077 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2103,7 +2103,10 @@ where I: TrustedLen, { fn from_iter(iterator: I) -> Self { - let mut vector = Vec::new(); + let mut vector = match iterator.size_hint() { + (_, Some(upper)) => Vec::with_capacity(upper), + _ => Vec::new(), + }; // must delegate to spec_extend() since extend() itself delegates // to spec_from for empty Vecs vector.spec_extend(iterator); From 4fb9f1d7846f64beeec749db5933a24c05456ff2 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 8 Dec 2020 10:34:31 +0100 Subject: [PATCH 143/719] fix unsoundness in `make_contiguous` --- library/alloc/src/collections/vec_deque/mod.rs | 18 +++++++++++++----- .../alloc/src/collections/vec_deque/tests.rs | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 85c809e0d188..57807bc54539 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1469,6 +1469,8 @@ impl VecDeque { #[inline] fn is_contiguous(&self) -> bool { + // FIXME: Should we consider `head == 0` to mean + // that `self` is contiguous? self.tail <= self.head } @@ -2198,7 +2200,7 @@ impl VecDeque { if self.is_contiguous() { let tail = self.tail; let head = self.head; - return unsafe { &mut self.buffer_as_mut_slice()[tail..head] }; + return unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 }; } let buf = self.buf.ptr(); @@ -2224,7 +2226,13 @@ impl VecDeque { self.tail = 0; self.head = len; } - } else if free >= self.head { + } else if free > self.head { + // FIXME: We currently do not consider ....ABCDEFGH + // to be contiguous because `head` would be `0` in this + // case. While we probably want to change this it + // isn't trivial as a few places expect `is_contiguous` + // to mean that we can just slice using `buf[tail..head]`. + // there is enough free space to copy the head in one go, // this means that we first shift the tail forwards, and then // copy the head to the correct position. @@ -2238,7 +2246,7 @@ impl VecDeque { // ...ABCDEFGH. self.tail = self.head; - self.head = self.tail + len; + self.head = self.wrap_add(self.tail, len); } } else { // free is smaller than both head and tail, @@ -2278,7 +2286,7 @@ impl VecDeque { let tail = self.tail; let head = self.head; - unsafe { &mut self.buffer_as_mut_slice()[tail..head] } + unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 } } /// Rotates the double-ended queue `mid` places to the left. @@ -2839,7 +2847,7 @@ impl From> for Vec { let len = other.len(); let cap = other.cap(); - if other.head != 0 { + if other.tail != 0 { ptr::copy(buf.add(other.tail), buf, len); } Vec::from_raw_parts(buf, len, cap) diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs index d74f91c752c0..21f52af056b2 100644 --- a/library/alloc/src/collections/vec_deque/tests.rs +++ b/library/alloc/src/collections/vec_deque/tests.rs @@ -210,6 +210,20 @@ fn make_contiguous_small_free() { ); } +#[test] +fn make_contiguous_head_to_end() { + let mut dq = VecDeque::with_capacity(3); + dq.push_front('B'); + dq.push_front('A'); + dq.push_back('C'); + dq.make_contiguous(); + let expected_tail = 0; + let expected_head = 3; + assert_eq!(expected_tail, dq.tail); + assert_eq!(expected_head, dq.head); + assert_eq!((&['A', 'B', 'C'] as &[_], &[] as &[_]), dq.as_slices()); +} + #[test] fn test_remove() { // This test checks that every single combination of tail position, length, and From 989edf4a5ffb0944e173ec23cb5614c252e8082e Mon Sep 17 00:00:00 2001 From: Eric Arellano Date: Tue, 8 Dec 2020 12:50:52 -0700 Subject: [PATCH 144/719] Review feedback * Use a match statement. * Clarify why we can't use `file_stem()`. * Error if the `:` is missing for Tidy error codes, rather than no-oping. --- .../rustc_mir/src/transform/coverage/debug.rs | 68 ++++++++++--------- src/tools/tidy/src/error_codes_check.rs | 14 ++-- src/tools/tidy/src/ui_tests.rs | 3 + 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs index 1347656c23ea..af81d9af0e29 100644 --- a/compiler/rustc_mir/src/transform/coverage/debug.rs +++ b/compiler/rustc_mir/src/transform/coverage/debug.rs @@ -152,38 +152,42 @@ impl DebugOptions { None => (setting_str, None), Some((k, v)) => (k, Some(v)), }; - if option == "allow_unused_expressions" { - allow_unused_expressions = bool_option_val(option, value); - debug!( - "{} env option `allow_unused_expressions` is set to {}", - RUSTC_COVERAGE_DEBUG_OPTIONS, allow_unused_expressions - ); - } else if option == "counter_format" { - match value { - None => { - bug!( - "`{}` option in environment variable {} requires one or more \ - plus-separated choices (a non-empty subset of \ - `id+block+operation`)", - option, - RUSTC_COVERAGE_DEBUG_OPTIONS - ); - } - Some(val) => { - counter_format = counter_format_option_val(val); - debug!( - "{} env option `counter_format` is set to {:?}", - RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format - ); - } - }; - } else { - bug!( - "Unsupported setting `{}` in environment variable {}", - option, - RUSTC_COVERAGE_DEBUG_OPTIONS - ) - } + match option { + "allow_unused_expressions" => { + allow_unused_expressions = bool_option_val(option, value); + debug!( + "{} env option `allow_unused_expressions` is set to {}", + RUSTC_COVERAGE_DEBUG_OPTIONS, allow_unused_expressions + ); + } + "counter_format" => { + match value { + None => { + bug!( + "`{}` option in environment variable {} requires one or more \ + plus-separated choices (a non-empty subset of \ + `id+block+operation`)", + option, + RUSTC_COVERAGE_DEBUG_OPTIONS + ); + } + Some(val) => { + counter_format = counter_format_option_val(val); + debug!( + "{} env option `counter_format` is set to {:?}", + RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format + ); + } + }; + } + _ => { + bug!( + "Unsupported setting `{}` in environment variable {}", + option, + RUSTC_COVERAGE_DEBUG_OPTIONS + ) + } + }; } } diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 1c175901be8d..a7199fdfce66 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -85,10 +85,16 @@ fn extract_error_codes( for line in f.lines() { let s = line.trim(); if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") { - let err_code = match s.split_once(':') { - None => continue, - Some((err_code, _)) => err_code.to_owned(), - }; + let err_code = s + .split_once(':') + .expect( + format!( + "Expected a line with the format `E0xxx: include_str!(\"..\")`, but got {} without a `:` delimiter", + s, + ).as_str() + ) + .0 + .to_owned(); if !error_codes.contains_key(&err_code) { error_codes.insert(err_code.clone(), false); } diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 4c8c1d58ed72..03f4efea983b 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -19,6 +19,9 @@ pub fn check(path: &Path, bad: &mut bool) { // // For now, just make sure that there is a corresponding // `$testname.rs` file. + // + // NB: We do not use file_stem() as some file names have multiple `.`s and we + // must strip all of them. let testname = file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0; if !file_path.with_file_name(testname).with_extension("rs").exists() { From 5cab04ea92355ed3a71caf96ac7ffcb638cd37cb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 8 Dec 2020 20:52:57 +0100 Subject: [PATCH 145/719] Remove deprecated linked_list_extras methods. --- library/alloc/src/collections/linked_list.rs | 62 -------------------- 1 file changed, 62 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 412c65681e68..4707f1294017 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1099,68 +1099,6 @@ impl ExactSizeIterator for IterMut<'_, T> {} #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IterMut<'_, T> {} -impl IterMut<'_, T> { - /// Inserts the given element just after the element most recently returned by `.next()`. - /// The inserted element does not appear in the iteration. - /// - /// This method will be removed soon. - #[inline] - #[unstable( - feature = "linked_list_extras", - reason = "this is probably better handled by a cursor type -- we'll see", - issue = "27794" - )] - #[rustc_deprecated( - reason = "Deprecated in favor of CursorMut methods. This method will be removed soon.", - since = "1.47.0" - )] - pub fn insert_next(&mut self, element: T) { - match self.head { - // `push_back` is okay with aliasing `element` references - None => self.list.push_back(element), - Some(head) => unsafe { - let prev = match head.as_ref().prev { - // `push_front` is okay with aliasing nodes - None => return self.list.push_front(element), - Some(prev) => prev, - }; - - let node = Some( - Box::leak(box Node { next: Some(head), prev: Some(prev), element }).into(), - ); - - // Not creating references to entire nodes to not invalidate the - // reference to `element` we handed to the user. - (*prev.as_ptr()).next = node; - (*head.as_ptr()).prev = node; - - self.list.len += 1; - }, - } - } - - /// Provides a reference to the next element, without changing the iterator. - /// - /// This method will be removed soon. - #[inline] - #[unstable( - feature = "linked_list_extras", - reason = "this is probably better handled by a cursor type -- we'll see", - issue = "27794" - )] - #[rustc_deprecated( - reason = "Deprecated in favor of CursorMut methods. This method will be removed soon.", - since = "1.47.0" - )] - 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) } - } - } -} - /// A cursor over a `LinkedList`. /// /// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. From 2bc5d44ca963a4dccf09c993fe9813f6a795aedf Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 10 Oct 2020 20:13:03 +0200 Subject: [PATCH 146/719] Fix outdated comment about not needing to flush stderr. --- library/std/src/io/stdio.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 6ea7704d4221..b5594c8e093b 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -756,13 +756,9 @@ pub struct StderrLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { - // Note that unlike `stdout()` we don't use `Lazy` here which registers a - // destructor. Stderr is not buffered nor does the `stderr_raw` type consume - // any owned resources, so there's no need to run any destructors at some - // point in the future. - // - // This has the added benefit of allowing `stderr` to be usable during - // process shutdown as well! + // Note that unlike `stdout()` we don't use `at_exit` here to register a + // destructor. Stderr is not buffered , so there's no need to run a + // destructor for flushing the buffer static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); Stderr { From 9dc7f13c39febc6466c8f79ad4c270ab8a63881f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 10 Oct 2020 20:15:55 +0200 Subject: [PATCH 147/719] Remove unnecessary import of `crate::marker` in std::sys_common::remutex. It was used for marker::Send, but Send is already in scope. --- library/std/src/sys_common/remutex.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 162eab2388d5..35d6701efd0b 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -2,7 +2,6 @@ mod tests; use crate::fmt; -use crate::marker; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sys::mutex as sys; @@ -40,7 +39,7 @@ pub struct ReentrantMutexGuard<'a, T: 'a> { lock: &'a ReentrantMutex, } -impl !marker::Send for ReentrantMutexGuard<'_, T> {} +impl !Send for ReentrantMutexGuard<'_, T> {} impl ReentrantMutex { /// Creates a new reentrant mutex in an unlocked state. From 8fe90966e19a4c3b6d05484d5368e5f9b444eb8b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 17:19:38 +0200 Subject: [PATCH 148/719] Add (internal-only) SyncOnceCell::get_or_init_pin. --- library/std/src/lazy.rs | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index e0095e64faf3..68f57958bb23 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -10,6 +10,7 @@ use crate::{ mem::MaybeUninit, ops::{Deref, Drop}, panic::{RefUnwindSafe, UnwindSafe}, + pin::Pin, sync::Once, }; @@ -297,6 +298,60 @@ impl SyncOnceCell { Ok(unsafe { self.get_unchecked() }) } + /// Internal-only API that gets the contents of the cell, initializing it + /// in two steps with `f` and `g` if the cell was empty. + /// + /// `f` is called to construct the value, which is then moved into the cell + /// and given as a (pinned) mutable reference to `g` to finish + /// initialization. + /// + /// This allows `g` to inspect an manipulate the value after it has been + /// moved into its final place in the cell, but before the cell is + /// considered initialized. + /// + /// # Panics + /// + /// If `f` or `g` panics, the panic is propagated to the caller, and the + /// cell remains uninitialized. + /// + /// With the current implementation, if `g` panics, the value from `f` will + /// not be dropped. This should probably be fixed if this is ever used for + /// a type where this matters. + /// + /// It is an error to reentrantly initialize the cell from `f`. The exact + /// outcome is unspecified. Current implementation deadlocks, but this may + /// be changed to a panic in the future. + pub(crate) fn get_or_init_pin(self: Pin<&Self>, f: F, g: G) -> Pin<&T> + where + F: FnOnce() -> T, + G: FnOnce(Pin<&mut T>), + { + if let Some(value) = self.get_ref().get() { + // SAFETY: The inner value was already initialized, and will not be + // moved anymore. + return unsafe { Pin::new_unchecked(value) }; + } + + let slot = &self.value; + + // Ignore poisoning from other threads + // If another thread panics, then we'll be able to run our closure + self.once.call_once_force(|_| { + let value = f(); + // SAFETY: We use the Once (self.once) to guarantee unique access + // to the UnsafeCell (slot). + let value: &mut T = unsafe { (&mut *slot.get()).write(value) }; + // SAFETY: The value has been written to its final place in + // self.value. We do not to move it anymore, which we promise here + // with a Pin<&mut T>. + g(unsafe { Pin::new_unchecked(value) }); + }); + + // SAFETY: The inner value has been initialized, and will not be moved + // anymore. + unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) } + } + /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns /// `None` if the cell was empty. /// From 67c18fdec59cf313818b8606c3847a8af6bcf684 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 10 Oct 2020 20:20:14 +0200 Subject: [PATCH 149/719] Use Pin for the 'don't move' requirement of ReentrantMutex. The code in io::stdio before this change misused the ReentrantMutexes, by calling init() on them and moving them afterwards. Now that ReentrantMutex requires Pin for init(), this mistake is no longer easy to make. --- library/std/src/io/stdio.rs | 54 +++++++++++---------- library/std/src/lib.rs | 2 + library/std/src/sys_common/remutex.rs | 52 ++++++++------------ library/std/src/sys_common/remutex/tests.rs | 35 +++++++------ 4 files changed, 70 insertions(+), 73 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index b5594c8e093b..1160011f3528 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -9,6 +9,7 @@ use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; use crate::lazy::SyncOnceCell; +use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard}; use crate::sys::stdio; @@ -490,7 +491,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: &'static ReentrantMutex>>, + inner: Pin<&'static ReentrantMutex>>>, } /// A locked reference to the `Stdout` handle. @@ -550,25 +551,29 @@ pub struct StdoutLock<'a> { pub fn stdout() -> Stdout { static INSTANCE: SyncOnceCell>>> = SyncOnceCell::new(); + + fn cleanup() { + if let Some(instance) = INSTANCE.get() { + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = Pin::static_ref(instance).try_lock() { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); + } + } + } + Stdout { - inner: INSTANCE.get_or_init(|| unsafe { - let _ = sys_common::at_exit(|| { - if let Some(instance) = INSTANCE.get() { - // Flush the data and disable buffering during shutdown - // by replacing the line writer by one with zero - // buffering capacity. - // We use try_lock() instead of lock(), because someone - // might have leaked a StdoutLock, which would - // otherwise cause a deadlock here. - if let Some(lock) = instance.try_lock() { - *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); - } - } - }); - let r = ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))); - r.init(); - r - }), + inner: Pin::static_ref(&INSTANCE).get_or_init_pin( + || unsafe { + let _ = sys_common::at_exit(cleanup); + ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) + }, + |mutex| unsafe { mutex.init() }, + ), } } @@ -700,7 +705,7 @@ impl fmt::Debug for StdoutLock<'_> { /// an error. #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: &'static ReentrantMutex>, + inner: Pin<&'static ReentrantMutex>>, } /// A locked reference to the `Stderr` handle. @@ -762,11 +767,10 @@ pub fn stderr() -> Stderr { static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); Stderr { - inner: INSTANCE.get_or_init(|| unsafe { - let r = ReentrantMutex::new(RefCell::new(stderr_raw())); - r.init(); - r - }), + inner: Pin::static_ref(&INSTANCE).get_or_init_pin( + || unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }, + |mutex| unsafe { mutex.init() }, + ), } } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 6c240cb4c3ed..def8db1f45c3 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -266,6 +266,7 @@ #![feature(format_args_nl)] #![feature(gen_future)] #![feature(generator_trait)] +#![feature(get_mut_unchecked)] #![feature(global_asm)] #![feature(hashmap_internals)] #![feature(int_error_internals)] @@ -293,6 +294,7 @@ #![feature(panic_info_message)] #![feature(panic_internals)] #![feature(panic_unwind)] +#![feature(pin_static_ref)] #![feature(prelude_import)] #![feature(ptr_internals)] #![feature(raw)] diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 35d6701efd0b..475bfca9b6dc 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -1,9 +1,10 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; -use crate::fmt; +use crate::marker::PhantomPinned; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; +use crate::pin::Pin; use crate::sys::mutex as sys; /// A re-entrant mutual exclusion @@ -14,6 +15,7 @@ use crate::sys::mutex as sys; pub struct ReentrantMutex { inner: sys::ReentrantMutex, data: T, + _pinned: PhantomPinned, } unsafe impl Send for ReentrantMutex {} @@ -36,7 +38,7 @@ impl RefUnwindSafe for ReentrantMutex {} /// guarded data. #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { - lock: &'a ReentrantMutex, + lock: Pin<&'a ReentrantMutex>, } impl !Send for ReentrantMutexGuard<'_, T> {} @@ -50,7 +52,11 @@ impl ReentrantMutex { /// once this mutex is in its final resting place, and only then are the /// lock/unlock methods safe. pub const unsafe fn new(t: T) -> ReentrantMutex { - ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t } + ReentrantMutex { + inner: sys::ReentrantMutex::uninitialized(), + data: t, + _pinned: PhantomPinned, + } } /// Initializes this mutex so it's ready for use. @@ -59,8 +65,8 @@ impl ReentrantMutex { /// /// Unsafe to call more than once, and must be called after this will no /// longer move in memory. - pub unsafe fn init(&self) { - self.inner.init(); + pub unsafe fn init(self: Pin<&mut Self>) { + self.get_unchecked_mut().inner.init() } /// Acquires a mutex, blocking the current thread until it is able to do so. @@ -75,9 +81,9 @@ impl ReentrantMutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn lock(&self) -> ReentrantMutexGuard<'_, T> { + pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> { unsafe { self.inner.lock() } - ReentrantMutexGuard::new(&self) + ReentrantMutexGuard { lock: self } } /// Attempts to acquire this lock. @@ -92,8 +98,12 @@ impl ReentrantMutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn try_lock(&self) -> Option> { - if unsafe { self.inner.try_lock() } { Some(ReentrantMutexGuard::new(&self)) } else { None } + pub fn try_lock(self: Pin<&Self>) -> Option> { + if unsafe { self.inner.try_lock() } { + Some(ReentrantMutexGuard { lock: self }) + } else { + None + } } } @@ -106,30 +116,6 @@ impl Drop for ReentrantMutex { } } -impl fmt::Debug for ReentrantMutex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.try_lock() { - Some(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(), - None => { - struct LockedPlaceholder; - impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("") - } - } - - f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish() - } - } - } -} - -impl<'mutex, T> ReentrantMutexGuard<'mutex, T> { - fn new(lock: &'mutex ReentrantMutex) -> ReentrantMutexGuard<'mutex, T> { - ReentrantMutexGuard { lock } - } -} - impl Deref for ReentrantMutexGuard<'_, T> { type Target = T; diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sys_common/remutex/tests.rs index 9c686e579d73..88453ded2f9f 100644 --- a/library/std/src/sys_common/remutex/tests.rs +++ b/library/std/src/sys_common/remutex/tests.rs @@ -1,4 +1,6 @@ +use crate::boxed::Box; use crate::cell::RefCell; +use crate::pin::Pin; use crate::sync::Arc; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread; @@ -6,10 +8,11 @@ use crate::thread; #[test] fn smoke() { let m = unsafe { - let m = ReentrantMutex::new(()); - m.init(); + let mut m = Box::pin(ReentrantMutex::new(())); + m.as_mut().init(); m }; + let m = m.as_ref(); { let a = m.lock(); { @@ -27,18 +30,19 @@ fn smoke() { #[test] fn is_mutex() { let m = unsafe { - let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - m.init(); - m + // FIXME: Simplify this if Arc gets a Arc::get_pin_mut. + let mut m = Arc::new(ReentrantMutex::new(RefCell::new(0))); + Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init(); + Pin::new_unchecked(m) }; let m2 = m.clone(); - let lock = m.lock(); + let lock = m.as_ref().lock(); let child = thread::spawn(move || { - let lock = m2.lock(); + let lock = m2.as_ref().lock(); assert_eq!(*lock.borrow(), 4950); }); for i in 0..100 { - let lock = m.lock(); + let lock = m.as_ref().lock(); *lock.borrow_mut() += i; } drop(lock); @@ -48,20 +52,21 @@ fn is_mutex() { #[test] fn trylock_works() { let m = unsafe { - let m = Arc::new(ReentrantMutex::new(())); - m.init(); - m + // FIXME: Simplify this if Arc gets a Arc::get_pin_mut. + let mut m = Arc::new(ReentrantMutex::new(())); + Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init(); + Pin::new_unchecked(m) }; let m2 = m.clone(); - let _lock = m.try_lock(); - let _lock2 = m.try_lock(); + let _lock = m.as_ref().try_lock(); + let _lock2 = m.as_ref().try_lock(); thread::spawn(move || { - let lock = m2.try_lock(); + let lock = m2.as_ref().try_lock(); assert!(lock.is_none()); }) .join() .unwrap(); - let _lock3 = m.try_lock(); + let _lock3 = m.as_ref().try_lock(); } pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); From 7bb1889899d27a453f00e2b701cf8e3508431f4c Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Tue, 8 Dec 2020 22:13:03 +0000 Subject: [PATCH 150/719] Apply suggestions from code review Co-authored-by: Jonas Schievink Co-authored-by: Vadim Petrochenkov --- RELEASES.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 13af6dfe0c9b..a06963ae1b43 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -4,10 +4,10 @@ Version 1.49.0 (2020-11-19) Language ----------------------- -- [Unions now implement `Drop`, and you can now have a field in a union +- [Unions can now implement `Drop`, and you can now have a field in a union with `ManuallyDrop`.][77547] -- [You can now cast zero sized enums (0 or 1 variants) integers.][76199] -- [You can now take bind by reference and by move in patterns.][76119] This +- [You can now cast zero sized enums (0 or 1 variants) to integers.][76199] +- [You can now bind by reference and by move in patterns.][76119] This allows you to selectively borrow individual components of a type. E.g. ```rust #[derive(Debug)] @@ -25,7 +25,7 @@ Language let Person { name, ref age } = person; println!("{} {}", name, age); ``` -- [Macros that end with a semi-colon are now treated as statements.][78376] +- [Macros that end with a semi-colon are now treated as statements even if they expand to nothing.][78376] Compiler ----------------------- @@ -74,7 +74,8 @@ Compatibility Notes ------------------- - [Demoted `i686-unknown-freebsd` to tier 2 support.][78746] -- [Rustc will now check for the validity of attributes on enum variants.][77015] +- [Rustc will now check for the validity of some built-in attributes on enum variants.][77015] + Previously such invalid or unused attributes could be ignored. Previously invalid or unused attributes were ignored. Internal Only @@ -83,7 +84,7 @@ These changes provide no direct user facing benefits, but represent significant improvements to the internals and overall performance of rustc and related tools. -- [rustc's internal crates are now compiled the `initial-exec` Thread +- [rustc's internal crates are now compiled using the `initial-exec` Thread Local Storage model.][78201] - [Calculate visibilities once in resolve.][78077] - [Added `system` to the `llvm-libunwind` bootstrap config option.][77703] From 468c578b24b7eaa5ca743d47e2b259b9acdf2db3 Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Tue, 8 Dec 2020 22:14:10 +0000 Subject: [PATCH 151/719] Update RELEASES.md --- RELEASES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index a06963ae1b43..7a0bfd5fc956 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,4 +1,4 @@ -Version 1.49.0 (2020-11-19) +Version 1.49.0 (2020-12-31) ============================ Language @@ -6,7 +6,7 @@ Language - [Unions can now implement `Drop`, and you can now have a field in a union with `ManuallyDrop`.][77547] -- [You can now cast zero sized enums (0 or 1 variants) to integers.][76199] +- [You can now cast uninhabited enums to integers.][76199] - [You can now bind by reference and by move in patterns.][76119] This allows you to selectively borrow individual components of a type. E.g. ```rust From edb55e93bc69c31adf69dec3092ae2cdd4cdd74b Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Tue, 8 Dec 2020 22:14:45 +0000 Subject: [PATCH 152/719] Update RELEASES.md Co-authored-by: Jonas Schievink --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 7a0bfd5fc956..3fca9c789939 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -36,7 +36,7 @@ Compiler - [Added tier 3 support for `mipsel-unknown-none`.][78676] - [Raised the minimum supported LLVM version to LLVM 9.][78848] - [Output from threads spawned in tests is now captured.][78227] -- [TODO: rustc_target: Change os and vendor values to "none" and "unknown" for some targets][78951] +- [Change os and vendor values to "none" and "unknown" for some targets][78951] \* Refer to Rust's [platform support page][forge-platform-support] for more information on Rust's tiered platform support. From 4aaace9b53fc62696965860c8e9967b0385a22a3 Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Tue, 8 Dec 2020 22:15:53 +0000 Subject: [PATCH 153/719] Update RELEASES.md --- RELEASES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 3fca9c789939..8f5d6db5db92 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -119,7 +119,8 @@ related tools. [`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by [`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key [`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html - +[`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready +[`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending Version 1.48.0 (2020-11-19) ========================== From 7cb74ed1917cc982830d6b7b7bac7e8a7f4d271c Mon Sep 17 00:00:00 2001 From: Tunahan Karlibas Date: Wed, 9 Dec 2020 01:17:02 +0300 Subject: [PATCH 154/719] Remove memoization leftovers closes #79667 --- compiler/rustc_mir/src/const_eval/machine.rs | 63 ++------------------ 1 file changed, 4 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 187f6fab5181..cc5f5dda7d49 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -1,6 +1,4 @@ use rustc_middle::mir; -use rustc_middle::ty::layout::HasTyCtxt; -use rustc_middle::ty::InstanceDef; use rustc_middle::ty::{self, Ty}; use std::borrow::Borrow; use std::collections::hash_map::Entry; @@ -17,60 +15,13 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{Align, Size}; use crate::interpret::{ - self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx, - InterpResult, Memory, OpTy, PlaceTy, Pointer, Scalar, + self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, Memory, + OpTy, PlaceTy, Pointer, Scalar, }; use super::error::*; impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { - /// Evaluate a const function where all arguments (if any) are zero-sized types. - /// The evaluation is memoized thanks to the query system. - /// - /// Returns `true` if the call has been evaluated. - fn try_eval_const_fn_call( - &mut self, - instance: ty::Instance<'tcx>, - ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, - args: &[OpTy<'tcx>], - ) -> InterpResult<'tcx, bool> { - trace!("try_eval_const_fn_call: {:?}", instance); - // Because `#[track_caller]` adds an implicit non-ZST argument, we also cannot - // perform this optimization on items tagged with it. - if instance.def.requires_caller_location(self.tcx()) { - return Ok(false); - } - // Only memoize instrinsics. This was added in #79594 while adding the `const_allocate` intrinsic. - // We only memoize intrinsics because it would be unsound to memoize functions - // which might interact with the heap. - // Additionally, const_allocate intrinsic is impure and thus should not be memoized; - // it will not be memoized because it has non-ZST args - if !matches!(instance.def, InstanceDef::Intrinsic(_)) { - return Ok(false); - } - // For the moment we only do this for functions which take no arguments - // (or all arguments are ZSTs) so that we don't memoize too much. - if args.iter().any(|a| !a.layout.is_zst()) { - return Ok(false); - } - - let dest = match ret { - Some((dest, _)) => dest, - // Don't memoize diverging function calls. - None => return Ok(false), - }; - - let gid = GlobalId { instance, promoted: None }; - - let place = self.eval_to_allocation(gid)?; - - self.copy_op(place.into(), dest)?; - - self.return_to_block(ret.map(|r| r.1))?; - trace!("{:?}", self.dump_place(*dest)); - Ok(true) - } - /// "Intercept" a function call to a panic-related function /// because we have something special to do for it. /// If this returns successfully (`Ok`), the function should just be evaluated normally. @@ -253,7 +204,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + _ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, _unwind: Option, // unwinding is not supported in consts ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { debug!("find_mir_or_eval_fn: {:?}", instance); @@ -263,13 +214,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const // at all. - if ecx.tcx.is_const_fn_raw(def.did) { - // If this function is a `const fn` then under certain circumstances we - // can evaluate call via the query system, thus memoizing all future calls. - if ecx.try_eval_const_fn_call(instance, ret, args)? { - return Ok(None); - } - } else { + if !ecx.tcx.is_const_fn_raw(def.did) { // Some functions we support even if they are non-const -- but avoid testing // that for const fn! ecx.hook_panic_fn(instance, args)?; From 3187cad8ec0e9c32272341028526d6f1e208a704 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Tue, 8 Dec 2020 23:17:12 +0100 Subject: [PATCH 155/719] Factor out some code in write.rs Get rid of the too-many-lines error. --- clippy_lints/src/write.rs | 112 ++++++++++++--------------- tests/ui/println_empty_string.fixed | 7 ++ tests/ui/println_empty_string.rs | 7 ++ tests/ui/println_empty_string.stderr | 14 +++- 4 files changed, 78 insertions(+), 62 deletions(-) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 0fd56f785724..337f7a229b90 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -262,71 +262,22 @@ impl EarlyLintPass for Write { .map_or(false, |crate_name| crate_name == "build_script_build") } - if mac.path == sym!(println) { - if !is_build_script(cx) { - span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`"); - } - if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { - if fmt_str.symbol == Symbol::intern("") { - span_lint_and_sugg( - cx, - PRINTLN_EMPTY_STRING, - mac.span(), - "using `println!(\"\")`", - "replace it with", - "println!()".to_string(), - Applicability::MachineApplicable, - ); - } - } - } else if mac.path == sym!(eprintln) { - span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`"); - } else if mac.path == sym!(eprint) { - span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`"); - if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { - if check_newlines(&fmt_str) { - span_lint_and_then( - cx, - PRINT_WITH_NEWLINE, - mac.span(), - "using `eprint!()` with a format string that ends in a single newline", - |err| { - err.multipart_suggestion( - "use `eprintln!` instead", - vec![ - (mac.path.span, String::from("eprintln")), - (newline_span(&fmt_str), String::new()), - ], - Applicability::MachineApplicable, - ); - }, - ); - } - } - } else if mac.path == sym!(print) { + if mac.path == sym!(print) { if !is_build_script(cx) { span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`"); } - if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { - if check_newlines(&fmt_str) { - span_lint_and_then( - cx, - PRINT_WITH_NEWLINE, - mac.span(), - "using `print!()` with a format string that ends in a single newline", - |err| { - err.multipart_suggestion( - "use `println!` instead", - vec![ - (mac.path.span, String::from("println")), - (newline_span(&fmt_str), String::new()), - ], - Applicability::MachineApplicable, - ); - }, - ); - } + self.lint_print_with_newline(cx, mac); + } else if mac.path == sym!(println) { + if !is_build_script(cx) { + span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`"); } + self.lint_println_empty_string(cx, mac); + } else if mac.path == sym!(eprint) { + span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`"); + self.lint_print_with_newline(cx, mac); + } else if mac.path == sym!(eprintln) { + span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`"); + self.lint_println_empty_string(cx, mac); } else if mac.path == sym!(write) { if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) { if check_newlines(&fmt_str) { @@ -530,6 +481,45 @@ impl Write { } } } + + fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) { + if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { + if fmt_str.symbol == Symbol::intern("") { + let name = mac.path.segments[0].ident.name; + span_lint_and_sugg( + cx, + PRINTLN_EMPTY_STRING, + mac.span(), + &format!("using `{}!(\"\")`", name), + "replace it with", + format!("{}!()", name), + Applicability::MachineApplicable, + ); + } + } + } + + fn lint_print_with_newline(&self, cx: &EarlyContext<'_>, mac: &MacCall) { + if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { + if check_newlines(&fmt_str) { + let name = mac.path.segments[0].ident.name; + let suggested = format!("{}ln", name); + span_lint_and_then( + cx, + PRINT_WITH_NEWLINE, + mac.span(), + &format!("using `{}!()` with a format string that ends in a single newline", name), + |err| { + err.multipart_suggestion( + &format!("use `{}!` instead", suggested), + vec![(mac.path.span, suggested), (newline_span(&fmt_str), String::new())], + Applicability::MachineApplicable, + ); + }, + ); + } + } + } } /// Checks if the format string contains a single newline that terminates it. diff --git a/tests/ui/println_empty_string.fixed b/tests/ui/println_empty_string.fixed index 2b889b62ea99..9760680927a6 100644 --- a/tests/ui/println_empty_string.fixed +++ b/tests/ui/println_empty_string.fixed @@ -8,4 +8,11 @@ fn main() { match "a" { _ => println!(), } + + eprintln!(); + eprintln!(); + + match "a" { + _ => eprintln!(), + } } diff --git a/tests/ui/println_empty_string.rs b/tests/ui/println_empty_string.rs index 890f5f684760..80fdb3e6e210 100644 --- a/tests/ui/println_empty_string.rs +++ b/tests/ui/println_empty_string.rs @@ -8,4 +8,11 @@ fn main() { match "a" { _ => println!(""), } + + eprintln!(); + eprintln!(""); + + match "a" { + _ => eprintln!(""), + } } diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr index 23112b881689..17fe4ea74790 100644 --- a/tests/ui/println_empty_string.stderr +++ b/tests/ui/println_empty_string.stderr @@ -12,5 +12,17 @@ error: using `println!("")` LL | _ => println!(""), | ^^^^^^^^^^^^ help: replace it with: `println!()` -error: aborting due to 2 previous errors +error: using `eprintln!("")` + --> $DIR/println_empty_string.rs:13:5 + | +LL | eprintln!(""); + | ^^^^^^^^^^^^^ help: replace it with: `eprintln!()` + +error: using `eprintln!("")` + --> $DIR/println_empty_string.rs:16:14 + | +LL | _ => eprintln!(""), + | ^^^^^^^^^^^^^ help: replace it with: `eprintln!()` + +error: aborting due to 4 previous errors From 8909c4dc315bf1686449e762958558893c420923 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 8 Dec 2020 19:18:06 -0500 Subject: [PATCH 156/719] Fix rustup support in default_build_triple for python3 bootstrap completely ignores all errors when detecting a rustup version, so this wasn't noticed before. Fixes the following error: ``` rustup not detected: a bytes-like object is required, not 'str' falling back to auto-detect ``` This also takes the opportunity to only call rustup and other external commands only once during startup. --- src/bootstrap/bootstrap.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index a819e1b6e2f1..f919f63e579d 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -192,8 +192,10 @@ def default_build_triple(verbose): # If the user already has a host build triple with an existing `rustc` # install, use their preference. This fixes most issues with Windows builds # being detected as GNU instead of MSVC. + default_encoding = sys.getdefaultencoding() try: version = subprocess.check_output(["rustc", "--version", "--verbose"]) + version = version.decode(default_encoding) host = next(x for x in version.split('\n') if x.startswith("host: ")) triple = host.split("host: ")[1] if verbose: @@ -204,7 +206,6 @@ def default_build_triple(verbose): print("rustup not detected: {}".format(e)) print("falling back to auto-detect") - default_encoding = sys.getdefaultencoding() required = sys.platform != 'win32' ostype = require(["uname", "-s"], exit=required) cputype = require(['uname', '-m'], exit=required) @@ -794,7 +795,7 @@ class RustBuild(object): env.setdefault("RUSTFLAGS", "") env["RUSTFLAGS"] += " -Cdebuginfo=2" - build_section = "target.{}".format(self.build_triple()) + build_section = "target.{}".format(self.build) target_features = [] if self.get_toml("crt-static", build_section) == "true": target_features += ["+crt-static"] @@ -825,7 +826,11 @@ class RustBuild(object): run(args, env=env, verbose=self.verbose) def build_triple(self): - """Build triple as in LLVM""" + """Build triple as in LLVM + + Note that `default_build_triple` is moderately expensive, + so use `self.build` where possible. + """ config = self.get_toml('build') if config: return config From 4e21942ba4d435c3211677ad42ddc528fff97857 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 8 Dec 2020 21:56:22 -0800 Subject: [PATCH 157/719] Clarify the 'default is only allowed on...' error Code like impl Foo { default fn foo() {} } will trigger the error error: `default` is only allowed on items in `impl` definitions --> src/lib.rs:5:5 | 5 | default fn foo() {} | -------^^^^^^^^^ | | | `default` because of this but that's very confusing! I *did* put it on an item in an impl! So this commit changes the message to error: `default` is only allowed on items in trait impls --> src/lib.rs:5:5 | 5 | default fn foo() {} | -------^^^^^^^^^ | | | `default` because of this --- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- .../trait-item-with-defaultness-fail-semantic.rs | 12 ++++++------ .../trait-item-with-defaultness-fail-semantic.stderr | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 4ec3e39facc9..bf6d33221761 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -400,7 +400,7 @@ impl<'a> AstValidator<'a> { if let Defaultness::Default(def_span) = defaultness { let span = self.session.source_map().guess_head_span(span); self.err_handler() - .struct_span_err(span, "`default` is only allowed on items in `impl` definitions") + .struct_span_err(span, "`default` is only allowed on items in trait impls") .span_label(def_span, "`default` because of this") .emit(); } diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs index 34aee7f69359..f2d97b7bac3c 100644 --- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs @@ -3,10 +3,10 @@ fn main() {} trait X { - default const A: u8; //~ ERROR `default` is only allowed on items in `impl` definitions - default const B: u8 = 0; //~ ERROR `default` is only allowed on items in `impl` definitions - default type D; //~ ERROR `default` is only allowed on items in `impl` definitions - default type C: Ord; //~ ERROR `default` is only allowed on items in `impl` definitions - default fn f1(); //~ ERROR `default` is only allowed on items in `impl` definitions - default fn f2() {} //~ ERROR `default` is only allowed on items in `impl` definitions + default const A: u8; //~ ERROR `default` is only allowed on items in trait impls + default const B: u8 = 0; //~ ERROR `default` is only allowed on items in trait impls + default type D; //~ ERROR `default` is only allowed on items in trait impls + default type C: Ord; //~ ERROR `default` is only allowed on items in trait impls + default fn f1(); //~ ERROR `default` is only allowed on items in trait impls + default fn f2() {} //~ ERROR `default` is only allowed on items in trait impls } diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr index cdc9ee8d9e7c..76fa860334d7 100644 --- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr @@ -1,4 +1,4 @@ -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:6:5 | LL | default const A: u8; @@ -6,7 +6,7 @@ LL | default const A: u8; | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:7:5 | LL | default const B: u8 = 0; @@ -14,7 +14,7 @@ LL | default const B: u8 = 0; | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:8:5 | LL | default type D; @@ -22,7 +22,7 @@ LL | default type D; | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:9:5 | LL | default type C: Ord; @@ -30,7 +30,7 @@ LL | default type C: Ord; | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:10:5 | LL | default fn f1(); @@ -38,7 +38,7 @@ LL | default fn f1(); | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:11:5 | LL | default fn f2() {} From de1cd4b36d57b33f4217a46c0c52fbe1eb4530a1 Mon Sep 17 00:00:00 2001 From: Tunahan Karlibas Date: Wed, 9 Dec 2020 14:53:35 +0300 Subject: [PATCH 158/719] Extra assertions in eval_body_using_ecx to disallow queries for functions that does allocations --- compiler/rustc_middle/src/mir/interpret/mod.rs | 1 - compiler/rustc_mir/src/const_eval/eval_queries.rs | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index bcf85797313f..80b58642136e 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -132,7 +132,6 @@ pub use self::pointer::{Pointer, PointerArithmetic}; /// Uniquely identifies one of the following: /// - A constant /// - A static -/// - A const fn where all arguments (if any) are zero-sized types #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, Lift)] pub struct GlobalId<'tcx> { diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 6e09ae434064..4d14e45c2e93 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -30,6 +30,13 @@ fn eval_body_using_ecx<'mir, 'tcx>( body: &'mir mir::Body<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); + assert!( + cid.promoted.is_some() + || matches!( + ecx.tcx.hir().body_const_context(def_id), + Some(ConstContext::Const | ConstContext::Static(_)) + ) + ); let tcx = *ecx.tcx; let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); From 99df3406cf419cb5e45f5ee59c7b04cb294630c5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 7 Dec 2020 15:13:12 +0100 Subject: [PATCH 159/719] Hide associated constants too when collapsing implementation --- src/librustdoc/html/static/main.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 69984be5eb62..0c55a61bb7d0 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2257,9 +2257,12 @@ function defocusSearchBar() { function implHider(addOrRemove, fullHide) { return function(n) { - var is_method = hasClass(n, "method") || fullHide; - if (is_method || hasClass(n, "type")) { - if (is_method === true) { + var shouldHide = + fullHide === true || + hasClass(n, "method") === true || + hasClass(n, "associatedconstant") === true; + if (shouldHide === true || hasClass(n, "type") === true) { + if (shouldHide === true) { if (addOrRemove) { addClass(n, "hidden-by-impl-hider"); } else { From f77f1db35b1f263286962cfa5e5c08a55add83cb Mon Sep 17 00:00:00 2001 From: Korrat Date: Sat, 24 Oct 2020 16:48:10 +0200 Subject: [PATCH 160/719] Add a lint for maps with zero-sized values Co-authored-by: Eduardo Broto --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 4 + clippy_lints/src/zero_sized_map_values.rs | 82 ++++++++++++++++ tests/ui/zero_sized_btreemap_values.rs | 68 +++++++++++++ tests/ui/zero_sized_btreemap_values.stderr | 107 +++++++++++++++++++++ tests/ui/zero_sized_hashmap_values.rs | 68 +++++++++++++ tests/ui/zero_sized_hashmap_values.stderr | 107 +++++++++++++++++++++ 7 files changed, 437 insertions(+) create mode 100644 clippy_lints/src/zero_sized_map_values.rs create mode 100644 tests/ui/zero_sized_btreemap_values.rs create mode 100644 tests/ui/zero_sized_btreemap_values.stderr create mode 100644 tests/ui/zero_sized_hashmap_values.rs create mode 100644 tests/ui/zero_sized_hashmap_values.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 82f2ad7ec4e8..af3b1c1db2ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2171,5 +2171,6 @@ Released 2018-09-13 [`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr +[`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a92ae9ed8d93..5fca088c9b40 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -345,6 +345,7 @@ mod wildcard_dependencies; mod wildcard_imports; mod write; mod zero_div_zero; +mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` pub use crate::utils::conf::Conf; @@ -944,6 +945,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &write::WRITE_LITERAL, &write::WRITE_WITH_NEWLINE, &zero_div_zero::ZERO_DIVIDED_BY_ZERO, + &zero_sized_map_values::ZERO_SIZED_MAP_VALUES, ]); // end register lints, do not remove this comment, it’s used in `update_lints` @@ -1204,6 +1206,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops); store.register_late_pass(|| box strings::StrToString); store.register_late_pass(|| box strings::StringToString); + store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1336,6 +1339,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unused_self::UNUSED_SELF), LintId::of(&wildcard_imports::ENUM_GLOB_USE), LintId::of(&wildcard_imports::WILDCARD_IMPORTS), + LintId::of(&zero_sized_map_values::ZERO_SIZED_MAP_VALUES), ]); #[cfg(feature = "internal-lints")] diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs new file mode 100644 index 000000000000..1d5fa8d06a99 --- /dev/null +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -0,0 +1,82 @@ +use if_chain::if_chain; +use rustc_hir::{self as hir, HirId, ItemKind, Node}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{Adt, Ty}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_target::abi::LayoutOf as _; +use rustc_typeck::hir_ty_to_ty; + +use crate::utils::{is_type_diagnostic_item, match_type, paths, span_lint_and_help}; + +declare_clippy_lint! { + /// **What it does:** Checks for maps with zero-sized value types anywhere in the code. + /// + /// **Why is this bad?** Since there is only a single value for a zero-sized type, a map + /// containing zero sized values is effectively a set. Using a set in that case improves + /// readability and communicates intent more clearly. + /// + /// **Known problems:** + /// * A zero-sized type cannot be recovered later if it contains private fields. + /// * This lints the signature of public items + /// + /// **Example:** + /// + /// ```rust + /// # use std::collections::HashMap; + /// fn unique_words(text: &str) -> HashMap<&str, ()> { + /// todo!(); + /// } + /// ``` + /// Use instead: + /// ```rust + /// # use std::collections::HashSet; + /// fn unique_words(text: &str) -> HashSet<&str> { + /// todo!(); + /// } + /// ``` + pub ZERO_SIZED_MAP_VALUES, + pedantic, + "usage of map with zero-sized value type" +} + +declare_lint_pass!(ZeroSizedMapValues => [ZERO_SIZED_MAP_VALUES]); + +impl LateLintPass<'_> for ZeroSizedMapValues { + fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { + if_chain! { + if !hir_ty.span.from_expansion(); + if !in_trait_impl(cx, hir_ty.hir_id); + let ty = ty_from_hir_ty(cx, hir_ty); + if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) || match_type(cx, ty, &paths::BTREEMAP); + if let Adt(_, ref substs) = ty.kind(); + let ty = substs.type_at(1); + if let Ok(layout) = cx.layout_of(ty); + if layout.is_zst(); + then { + span_lint_and_help(cx, ZERO_SIZED_MAP_VALUES, hir_ty.span, "map with zero-sized value type", None, "consider using a set instead"); + } + } + } +} + +fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool { + let parent_id = cx.tcx.hir().get_parent_item(hir_id); + if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(parent_id)) { + if let ItemKind::Impl { of_trait: Some(_), .. } = item.kind { + return true; + } + } + false +} + +fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { + cx.maybe_typeck_results() + .and_then(|results| { + if results.hir_owner == hir_ty.hir_id.owner { + results.node_type_opt(hir_ty.hir_id) + } else { + None + } + }) + .unwrap_or_else(|| hir_ty_to_ty(cx.tcx, hir_ty)) +} diff --git a/tests/ui/zero_sized_btreemap_values.rs b/tests/ui/zero_sized_btreemap_values.rs new file mode 100644 index 000000000000..5cd254787d83 --- /dev/null +++ b/tests/ui/zero_sized_btreemap_values.rs @@ -0,0 +1,68 @@ +#![warn(clippy::zero_sized_map_values)] +use std::collections::BTreeMap; + +const CONST_OK: Option> = None; +const CONST_NOT_OK: Option> = None; + +static STATIC_OK: Option> = None; +static STATIC_NOT_OK: Option> = None; + +type OkMap = BTreeMap; +type NotOkMap = BTreeMap; + +enum TestEnum { + Ok(BTreeMap), + NotOk(BTreeMap), +} + +struct Test { + ok: BTreeMap, + not_ok: BTreeMap, + + also_not_ok: Vec>, +} + +trait TestTrait { + type Output; + + fn produce_output() -> Self::Output; + + fn weird_map(&self, map: BTreeMap); +} + +impl Test { + fn ok(&self) -> BTreeMap { + todo!() + } + + fn not_ok(&self) -> BTreeMap { + todo!() + } +} + +impl TestTrait for Test { + type Output = BTreeMap; + + fn produce_output() -> Self::Output { + todo!(); + } + + fn weird_map(&self, map: BTreeMap) { + todo!(); + } +} + +fn test(map: BTreeMap, key: &str) -> BTreeMap { + todo!(); +} + +fn test2(map: BTreeMap, key: &str) -> BTreeMap { + todo!(); +} + +fn main() { + let _: BTreeMap = BTreeMap::new(); + let _: BTreeMap = BTreeMap::new(); + + let _: BTreeMap<_, _> = std::iter::empty::<(String, ())>().collect(); +} diff --git a/tests/ui/zero_sized_btreemap_values.stderr b/tests/ui/zero_sized_btreemap_values.stderr new file mode 100644 index 000000000000..334d921a9af3 --- /dev/null +++ b/tests/ui/zero_sized_btreemap_values.stderr @@ -0,0 +1,107 @@ +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:5:28 + | +LL | const CONST_NOT_OK: Option> = None; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::zero-sized-map-values` implied by `-D warnings` + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:8:30 + | +LL | static STATIC_NOT_OK: Option> = None; + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:11:17 + | +LL | type NotOkMap = BTreeMap; + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:15:11 + | +LL | NotOk(BTreeMap), + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:20:13 + | +LL | not_ok: BTreeMap, + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:22:22 + | +LL | also_not_ok: Vec>, + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:30:30 + | +LL | fn weird_map(&self, map: BTreeMap); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:38:25 + | +LL | fn not_ok(&self) -> BTreeMap { + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:55:14 + | +LL | fn test(map: BTreeMap, key: &str) -> BTreeMap { + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:55:50 + | +LL | fn test(map: BTreeMap, key: &str) -> BTreeMap { + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:64:35 + | +LL | let _: BTreeMap = BTreeMap::new(); + | ^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:64:12 + | +LL | let _: BTreeMap = BTreeMap::new(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_btreemap_values.rs:67:12 + | +LL | let _: BTreeMap<_, _> = std::iter::empty::<(String, ())>().collect(); + | ^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: aborting due to 13 previous errors + diff --git a/tests/ui/zero_sized_hashmap_values.rs b/tests/ui/zero_sized_hashmap_values.rs new file mode 100644 index 000000000000..a1608d863fb5 --- /dev/null +++ b/tests/ui/zero_sized_hashmap_values.rs @@ -0,0 +1,68 @@ +#![warn(clippy::zero_sized_map_values)] +use std::collections::HashMap; + +const CONST_OK: Option> = None; +const CONST_NOT_OK: Option> = None; + +static STATIC_OK: Option> = None; +static STATIC_NOT_OK: Option> = None; + +type OkMap = HashMap; +type NotOkMap = HashMap; + +enum TestEnum { + Ok(HashMap), + NotOk(HashMap), +} + +struct Test { + ok: HashMap, + not_ok: HashMap, + + also_not_ok: Vec>, +} + +trait TestTrait { + type Output; + + fn produce_output() -> Self::Output; + + fn weird_map(&self, map: HashMap); +} + +impl Test { + fn ok(&self) -> HashMap { + todo!() + } + + fn not_ok(&self) -> HashMap { + todo!() + } +} + +impl TestTrait for Test { + type Output = HashMap; + + fn produce_output() -> Self::Output { + todo!(); + } + + fn weird_map(&self, map: HashMap) { + todo!(); + } +} + +fn test(map: HashMap, key: &str) -> HashMap { + todo!(); +} + +fn test2(map: HashMap, key: &str) -> HashMap { + todo!(); +} + +fn main() { + let _: HashMap = HashMap::new(); + let _: HashMap = HashMap::new(); + + let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect(); +} diff --git a/tests/ui/zero_sized_hashmap_values.stderr b/tests/ui/zero_sized_hashmap_values.stderr new file mode 100644 index 000000000000..43987b3d01d1 --- /dev/null +++ b/tests/ui/zero_sized_hashmap_values.stderr @@ -0,0 +1,107 @@ +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:5:28 + | +LL | const CONST_NOT_OK: Option> = None; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::zero-sized-map-values` implied by `-D warnings` + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:8:30 + | +LL | static STATIC_NOT_OK: Option> = None; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:11:17 + | +LL | type NotOkMap = HashMap; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:15:11 + | +LL | NotOk(HashMap), + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:20:13 + | +LL | not_ok: HashMap, + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:22:22 + | +LL | also_not_ok: Vec>, + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:30:30 + | +LL | fn weird_map(&self, map: HashMap); + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:38:25 + | +LL | fn not_ok(&self) -> HashMap { + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:55:14 + | +LL | fn test(map: HashMap, key: &str) -> HashMap { + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:55:49 + | +LL | fn test(map: HashMap, key: &str) -> HashMap { + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:64:34 + | +LL | let _: HashMap = HashMap::new(); + | ^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:64:12 + | +LL | let _: HashMap = HashMap::new(); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> $DIR/zero_sized_hashmap_values.rs:67:12 + | +LL | let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect(); + | ^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: aborting due to 13 previous errors + From 33ae62c3d7c5a619595e9faced2450dae27ad702 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 9 Dec 2020 13:17:54 -0500 Subject: [PATCH 161/719] Clarify that String::split_at takes a byte index. --- library/alloc/src/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index ce216e5336eb..27b32b695026 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1413,7 +1413,7 @@ impl String { self.len() == 0 } - /// Splits the string into two at the given index. + /// Splits the string into two at the given byte index. /// /// Returns a newly allocated `String`. `self` contains bytes `[0, at)`, and /// the returned `String` contains bytes `[at, len)`. `at` must be on the From 994b91ac73016e2671138115ecd7fbbb31f13d28 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 Dec 2020 19:55:11 +0100 Subject: [PATCH 162/719] Optimize branches when the target is statically known to a jump This can happen in generic code --- src/base.rs | 24 ++++++++++++++++++------ src/optimize/peephole.rs | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/base.rs b/src/base.rs index 72073896a723..3af4897b4f0b 100644 --- a/src/base.rs +++ b/src/base.rs @@ -307,7 +307,9 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) { } => { let discr = codegen_operand(fx, discr).load_scalar(fx); - if switch_ty.kind() == fx.tcx.types.bool.kind() { + let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind() + || (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0); + if use_bool_opt { assert_eq!(targets.iter().count(), 1); let (then_value, then_block) = targets.iter().next().unwrap(); let then_block = fx.get_block(then_block); @@ -325,12 +327,22 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) { let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr); let discr = crate::optimize::peephole::make_branchable_value(&mut fx.bcx, discr); - if test_zero { - fx.bcx.ins().brz(discr, then_block, &[]); - fx.bcx.ins().jump(else_block, &[]); + if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken( + &fx.bcx, discr, test_zero, + ) { + if taken { + fx.bcx.ins().jump(then_block, &[]); + } else { + fx.bcx.ins().jump(else_block, &[]); + } } else { - fx.bcx.ins().brnz(discr, then_block, &[]); - fx.bcx.ins().jump(else_block, &[]); + if test_zero { + fx.bcx.ins().brz(discr, then_block, &[]); + fx.bcx.ins().jump(else_block, &[]); + } else { + fx.bcx.ins().brnz(discr, then_block, &[]); + fx.bcx.ins().jump(else_block, &[]); + } } } else { let mut switch = ::cranelift_frontend::Switch::new(); diff --git a/src/optimize/peephole.rs b/src/optimize/peephole.rs index f8e0f3af3d0a..a575ed8dc35f 100644 --- a/src/optimize/peephole.rs +++ b/src/optimize/peephole.rs @@ -73,7 +73,7 @@ pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) - })() .unwrap_or_else(|| { match bcx.func.dfg.value_type(arg) { - types::I8 | types::I32 => { + types::I8 | types::I16 => { // WORKAROUND for brz.i8 and brnz.i8 not yet being implemented bcx.ins().uextend(types::I32, arg) } @@ -81,3 +81,40 @@ pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) - } }) } + +/// Returns whether the branch is statically known to be taken or `None` if it isn't statically known. +pub(crate) fn maybe_known_branch_taken( + bcx: &FunctionBuilder<'_>, + arg: Value, + test_zero: bool, +) -> Option { + let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) { + arg_inst + } else { + return None; + }; + + match bcx.func.dfg[arg_inst] { + InstructionData::UnaryBool { + opcode: Opcode::Bconst, + imm, + } => { + if test_zero { + Some(!imm) + } else { + Some(imm) + } + } + InstructionData::UnaryImm { + opcode: Opcode::Iconst, + imm, + } => { + if test_zero { + Some(imm.bits() == 0) + } else { + Some(imm.bits() != 0) + } + } + _ => None, + } +} From 5c1d2ced03fe8ce62deaf23abf62213d959ec4cb Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 9 Dec 2020 21:54:24 +0200 Subject: [PATCH 163/719] tests: add 3 cases involving pointers to codegen/transmute-scalar. --- src/test/codegen/transmute-scalar.rs | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/test/codegen/transmute-scalar.rs b/src/test/codegen/transmute-scalar.rs index 48aea4a2f086..f16335fdc74f 100644 --- a/src/test/codegen/transmute-scalar.rs +++ b/src/test/codegen/transmute-scalar.rs @@ -2,6 +2,9 @@ #![crate_type = "lib"] +// FIXME(eddyb) all of these tests show memory stores and loads, even after a +// scalar `bitcast`, more special-casing is required to remove `alloca` usage. + // CHECK: define i32 @f32_to_bits(float %x) // CHECK: %2 = bitcast float %x to i32 // CHECK-NEXT: store i32 %2, i32* %0 @@ -33,3 +36,50 @@ pub fn bool_to_byte(b: bool) -> u8 { pub unsafe fn byte_to_bool(byte: u8) -> bool { std::mem::transmute(byte) } + +// CHECK: define i8* @ptr_to_ptr(i16* %p) +// CHECK: %2 = bitcast i16* %p to i8* +// CHECK-NEXT: store i8* %2, i8** %0 +// CHECK-NEXT: %3 = load i8*, i8** %0 +// CHECK: ret i8* %3 +#[no_mangle] +pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { + unsafe { std::mem::transmute(p) } +} + +// HACK(eddyb) scalar `transmute`s between pointers and non-pointers are +// currently not special-cased like other scalar `transmute`s, because +// LLVM requires specifically `ptrtoint`/`inttoptr` instead of `bitcast`. +// +// Tests below show the non-special-cased behavior (with the possible +// future special-cased instructions in the "NOTE(eddyb)" comments). + +// CHECK: define [[USIZE:i[0-9]+]] @ptr_to_int(i16* %p) + +// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: +// %2 = ptrtoint i16* %p to [[USIZE]] +// store [[USIZE]] %2, [[USIZE]]* %0 +// CHECK: %2 = bitcast [[USIZE]]* %0 to i16** +// CHECK-NEXT: store i16* %p, i16** %2 + +// CHECK-NEXT: %3 = load [[USIZE]], [[USIZE]]* %0 +// CHECK: ret [[USIZE]] %3 +#[no_mangle] +pub fn ptr_to_int(p: *mut u16) -> usize { + unsafe { std::mem::transmute(p) } +} + +// CHECK: define i16* @int_to_ptr([[USIZE]] %i) + +// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: +// %2 = inttoptr [[USIZE]] %i to i16* +// store i16* %2, i16** %0 +// CHECK: %2 = bitcast i16** %0 to [[USIZE]]* +// CHECK-NEXT: store [[USIZE]] %i, [[USIZE]]* %2 + +// CHECK-NEXT: %3 = load i16*, i16** %0 +// CHECK: ret i16* %3 +#[no_mangle] +pub fn int_to_ptr(i: usize) -> *mut u16 { + unsafe { std::mem::transmute(i) } +} From 028754a2f7f62ed1e4df889fadfa74eb2d007109 Mon Sep 17 00:00:00 2001 From: The8472 Date: Sat, 21 Nov 2020 19:34:45 +0100 Subject: [PATCH 164/719] implement better availability probing for copy_file_range previously any attempt to copy to an immutable file (EPERM) would disable copy_file_range support for the whole process. --- library/std/src/sys/unix/kernel_copy.rs | 82 +++++++++++++++---------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 5bfac8031534..56efc93a1e28 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -59,7 +59,7 @@ use crate::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use crate::os::unix::net::UnixStream; use crate::process::{ChildStderr, ChildStdin, ChildStdout}; use crate::ptr; -use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use crate::sys::cvt; #[cfg(test)] @@ -491,6 +491,13 @@ impl CopyResult { } } +/// Invalid file descriptor. +/// +/// Valid file descriptors are guaranteed to be positive numbers (see `open()` manpage) +/// while negative values are used to indicate errors. +/// Thus -1 will never be overlap with a valid open file. +const INVALID_FD: RawFd = -1; + /// linux-specific implementation that will attempt to use copy_file_range for copy offloading /// as the name says, it only works on regular files /// @@ -500,9 +507,13 @@ impl CopyResult { pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> CopyResult { use crate::cmp; + const NOT_PROBED: u8 = 0; + const UNAVAILABLE: u8 = 1; + const AVAILABLE: u8 = 2; + // Kernel prior to 4.5 don't have copy_file_range // We store the availability in a global to avoid unnecessary syscalls - static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true); + static HAS_COPY_FILE_RANGE: AtomicU8 = AtomicU8::new(NOT_PROBED); syscall! { fn copy_file_range( @@ -515,39 +526,39 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> ) -> libc::ssize_t } - let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); + match HAS_COPY_FILE_RANGE.load(Ordering::Relaxed) { + NOT_PROBED => { + // EPERM can indicate seccomp filters or an immutable file. + // To distinguish these cases we probe with invalid file descriptors which should result in EBADF if the syscall is supported + // and some other error (ENOSYS or EPERM) if it's not available + let result = unsafe { + cvt(copy_file_range(INVALID_FD, ptr::null_mut(), INVALID_FD, ptr::null_mut(), 1, 0)) + }; + + if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(libc::EBADF))) { + HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed); + } else { + HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed); + return CopyResult::Fallback(0); + } + } + UNAVAILABLE => return CopyResult::Fallback(0), + _ => {} + }; + let mut written = 0u64; while written < max_len { - let copy_result = if has_copy_file_range { - let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64); - // cap to 1GB chunks in case u64::MAX is passed as max_len and the file has a non-zero seek position - // this allows us to copy large chunks without hitting EOVERFLOW, - // unless someone sets a file offset close to u64::MAX - 1GB, in which case a fallback would be required - let bytes_to_copy = cmp::min(bytes_to_copy as usize, 0x4000_0000usize); - 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, - ptr::null_mut(), - writer, - ptr::null_mut(), - bytes_to_copy, - 0, - )) - }; - if let Err(ref copy_err) = copy_result { - match copy_err.raw_os_error() { - Some(libc::ENOSYS | libc::EPERM | libc::EOPNOTSUPP) => { - HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); - } - _ => {} - } - } - copy_result - } else { - Err(Error::from_raw_os_error(libc::ENOSYS)) + let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64); + // cap to 1GB chunks in case u64::MAX is passed as max_len and the file has a non-zero seek position + // this allows us to copy large chunks without hitting EOVERFLOW, + // unless someone sets a file offset close to u64::MAX - 1GB, in which case a fallback would be required + let bytes_to_copy = cmp::min(bytes_to_copy as usize, 0x4000_0000usize); + 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, ptr::null_mut(), writer, ptr::null_mut(), bytes_to_copy, 0)) }; + match copy_result { Ok(0) if written == 0 => { // fallback to work around several kernel bugs where copy_file_range will fail to @@ -567,11 +578,14 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> libc::ENOSYS | libc::EXDEV | libc::EINVAL | libc::EPERM | libc::EOPNOTSUPP, ) => { // Try fallback io::copy if either: - // - Kernel version is < 4.5 (ENOSYS) + // - Kernel version is < 4.5 (ENOSYS¹) // - Files are mounted on different fs (EXDEV) // - copy_file_range is broken in various ways on RHEL/CentOS 7 (EOPNOTSUPP) - // - copy_file_range is disallowed, for example by seccomp (EPERM) + // - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM) // - copy_file_range cannot be used with pipes or device nodes (EINVAL) + // + // ¹ these cases should be detected by the initial probe but we handle them here + // anyway in case syscall interception changes during runtime assert_eq!(written, 0); CopyResult::Fallback(0) } From 7647d03c33339bd85a1665047b22ae7e800fee98 Mon Sep 17 00:00:00 2001 From: The8472 Date: Wed, 9 Dec 2020 21:12:39 +0100 Subject: [PATCH 165/719] Improve comment grammar --- library/std/src/sys/unix/kernel_copy.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 56efc93a1e28..200dbf06ff8a 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -498,8 +498,8 @@ impl CopyResult { /// Thus -1 will never be overlap with a valid open file. const INVALID_FD: RawFd = -1; -/// linux-specific implementation that will attempt to use copy_file_range for copy offloading -/// as the name says, it only works on regular files +/// Linux-specific implementation that will attempt to use copy_file_range for copy offloading. +/// As the name says, it only works on regular files. /// /// Callers must handle fallback to a generic copy loop. /// `Fallback` may indicate non-zero number of bytes already written From 56d9784b5a6b43af53fd3268cf3dc0ea6b9fd95c Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 9 Dec 2020 15:14:58 -0800 Subject: [PATCH 166/719] Fix typo in `wrapping_shl` documentation --- library/core/src/num/int_macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 33eefe5d2658..4fa48427ec6e 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1211,7 +1211,7 @@ any high-order bits of `rhs` that would cause the shift to exceed the bitwidth o 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`](#method.rotate_left) function, +The primitive integer types all implement a [`rotate_left`](#method.rotate_left) function, which may be what you want instead. # Examples From c6f2d49ff8be6b42bba94e7dc96e0fff8b5ca580 Mon Sep 17 00:00:00 2001 From: Chenguang Wang Date: Wed, 9 Dec 2020 18:56:27 -0800 Subject: [PATCH 167/719] fix issue #78496 --- .../src/transform/early_otherwise_branch.rs | 28 +++++++++++++++++++ src/test/ui/mir/issue-78496.rs | 16 +++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/test/ui/mir/issue-78496.rs diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index f91477911a48..5829c5229353 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -283,6 +283,34 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { return None; } + // when one place is the projection of the other, it's not safe to calculate their discriminant values sequentially. + // for example, this should not be optimized: + // + // ```rust + // enum E<'a> { Empty, Some(&'a E<'a>), } + // let Some(Some(_)) = e; + // ``` + // + // ```mir + // bb0: { + // _2 = discriminant(*_1) + // switchInt(move _2) -> [...] + // } + // bb1: { + // _3 = discriminant(*(((*_1) as Some).0: &E)) + // switchInt(move _3) -> [...] + // } + // ``` + let discr_place = discr_info.place_of_adt_discr_read; + let this_discr_place = this_bb_discr_info.place_of_adt_discr_read; + if discr_place.local == this_discr_place.local + && (discr_place.projection.starts_with(this_discr_place.projection) + || this_discr_place.projection.starts_with(discr_place.projection)) + { + trace!("NO: one target is the projection of another"); + return None; + } + // if we reach this point, the optimization applies, and we should be able to optimize this case // store the info that is needed to apply the optimization diff --git a/src/test/ui/mir/issue-78496.rs b/src/test/ui/mir/issue-78496.rs new file mode 100644 index 000000000000..cc45945a2b8d --- /dev/null +++ b/src/test/ui/mir/issue-78496.rs @@ -0,0 +1,16 @@ +// run-pass +// compile-flags: -Z mir-opt-level=2 -C opt-level=0 + +// example from #68867 +pub enum E<'a> { + Empty, + Some(&'a E<'a>), +} + +fn f(e: &E) -> u32 { + if let E::Some(E::Some(_)) = e { 1 } else { 2 } +} + +fn main() { + assert_eq!(f(&E::Empty), 2); +} From 6a1d0699a484ee875c87394f70cb37f09acadd88 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Thu, 26 Nov 2020 00:05:18 -0500 Subject: [PATCH 168/719] Use Places for captures in MIR - Use closure_min_capture maps to capture precise paths - PlaceBuilder now searches for ancestors in min_capture list - Add API to `Ty` to allow access to the n-th element in a tuple in O(1) time. Co-authored-by: Roxane Fruytier --- compiler/rustc_middle/src/ty/sty.rs | 9 ++ .../src/build/expr/as_place.rs | 150 +++++++++++++++--- 2 files changed, 137 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 78994c6e1c77..a90807de99d3 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2174,6 +2174,15 @@ impl<'tcx> TyS<'tcx> { } } + /// Get the `i`-th element of a tuple. + /// Panics when called on anything but a tuple. + pub fn tuple_element_ty(&self, i: usize) -> Option> { + match self.kind() { + Tuple(substs) => substs.iter().nth(i).map(|field| field.expect_ty()), + _ => bug!("tuple_fields called on non-tuple"), + } + } + /// If the type contains variants, returns the valid range of variant indices. // // FIXME: This requires the optimized MIR in the case of generators. diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 2ab733fabb8c..b3957fa72227 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -7,10 +7,12 @@ use crate::thir::*; use rustc_hir::def_id::DefId; use rustc_hir::HirId; use rustc_middle::middle::region; +use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; use rustc_span::Span; +use rustc_target::abi::VariantIdx; use rustc_index::vec::Idx; @@ -70,28 +72,129 @@ struct PlaceBuilder<'tcx> { projection: Vec>, } -fn capture_matching_projections<'a, 'tcx>( +/// Given a list of MIR projections, convert them to list of HIR ProjectionKind. +/// The projections are truncated to represent a path that might be captured by a +/// closure/generator. This implies the vector returned from this function doesn't contain +/// ProjectionElems `Downcast`, `ConstantIndex`, `Index`, or `Subslice` because those will never be +/// part of a path that is captued by a closure. We stop applying projections once we see the first +/// projection that isn't captured by a closure. +fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( + mir_projections: &Vec>, +) -> Vec { + + let mut hir_projections = Vec::new(); + + for mir_projection in mir_projections { + let hir_projection = match mir_projection { + ProjectionElem::Deref => HirProjectionKind::Deref, + ProjectionElem::Field(field, _) => { + // We will never encouter this for multivariant enums, + // read the comment for `Downcast`. + HirProjectionKind::Field(field.index() as u32, VariantIdx::new(0)) + }, + ProjectionElem::Downcast(..) => { + // This projections exist only for enums that have + // multiple variants. Since such enums that are captured + // completely, we can stop here. + break + }, + ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => { + // We don't capture array-access projections. + // We can stop here as arrays are captured completely. + break + }, + }; + + hir_projections.push(hir_projection); + } + + hir_projections +} + +/// Return true if the `proj_possible_ancestor` represents an ancestor path +/// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`, +/// assuming they both start off of the same root variable. +/// +/// **Note:** It's the caller's responsibility to ensure that both lists of projections +/// start off of the same root variable. +/// +/// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of +/// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`. +/// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`. +/// 2. Since we only look at the projections here function will return `bar.x` as an a valid +/// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections +/// list are being applied to the same root variable. +fn is_ancestor_or_same_capture( + proj_possible_ancestor: &Vec, + proj_capture: &Vec, +) -> bool { + // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false. + // Therefore we can't just check if all projections are same in the zipped iterator below. + if proj_possible_ancestor.len() > proj_capture.len() { + return false; + } + + proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b) +} + +/// Computes the index of a capture within the desugared closure provided the closure's +/// `closure_min_captures` and the capture's index of the capture in the +/// `ty::MinCaptureList` of the root variable `var_hir_id`. +fn compute_capture_idx<'tcx>( + closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>, + var_hir_id: HirId, + root_var_idx: usize, +) -> usize { + let mut res = 0; + for (var_id, capture_list) in closure_min_captures { + if *var_id == var_hir_id { + res += root_var_idx; + break; + } else { + res += capture_list.len(); + } + } + + res +} + +/// Given a closure, returns the index of a capture within the desugared closure struct and the +/// `ty::CapturedPlace` which is the ancestor of the Place represented using the `var_hir_id` +/// and `projection`. +/// +/// Note there will be at most one ancestor for any given Place. +/// +/// Returns None, when the ancestor is not found. +fn find_capture_matching_projections<'a, 'tcx>( typeck_results: &'a ty::TypeckResults<'tcx>, var_hir_id: HirId, closure_def_id: DefId, - _projections: &Vec>, -) -> Option<(usize, ty::UpvarCapture<'tcx>)> { - typeck_results - .closure_captures - .get(&closure_def_id) - .and_then(|captures| captures.get_full(&var_hir_id)) - .and_then(|(capture_index, _, _)|{ - let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local()); - let capture_kind = typeck_results.upvar_capture(upvar_id); - Some((capture_index, capture_kind)) - }) + projections: &Vec>, +) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> { + let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?; + let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?; + + let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections); + + // If an ancestor is found, `idx` is the index within the list of captured places + // for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself. + let (idx, capture) = root_variable_min_captures.iter().enumerate().find(|(_, capture)| { + let possible_ancestor_proj_kinds = + capture.place.projections.iter().map(|proj| proj.kind).collect(); + is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections) + })?; + + // Convert index to be from the presepective of the entire closure_min_captures map + // instead of just the root variable capture list + Some((compute_capture_idx(closure_min_captures, var_hir_id, idx), capture)) } -/// Takes a PlaceBuilder and resolves the upvar (if any) within it, -/// so that the PlaceBuilder now starts from PlaceBase::Local. +/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the +/// `PlaceBuilder` now starts from `PlaceBase::Local`. /// -/// Returns a Result with the error being the HirId of the -/// Upvar that was not found. +/// Returns a Result with the error being the HirId of the Upvar that was not found. fn to_upvars_resolved_place_builder<'a, 'tcx>( from_builder: PlaceBuilder<'tcx>, tcx: TyCtxt<'tcx>, @@ -110,8 +213,8 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( ty::ClosureKind::FnOnce => {} } - let (capture_index, capture_kind) = - if let Some(capture_details) = capture_matching_projections( + let (capture_index, capture) = + if let Some(capture_details) = find_capture_matching_projections( typeck_results, var_hir_id, closure_def_id, @@ -149,21 +252,24 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( // Access the capture by accessing the field within the Closure struct. // // We must have inferred the capture types since we are building MIR, therefore - // it's safe to call `upvar_tys` and we can unwrap here because + // it's safe to call `tuple_element_ty` and we can unwrap here because // we know that the capture exists and is the `capture_index`-th capture. - let var_ty = substs.upvar_tys().nth(capture_index).unwrap(); + let var_ty = substs.tupled_upvars_ty().tuple_element_ty(capture_index).unwrap(); upvar_resolved_place_builder = upvar_resolved_place_builder.field(Field::new(capture_index), var_ty); // If the variable is captured via ByRef(Immutable/Mutable) Borrow, // we need to deref it - upvar_resolved_place_builder = match capture_kind { + upvar_resolved_place_builder = match capture.info.capture_kind { ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(), ty::UpvarCapture::ByValue(_) => upvar_resolved_place_builder, }; - let next_projection = 0; + let next_projection = capture.place.projections.len(); let mut curr_projections = from_builder.projection; + + // We used some of the projections to build the capture itself, + // now we apply the remaining to the upvar resolved place. upvar_resolved_place_builder.projection.extend( curr_projections.drain(next_projection..)); From e2efdd156bf6915d6831821ff8a263e43e493e32 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Thu, 26 Nov 2020 00:07:41 -0500 Subject: [PATCH 169/719] Use precise places when lowering Closures in THIR - Closures now use closure_min_captures to figure out captured paths - Build upvar_mutbls using closure_min_captures - Change logic in limit_capture_mutability to differentiate b/w capturing parent's local variable or capturing a variable that is captured by the parent (in case of nested closure) using PlaceBase. Co-authored-by: Roxane Fruytier --- .../src/build/expr/as_place.rs | 12 ++- .../src/build/expr/as_rvalue.rs | 74 ++++++++++--------- compiler/rustc_mir_build/src/build/mod.rs | 22 ++++-- compiler/rustc_mir_build/src/thir/cx/expr.rs | 60 +++++++++++---- 4 files changed, 107 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index b3957fa72227..e1a3dc87c8c8 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -18,7 +18,7 @@ use rustc_index::vec::Idx; /// The "outermost" place that holds this value. #[derive(Copy, Clone)] -pub enum PlaceBase { +crate enum PlaceBase { /// Denotes the start of a `Place`. Local(Local), @@ -67,7 +67,7 @@ pub enum PlaceBase { /// This is used internally when building a place for an expression like `a.b.c`. The fields `b` /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. #[derive(Clone)] -struct PlaceBuilder<'tcx> { +crate struct PlaceBuilder<'tcx> { base: PlaceBase, projection: Vec>, } @@ -279,7 +279,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( } impl<'tcx> PlaceBuilder<'tcx> { - fn into_place<'a>( + crate fn into_place<'a>( self, tcx: TyCtxt<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, @@ -299,6 +299,10 @@ impl<'tcx> PlaceBuilder<'tcx> { to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() } + crate fn base(&self) -> PlaceBase { + self.base + } + fn field(self, f: Field, ty: Ty<'tcx>) -> Self { self.project(PlaceElem::Field(f, ty)) } @@ -352,7 +356,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// This is used when constructing a compound `Place`, so that we can avoid creating /// intermediate `Place` values until we know the full set of projections. - fn as_place_builder(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + crate fn as_place_builder(&mut self, block: BasicBlock, expr: M) -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>>, { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c0e4141a558d..bfb3dcb8da35 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -4,6 +4,7 @@ use rustc_index::vec::Idx; use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; +use crate::build::expr::as_place::PlaceBase; use crate::thir::*; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind; @@ -393,44 +394,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); - let arg_place = unpack!(block = this.as_place(block, arg)); + let arg_place_builder = unpack!(block = this.as_place_builder(block, arg)); - let mutability = match arg_place.as_ref() { - PlaceRef { local, projection: &[] } => this.local_decls[local].mutability, - PlaceRef { local, projection: &[ProjectionElem::Deref] } => { - debug_assert!( - this.local_decls[local].is_ref_for_guard(), - "Unexpected capture place", - ); - this.local_decls[local].mutability - } - PlaceRef { - local, - projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], - } - | PlaceRef { - local, - projection: - &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref], - } => { - let place = PlaceRef { local, projection: proj_base }; + let mutability = match arg_place_builder.base() { + // We are capturing a path that starts off a local variable in the parent. + // The mutability of the current capture is same as the mutability + // of the local declaration in the parent. + PlaceBase::Local(local) => this.local_decls[local].mutability, + // Parent is a closure and we are capturing a path that is captured + // by the parent itself. The mutability of the current capture + // is same as that of the capture in the parent closure. + PlaceBase::Upvar { .. } => { + let enclosing_upvars_resolved = arg_place_builder.clone().into_place( + this.hir.tcx(), + this.hir.typeck_results()); - // Not projected from the implicit `self` in a closure. - debug_assert!( - match place.local_or_deref_local() { - Some(local) => local == Local::new(1), - None => false, - }, - "Unexpected capture place" - ); - // Not in a closure - debug_assert!( - this.upvar_mutbls.len() > upvar_index.index(), - "Unexpected capture place" - ); - this.upvar_mutbls[upvar_index.index()] + match enclosing_upvars_resolved.as_ref() { + PlaceRef { local, projection: &[ProjectionElem::Field(upvar_index, _), ..] } + | PlaceRef { + local, + projection: &[ProjectionElem::Deref, ProjectionElem::Field(upvar_index, _), ..] } => { + // Not in a closure + debug_assert!( + local == Local::new(1), + "Expected local to be Local(1), found {:?}", + local + ); + // Not in a closure + debug_assert!( + this.upvar_mutbls.len() > upvar_index.index(), + "Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}", + this.upvar_mutbls, upvar_index + ); + this.upvar_mutbls[upvar_index.index()] + } + _ => bug!("Unexpected capture place"), + } } - _ => bug!("Unexpected capture place"), }; let borrow_kind = match mutability { @@ -438,6 +438,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, }; + let arg_place = arg_place_builder.into_place( + this.hir.tcx(), + this.hir.typeck_results()); + this.cfg.push_assign( block, source_info, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 34ef4ed78fd0..d7fce15d9966 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{GeneratorKind, HirIdMap, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; @@ -823,7 +824,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // with the closure's DefId. Here, we run through that vec of UpvarIds for // the given closure and use the necessary information to create upvar // debuginfo and to fill `self.upvar_mutbls`. - if let Some(upvars) = hir_typeck_results.closure_captures.get(&fn_def_id) { + if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() { let closure_env_arg = Local::new(1); let mut closure_env_projs = vec![]; let mut closure_ty = self.local_decls[closure_env_arg].ty; @@ -836,14 +837,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty), }; - let upvar_tys = upvar_substs.upvar_tys(); - let upvars_with_tys = upvars.iter().zip(upvar_tys); - self.upvar_mutbls = upvars_with_tys + let capture_tys = upvar_substs.upvar_tys(); + let captures_with_tys = hir_typeck_results + .closure_min_captures_flattened(fn_def_id) + .zip(capture_tys); + + self.upvar_mutbls = captures_with_tys .enumerate() - .map(|(i, ((&var_id, &upvar_id), ty))| { - let capture = hir_typeck_results.upvar_capture(upvar_id); + .map(|(i, (captured_place, ty))| { + let capture = captured_place.info.capture_kind; + let var_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + _ => bug!("Expected an upvar") + }; let mut mutability = Mutability::Not; + + // FIXME(project-rfc-2229#8): Store more precise information let mut name = kw::Invalid; if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) { if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e404afeb698a..d6695a5500d1 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -6,6 +6,8 @@ use crate::thir::*; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_index::vec::Idx; +use rustc_middle::hir::place::PlaceBase as HirPlaceBase; +use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::BorrowKind; use rustc_middle::ty::adjustment::{ @@ -386,14 +388,12 @@ fn make_mirror_unadjusted<'a, 'tcx>( span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } }; + let upvars = cx .typeck_results() - .closure_captures - .get(&def_id) - .iter() - .flat_map(|upvars| upvars.iter()) + .closure_min_captures_flattened(def_id) .zip(substs.upvar_tys()) - .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty)) + .map(|(captured_place, ty)| capture_upvar(cx, expr, captured_place, ty)) .collect(); ExprKind::Closure { closure_id: def_id, substs, upvars, movability } } @@ -981,27 +981,55 @@ fn overloaded_place<'a, 'tcx>( ExprKind::Deref { arg: ref_expr.to_ref() } } -fn capture_upvar<'tcx>( +fn capture_upvar<'a, 'tcx>( cx: &mut Cx<'_, 'tcx>, closure_expr: &'tcx hir::Expr<'tcx>, - var_hir_id: hir::HirId, + captured_place: &'a ty::CapturedPlace<'tcx>, upvar_ty: Ty<'tcx>, ) -> ExprRef<'tcx> { - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id), - }; - let upvar_capture = cx.typeck_results().upvar_capture(upvar_id); + let upvar_capture = captured_place.info.capture_kind; let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); - let var_ty = cx.typeck_results().node_type(var_hir_id); - let captured_var = Expr { + let var_ty = captured_place.place.base_ty; + + // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path + // as it's seen for use within the closure and not at the time of closure creation. + // + // That is we see expect to see it start from a captured upvar and not something that is local + // to the closure's parent. + let var_hir_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + base => bug!("Expected an upvar, found {:?}", base), + }; + + let mut captured_place_expr = Expr { temp_lifetime, ty: var_ty, span: closure_expr.span, kind: convert_var(cx, var_hir_id), }; + + for proj in captured_place.place.projections.iter() { + let kind = match proj.kind { + HirProjectionKind::Deref => ExprKind::Deref { arg: captured_place_expr.to_ref() }, + HirProjectionKind::Field(field, ..) => { + // Variant index will always be 0, because for multi-variant + // enums, we capture the enum entirely. + ExprKind::Field { + lhs: captured_place_expr.to_ref(), + name: Field::new(field as usize), + } + } + HirProjectionKind::Index | HirProjectionKind::Subslice => { + // We don't capture these projections, so we can ignore them here + continue; + } + }; + + captured_place_expr = Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind }; + } + match upvar_capture { - ty::UpvarCapture::ByValue(_) => captured_var.to_ref(), + ty::UpvarCapture::ByValue(_) => captured_place_expr.to_ref(), ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow.kind { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, @@ -1012,7 +1040,7 @@ fn capture_upvar<'tcx>( temp_lifetime, ty: upvar_ty, span: closure_expr.span, - kind: ExprKind::Borrow { borrow_kind, arg: captured_var.to_ref() }, + kind: ExprKind::Borrow { borrow_kind, arg: captured_place_expr.to_ref() }, } .to_ref() } From 237ad1269844f483eb708de015b950253d906886 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Wed, 25 Nov 2020 18:48:26 -0500 Subject: [PATCH 170/719] Use closure_min_captures in borrow checker - Use closure_min_captures to generate the Upvar structure that stores information for diagnostics and information about mutability of captures. --- compiler/rustc_mir/src/borrow_check/mod.rs | 16 +++++++++------- .../rustc_mir/src/borrow_check/type_check/mod.rs | 6 +++++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index de54c5582e04..80eabdd9af83 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -9,6 +9,7 @@ use rustc_hir::{HirId, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, PlaceRef, @@ -75,6 +76,7 @@ crate use region_infer::RegionInferenceContext; crate struct Upvar { name: Symbol, + // FIXME(project-rfc-2229#8): This should use Place or something similar var_hir_id: HirId, /// If true, the capture is behind a reference. @@ -155,13 +157,13 @@ fn do_mir_borrowck<'a, 'tcx>( infcx.set_tainted_by_errors(); } let upvars: Vec<_> = tables - .closure_captures - .get(&def.did.to_def_id()) - .into_iter() - .flat_map(|v| v.values()) - .map(|upvar_id| { - let var_hir_id = upvar_id.var_path.hir_id; - let capture = tables.upvar_capture(*upvar_id); + .closure_min_captures_flattened(def.did.to_def_id()) + .map(|captured_place| { + let var_hir_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + _ => bug!("Expected upvar"), + }; + let capture = captured_place.info.capture_kind; let by_ref = match capture { ty::UpvarCapture::ByValue(_) => false, ty::UpvarCapture::ByRef(..) => true, diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index a5c45452dec8..543b7e7ebaa7 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -749,7 +749,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { (&adt_def.variants[VariantIdx::new(0)], substs) } ty::Closure(_, substs) => { - return match substs.as_closure().upvar_tys().nth(field.index()) { + return match substs + .as_closure() + .tupled_upvars_ty() + .tuple_element_ty(field.index()) + { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { field_count: substs.as_closure().upvar_tys().count(), From 78c0680b3febef5aaa2330d8b0a7879fd44e9eba Mon Sep 17 00:00:00 2001 From: Chenguang Wang Date: Wed, 9 Dec 2020 19:50:11 -0800 Subject: [PATCH 171/719] update comments --- .../rustc_mir/src/transform/early_otherwise_branch.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 5829c5229353..f28a4b467157 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -283,7 +283,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { return None; } - // when one place is the projection of the other, it's not safe to calculate their discriminant values sequentially. + // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially. // for example, this should not be optimized: // // ```rust @@ -294,18 +294,17 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { // ```mir // bb0: { // _2 = discriminant(*_1) - // switchInt(move _2) -> [...] + // switchInt(_2) -> [...] // } // bb1: { // _3 = discriminant(*(((*_1) as Some).0: &E)) - // switchInt(move _3) -> [...] + // switchInt(_3) -> [...] // } // ``` let discr_place = discr_info.place_of_adt_discr_read; let this_discr_place = this_bb_discr_info.place_of_adt_discr_read; if discr_place.local == this_discr_place.local - && (discr_place.projection.starts_with(this_discr_place.projection) - || this_discr_place.projection.starts_with(discr_place.projection)) + && this_discr_place.projection.starts_with(discr_place.projection) { trace!("NO: one target is the projection of another"); return None; From 3812f70355132b53092e826c9d1a753dfd8a1874 Mon Sep 17 00:00:00 2001 From: Chenguang Wang Date: Wed, 9 Dec 2020 20:11:32 -0800 Subject: [PATCH 172/719] fix test case issue ref --- src/test/ui/mir/issue-78496.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/mir/issue-78496.rs b/src/test/ui/mir/issue-78496.rs index cc45945a2b8d..1b0687cfac3f 100644 --- a/src/test/ui/mir/issue-78496.rs +++ b/src/test/ui/mir/issue-78496.rs @@ -1,7 +1,7 @@ // run-pass // compile-flags: -Z mir-opt-level=2 -C opt-level=0 -// example from #68867 +// example from #78496 pub enum E<'a> { Empty, Some(&'a E<'a>), From 613333acd537dff5844cd1ed72d4e6f56752ee6a Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sun, 29 Nov 2020 18:08:47 +0100 Subject: [PATCH 173/719] Pin Clippy to a nightly --- .github/workflows/clippy.yml | 3 --- .github/workflows/clippy_bors.yml | 11 ---------- CONTRIBUTING.md | 21 ++++++++++-------- doc/basics.md | 28 +++--------------------- rust-toolchain | 4 +++- setup-toolchain.sh | 36 ------------------------------- 6 files changed, 18 insertions(+), 85 deletions(-) delete mode 100755 setup-toolchain.sh diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index cf4aa39e49b9..181b3bab4216 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -56,9 +56,6 @@ jobs: restore-keys: | ${{ runner.os }}-x86_64-unknown-linux-gnu - - name: Master Toolchain Setup - run: bash setup-toolchain.sh - # Run - name: Set LD_LIBRARY_PATH (Linux) run: | diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 784463fe0df9..f08182365fc7 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -105,11 +105,6 @@ jobs: restore-keys: | ${{ runner.os }}-${{ matrix.host }} - - name: Master Toolchain Setup - run: bash setup-toolchain.sh - env: - HOST_TOOLCHAIN: ${{ matrix.host }} - # Run - name: Set LD_LIBRARY_PATH (Linux) if: runner.os == 'Linux' @@ -192,9 +187,6 @@ jobs: restore-keys: | ${{ runner.os }}-x86_64-unknown-linux-gnu - - name: Master Toolchain Setup - run: bash setup-toolchain.sh - # Run - name: Build Integration Test run: cargo test --test integration --features integration --no-run @@ -273,9 +265,6 @@ jobs: restore-keys: | ${{ runner.os }}-x86_64-unknown-linux-gnu - - name: Master Toolchain Setup - run: bash setup-toolchain.sh - # Download - name: Download target dir uses: actions/download-artifact@v1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f8c26e2d456d..29cbe2a08ecf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -182,18 +182,21 @@ That's why the `else_if_without_else` example uses the `register_early_pass` fun [early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html [late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html -## Fixing build failures caused by Rust +## Syncing changes from [`rust-lang/rust`] to Clippy -Clippy currently gets built with `rustc` of the `rust-lang/rust` `master` -branch. Most of the times we have to adapt to the changes and only very rarely -there's an actual bug in Rust. +Clippy currently gets built with a pinned nightly version. -If you decide to make Clippy work again with a Rust commit that breaks it, you -have to sync the `rust-lang/rust-clippy` repository with the `subtree` copy of -Clippy in the `rust-lang/rust` repository. +In the `rust-lang/rust` repository, where rustc resides, there's a copy of Clippy +that compiler hackers modify from time to time to adapt to changes in the unstable +API of the compiler. -For general information about `subtree`s in the Rust repository see [Rust's -`CONTRIBUTING.md`][subtree]. +We need to sync these changes back to this repository periodically. If you want +to help with that, you have to sync the `rust-lang/rust-clippy` repository with +the `subtree` copy of Clippy in the `rust-lang/rust` repository, and update +the `rustc-toolchain` file accordingly. + +For general information about `subtree`s in the Rust repository +see [Rust's `CONTRIBUTING.md`][subtree]. ### Patching git-subtree to work with big repos diff --git a/doc/basics.md b/doc/basics.md index f25edb793e26..8b2a8a238900 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -1,16 +1,14 @@ # Basics for hacking on Clippy This document explains the basics for hacking on Clippy. Besides others, this -includes how to set-up the development environment, how to build and how to test -Clippy. For a more in depth description on the codebase take a look at [Adding -Lints] or [Common Tools]. +includes how to build and test Clippy. For a more in depth description on +the codebase take a look at [Adding Lints] or [Common Tools]. [Adding Lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md [Common Tools]: https://github.com/rust-lang/rust-clippy/blob/master/doc/common_tools_writing_lints.md - [Basics for hacking on Clippy](#basics-for-hacking-on-clippy) - [Get the code](#get-the-code) - - [Setup](#setup) - [Building and Testing](#building-and-testing) - [`cargo dev`](#cargo-dev) - [PR](#pr) @@ -38,29 +36,9 @@ git rebase upstream/master git push ``` -## Setup - -Next we need to setup the toolchain to compile Clippy. Since Clippy heavily -relies on compiler internals it is build with the latest rustc master. To get -this toolchain, you can just use the `setup-toolchain.sh` script or use -`rustup-toolchain-install-master`: - -```bash -bash setup-toolchain.sh -# OR -cargo install rustup-toolchain-install-master -# For better IDE integration also add `-c rustfmt -c rust-src` (optional) -rustup-toolchain-install-master -f -n master -c rustc-dev -c llvm-tools -rustup override set master -``` - -_Note:_ Sometimes you may get compiler errors when building Clippy, even if you -didn't change anything. Normally those will be fixed by a maintainer in a few hours. - ## Building and Testing -Once the `master` toolchain is installed, you can build and test Clippy like -every other Rust project: +You can build and test Clippy like every other Rust project: ```bash cargo build # builds Clippy diff --git a/rust-toolchain b/rust-toolchain index bf867e0ae5b6..dba3e57bcf7b 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1,3 @@ -nightly +[toolchain] +channel = "nightly-2020-11-29" +components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] diff --git a/setup-toolchain.sh b/setup-toolchain.sh deleted file mode 100755 index 191ea4315a6b..000000000000 --- a/setup-toolchain.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -# Set up the appropriate rustc toolchain - -set -e - -cd "$(dirname "$0")" - -RTIM_PATH=$(command -v rustup-toolchain-install-master) || INSTALLED=false -CARGO_HOME=${CARGO_HOME:-$HOME/.cargo} - -# Check if RTIM is not installed or installed in other locations not in ~/.cargo/bin -if [[ "$INSTALLED" == false || "$RTIM_PATH" == $CARGO_HOME/bin/rustup-toolchain-install-master ]]; then - cargo +nightly install rustup-toolchain-install-master -else - VERSION=$(rustup-toolchain-install-master -V | grep -o "[0-9.]*") - REMOTE=$(cargo +nightly search rustup-toolchain-install-master | grep -o "[0-9.]*") - echo "info: skipping updating rustup-toolchain-install-master at $RTIM_PATH" - echo " current version : $VERSION" - echo " remote version : $REMOTE" -fi - -RUST_COMMIT=$(git ls-remote https://github.com/rust-lang/rust master | awk '{print $1}') - -if rustc +master -Vv 2>/dev/null | grep -q "$RUST_COMMIT"; then - echo "info: master toolchain is up-to-date" - exit 0 -fi - -if [[ -n "$HOST_TOOLCHAIN" ]]; then - TOOLCHAIN=('--host' "$HOST_TOOLCHAIN") -else - TOOLCHAIN=() -fi - -rustup-toolchain-install-master -f -n master "${TOOLCHAIN[@]}" -c rustc-dev -c llvm-tools -- "$RUST_COMMIT" -rustup override set master From 2e8b00a33150eebf2d1a5aa500466c20cac0c0c3 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Wed, 9 Dec 2020 17:20:38 +0100 Subject: [PATCH 174/719] Apply suggestions from PR review Also: - Update to latest nightly --- CONTRIBUTING.md | 40 ++++++++++++++++++++-------------------- rust-toolchain | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 29cbe2a08ecf..0a3c602b9e26 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,8 +70,8 @@ But we can make it nest-less by using [if_chain] macro, [like this][nest-less]. [`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good first issue`] first. Sometimes they are only somewhat involved code wise, but not difficult per-se. -Note that [`E-medium`] issues may require some knowledge of Clippy internals or some -debugging to find the actual problem behind the issue. +Note that [`E-medium`] issues may require some knowledge of Clippy internals or some +debugging to find the actual problem behind the issue. [`T-middle`] issues can be more involved and require verifying types. The [`ty`] module contains a lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of @@ -182,7 +182,7 @@ That's why the `else_if_without_else` example uses the `register_early_pass` fun [early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html [late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html -## Syncing changes from [`rust-lang/rust`] to Clippy +## Syncing changes between Clippy and [`rust-lang/rust`] Clippy currently gets built with a pinned nightly version. @@ -190,13 +190,18 @@ In the `rust-lang/rust` repository, where rustc resides, there's a copy of Clipp that compiler hackers modify from time to time to adapt to changes in the unstable API of the compiler. -We need to sync these changes back to this repository periodically. If you want -to help with that, you have to sync the `rust-lang/rust-clippy` repository with -the `subtree` copy of Clippy in the `rust-lang/rust` repository, and update -the `rustc-toolchain` file accordingly. +We need to sync these changes back to this repository periodically, and the changes +made to this repository in the meantime also need to be synced to the `rust-lang/rust` repository. -For general information about `subtree`s in the Rust repository -see [Rust's `CONTRIBUTING.md`][subtree]. +To avoid flooding the `rust-lang/rust` PR queue, this two-way sync process is done +in a bi-weekly basis if there's no urgent changes. This is done starting on the day of +the Rust stable release and then every other week. That way we guarantee that we keep +this repo up to date with the latest compiler API, and every feature in Clippy is available +for 2 weeks in nightly, before it can get to beta. For reference, the first sync +following this cadence was performed the 2020-08-27. + +This process is described in detail in the following sections. For general information +about `subtree`s in the Rust repository see [Rust's `CONTRIBUTING.md`][subtree]. ### Patching git-subtree to work with big repos @@ -225,13 +230,14 @@ This shell has a hardcoded recursion limit set to 1000. In order to make this pr you need to force the script to run `bash` instead. You can do this by editing the first line of the `git-subtree` script and changing `sh` to `bash`. -### Performing the sync +### Performing the sync from [`rust-lang/rust`] to Clippy Here is a TL;DR version of the sync process (all of the following commands have to be run inside the `rust` directory): -1. Clone the [`rust-lang/rust`] repository -2. Sync the changes to the rust-copy of Clippy to your Clippy fork: +1. Clone the [`rust-lang/rust`] repository or make sure it is up to date. +2. Checkout the commit from the latest available nightly. You can get it using `rustup check`. +3. Sync the changes to the rust-copy of Clippy to your Clippy fork: ```bash # Make sure to change `your-github-name` to your github name in the following command git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust @@ -249,17 +255,11 @@ to be run inside the `rust` directory): git checkout sync-from-rust git merge upstream/master ``` -3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to +4. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to accelerate the process ping the `@rust-lang/clippy` team in your PR and/or ~~annoy~~ ask them in the [Zulip] stream.) - -### Syncing back changes in Clippy to [`rust-lang/rust`] -To avoid flooding the [`rust-lang/rust`] PR queue, changes in Clippy's repo are synced back -in a bi-weekly basis if there's no urgent changes. This is done starting on the day of -the Rust stable release and then every other week. That way we guarantee that -every feature in Clippy is available for 2 weeks in nightly, before it can get to beta. -For reference, the first sync following this cadence was performed the 2020-08-27. +### Performing the sync from Clippy to [`rust-lang/rust`] All of the following commands have to be run inside the `rust` directory. diff --git a/rust-toolchain b/rust-toolchain index dba3e57bcf7b..dfa7dea449a6 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2020-11-29" +channel = "nightly-2020-12-09" components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] From 77a32ebe1ead9a85ca7f0c20eb59c5b9ba8e64b4 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Wed, 9 Dec 2020 23:38:15 +0100 Subject: [PATCH 175/719] Use new cache key --- .github/workflows/clippy.yml | 2 +- .github/workflows/clippy_bors.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 181b3bab4216..abdeb96d36d1 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -52,7 +52,7 @@ jobs: uses: actions/cache@v2 with: path: ~/.cargo - key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }} + key: ${{ runner.os }}-x86_64-unknown-linux-gnu-v2-${{ hashFiles('Cargo.lock') }} restore-keys: | ${{ runner.os }}-x86_64-unknown-linux-gnu diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index f08182365fc7..c86cd32951db 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -101,7 +101,7 @@ jobs: uses: actions/cache@v2 with: path: ~/.cargo - key: ${{ runner.os }}-${{ matrix.host }}-${{ hashFiles('Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.host }}-v2-${{ hashFiles('Cargo.lock') }} restore-keys: | ${{ runner.os }}-${{ matrix.host }} @@ -183,7 +183,7 @@ jobs: uses: actions/cache@v2 with: path: ~/.cargo - key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }} + key: ${{ runner.os }}-x86_64-unknown-linux-gnu-v2-${{ hashFiles('Cargo.lock') }} restore-keys: | ${{ runner.os }}-x86_64-unknown-linux-gnu @@ -261,7 +261,7 @@ jobs: uses: actions/cache@v2 with: path: ~/.cargo - key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }} + key: ${{ runner.os }}-x86_64-unknown-linux-gnu-v2-${{ hashFiles('Cargo.lock') }} restore-keys: | ${{ runner.os }}-x86_64-unknown-linux-gnu From 20d84fdd98c16e36d0701c2b5a7f52268c54977b Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 10 Dec 2020 08:51:27 +0100 Subject: [PATCH 176/719] Enable internal lints for every test in CI --- .github/workflows/clippy.yml | 6 +++--- .github/workflows/clippy_bors.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index abdeb96d36d1..85ca63ef8c24 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -63,13 +63,13 @@ jobs: echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV - name: Build - run: cargo build --features deny-warnings + run: cargo build --features deny-warnings,internal-lints - name: Test - run: cargo test --features deny-warnings + run: cargo test --features deny-warnings,internal-lints - name: Test clippy_lints - run: cargo test --features deny-warnings + run: cargo test --features deny-warnings,internal-lints working-directory: clippy_lints - name: Test rustc_tools_util diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index c86cd32951db..3e3495c25f57 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -123,13 +123,13 @@ jobs: SYSROOT=$(rustc --print sysroot) echo "$SYSROOT/bin" >> $GITHUB_PATH - - name: Build with internal lints + - name: Build run: cargo build --features deny-warnings,internal-lints - - name: Test with internal lints + - name: Test run: cargo test --features deny-warnings,internal-lints - - name: Test clippy_lints with internal lints + - name: Test clippy_lints run: cargo test --features deny-warnings,internal-lints working-directory: clippy_lints From a891f6edfeb4d7b061a215ba160fca0e4804ffd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 10:16:29 +0100 Subject: [PATCH 177/719] Introduce the GroupBy and GroupByMut Iterators --- library/alloc/src/lib.rs | 1 + library/alloc/src/slice.rs | 2 + library/alloc/tests/lib.rs | 1 + library/alloc/tests/slice.rs | 27 +++++ library/core/src/slice/iter.rs | 180 +++++++++++++++++++++++++++++++++ library/core/src/slice/mod.rs | 68 +++++++++++++ library/core/tests/lib.rs | 1 + 7 files changed, 280 insertions(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3ac34c9ae28a..34102d9c4036 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -140,6 +140,7 @@ #![feature(try_trait)] #![feature(type_alias_impl_trait)] #![feature(associated_type_bounds)] +#![feature(slice_group_by)] // Allow testing this library #[cfg(test)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 064700fc72c9..bfa317ffd73c 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -118,6 +118,8 @@ pub use core::slice::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; +#[unstable(feature = "slice_group_by", issue = "0")] +pub use core::slice::{GroupBy, GroupByMut}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index b7cc03f8eb99..268153242c77 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -21,6 +21,7 @@ #![feature(iter_map_while)] #![feature(int_bits_const)] #![feature(vecdeque_binary_search)] +#![feature(slice_group_by)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index a4f0fb415fb3..e2fdb5a6b5a7 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1898,3 +1898,30 @@ fn subslice_patterns() { m!(&mut v, [..] => ()); m!(&mut v, [x, .., y] => c!((x, y), (&mut N, &mut N), (&mut N(0), &mut N(4)))); } + +#[test] +fn test_group_by() { + let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + + let mut iter = slice.group_by(|a, b| a == b); + + assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + + assert_eq!(iter.remaining(), &[3, 3, 2, 2, 2]); + + assert_eq!(iter.next(), Some(&[3, 3][..])); + assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next(), None); +} + +#[test] +fn test_group_by_rev() { + let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + + let mut iter = slice.group_by(|a, b| a == b); + + assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next_back(), Some(&[3, 3][..])); + assert_eq!(iter.next_back(), Some(&[1, 1, 1][..])); + assert_eq!(iter.next_back(), None); +} diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index e373936a6c74..917997f902ae 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2967,3 +2967,183 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { false } } + +macro_rules! group_by { + (struct $name:ident, $elem:ty, $mkslice:ident) => { + #[unstable(feature = "slice_group_by", issue = "0")] + impl<'a, T: 'a, P> $name<'a, T, P> { + #[inline] + fn is_empty(&self) -> bool { + self.ptr == self.end + } + + #[inline] + fn remaining_len(&self) -> usize { + unsafe { self.end.offset_from(self.ptr) as usize } + } + } + + #[unstable(feature = "slice_group_by", issue = "0")] + impl<'a, T: 'a, P> Iterator for $name<'a, T, P> + where P: FnMut(&T, &T) -> bool, + { + type Item = $elem; + + fn next(&mut self) -> Option { + // we use an unsafe block to avoid bounds checking here. + // this is safe because the only thing we do here is to get + // two elements at `ptr` and `ptr + 1`, bounds checking is done by hand. + unsafe { + if self.is_empty() { return None } + + let mut i = 0; + let mut ptr = self.ptr; + + // we need to get *two* contiguous elements so we check that: + // - the first element is at the `end - 1` position because + // - the second one will be read from `ptr + 1` that must + // be lower or equal to `end` + while ptr != self.end.sub(1) { + let a = &*ptr; + ptr = ptr.add(1); + let b = &*ptr; + + i += 1; + + if !(self.predicate)(a, b) { + let slice = $mkslice(self.ptr, i); + self.ptr = ptr; + return Some(slice) + } + } + + // `i` is either `0` or the slice `length - 1` because either: + // - we have not entered the loop and so `i` is equal to `0` + // the slice length is necessarily `1` because we ensure it is not empty + // - we have entered the loop and we have not early returned + // so `i` is equal to the slice `length - 1` + let slice = $mkslice(self.ptr, i + 1); + self.ptr = self.end; + Some(slice) + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.is_empty() { return (0, Some(0)) } + let len = self.remaining_len(); + (1, Some(len)) + } + + fn last(mut self) -> Option { + self.next_back() + } + } + + #[unstable(feature = "slice_group_by", issue = "0")] + impl<'a, T: 'a, P> DoubleEndedIterator for $name<'a, T, P> + where P: FnMut(&T, &T) -> bool, + { + fn next_back(&mut self) -> Option { + // during the loop we retrieve two elements at `ptr` and `ptr - 1`. + unsafe { + if self.is_empty() { return None } + + let mut i = 0; + // we ensure that the first element that will be read + // is not under `end` because `end` is out of bound. + let mut ptr = self.end.sub(1); + + while ptr != self.ptr { + // we first get `a` that is at the left of `ptr` + // then `b` that is under the `ptr` position. + let a = &*ptr.sub(1); + let b = &*ptr; + + i += 1; + + if !(self.predicate)(a, b) { + // the slice to return starts at the `ptr` position + // and `i` is the length of it. + let slice = $mkslice(ptr, i); + + // because `end` is always an invalid bound + // we use `ptr` as `end` for the future call to `next`. + self.end = ptr; + return Some(slice) + } + + ptr = ptr.sub(1); + } + + let slice = $mkslice(self.ptr, i + 1); + self.ptr = self.end; + Some(slice) + } + } + } + + #[unstable(feature = "slice_group_by", issue = "0")] + impl<'a, T: 'a, P> FusedIterator for $name<'a, T, P> + where P: FnMut(&T, &T) -> bool, + { } + } +} + +/// An iterator over slice in (non-overlapping) chunks separated by a predicate. +/// +/// This struct is created by the [`group_by`] method on [slices]. +/// +/// [`group_by`]: ../../std/primitive.slice.html#method.group_by +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_group_by", issue = "0")] +#[derive(Debug)] // FIXME implement Debug to be more user friendly +pub struct GroupBy<'a, T: 'a, P> { + ptr: *const T, + end: *const T, + predicate: P, + _phantom: marker::PhantomData<&'a T>, +} + +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> GroupBy<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + /// Returns the remainder of the original slice that is going to be + /// returned by the iterator. + pub fn remaining(&self) -> &[T] { + let len = self.remaining_len(); + unsafe { from_raw_parts(self.ptr, len) } + } +} + +group_by!{ struct GroupBy, &'a [T], from_raw_parts } + +/// An iterator over slice in (non-overlapping) mutable chunks separated +/// by a predicate. +/// +/// This struct is created by the [`group_by_mut`] method on [slices]. +/// +/// [`group_by_mut`]: ../../std/primitive.slice.html#method.group_by_mut +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_group_by", issue = "0")] +#[derive(Debug)] // FIXME implement Debug to be more user friendly +pub struct GroupByMut<'a, T: 'a, P> { + ptr: *mut T, + end: *mut T, + predicate: P, + _phantom: marker::PhantomData<&'a T>, +} + +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> GroupByMut<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + /// Returns the remainder of the original slice that is going to be + /// returned by the iterator. + pub fn into_remaining(self) -> &'a mut [T] { + let len = self.remaining_len(); + unsafe { from_raw_parts_mut(self.ptr, len) } + } +} + +group_by!{ struct GroupByMut, &'a mut [T], from_raw_parts_mut } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 44fe2ca88596..e366baa34c66 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1207,6 +1207,74 @@ impl [T] { RChunksExactMut::new(self, chunk_size) } + /// Returns an iterator over the slice producing non-overlapping runs + /// of elements using the predicate to separate them. + /// + /// The predicate is called on two elements following themselves, + /// it means the predicate is called on `slice[0]` and `slice[1]` + /// then on `slice[1]` and `slice[2]` and so on. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_group_by)] + /// + /// let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.group_by(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&[3, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[unstable(feature = "slice_group_by", issue = "0")] + #[inline] + pub fn group_by(&self, pred: F) -> GroupBy + where F: FnMut(&T, &T) -> bool + { + GroupBy { + ptr: self.as_ptr(), + end: unsafe { self.as_ptr().add(self.len()) }, + predicate: pred, + _phantom: marker::PhantomData, + } + } + + /// Returns an iterator over the slice producing non-overlapping mutable + /// runs of elements using the predicate to separate them. + /// + /// The predicate is called on two elements following themselves, + /// it means the predicate is called on `slice[0]` and `slice[1]` + /// then on `slice[1]` and `slice[2]` and so on. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_group_by)] + /// + /// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.group_by_mut(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&mut [3, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[unstable(feature = "slice_group_by", issue = "0")] + #[inline] + pub fn group_by_mut(&mut self, pred: F) -> GroupByMut + where F: FnMut(&T, &T) -> bool + { + GroupByMut { + ptr: self.as_mut_ptr(), + end: unsafe { self.as_mut_ptr().add(self.len()) }, + predicate: pred, + _phantom: marker::PhantomData, + } + } + /// Divides one slice into two at an index. /// /// The first will contain all indices from `[0, mid)` (excluding diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 106c9fe5da3e..1199fa4abbce 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -65,6 +65,7 @@ #![feature(nonzero_leading_trailing_zeros)] #![feature(const_option)] #![feature(integer_atomics)] +#![feature(slice_group_by)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; From 41cab83fdb9d10d620c0529bc837a3dddff5dd5f Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 10 Dec 2020 08:53:27 +0100 Subject: [PATCH 178/719] Fix toolchain installation in workflows --- .github/workflows/clippy.yml | 13 +++------- .github/workflows/clippy_bors.yml | 40 ++++++++----------------------- .github/workflows/clippy_dev.yml | 10 +++++--- 3 files changed, 20 insertions(+), 43 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 85ca63ef8c24..89be0e741aa3 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -35,18 +35,11 @@ jobs: with: github_token: "${{ secrets.github_token }}" - - name: rust-toolchain - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: nightly - target: x86_64-unknown-linux-gnu - profile: minimal - - name: Checkout uses: actions/checkout@v2.3.3 - - name: Run cargo update - run: cargo update + - name: Install toolchain + run: rustup show active-toolchain - name: Cache cargo dir uses: actions/cache@v2 @@ -99,5 +92,5 @@ jobs: # Cleanup - name: Run cargo-cache --autoclean run: | - cargo +nightly install cargo-cache --no-default-features --features ci-autoclean cargo-cache + cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache cargo cache diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 3e3495c25f57..af5ddc022d4a 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -23,6 +23,7 @@ jobs: - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master with: github_token: "${{ secrets.github_token }}" + - name: Checkout uses: actions/checkout@v2.3.3 with: @@ -84,18 +85,11 @@ jobs: sudo apt-get install gcc-multilib libssl-dev:i386 libgit2-dev:i386 if: matrix.host == 'i686-unknown-linux-gnu' - - name: rust-toolchain - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: nightly - target: ${{ matrix.host }} - profile: minimal - - name: Checkout uses: actions/checkout@v2.3.3 - - name: Run cargo update - run: cargo update + - name: Install toolchain + run: rustup show active-toolchain - name: Cache cargo dir uses: actions/cache@v2 @@ -153,7 +147,7 @@ jobs: # Cleanup - name: Run cargo-cache --autoclean run: | - cargo +nightly install cargo-cache --no-default-features --features ci-autoclean cargo-cache + cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache cargo cache integration_build: @@ -166,18 +160,11 @@ jobs: with: github_token: "${{ secrets.github_token }}" - - name: rust-toolchain - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: nightly - target: x86_64-unknown-linux-gnu - profile: minimal - - name: Checkout uses: actions/checkout@v2.3.3 - - name: Run cargo update - run: cargo update + - name: Install toolchain + run: rustup show active-toolchain - name: Cache cargo dir uses: actions/cache@v2 @@ -209,7 +196,7 @@ jobs: # Cleanup - name: Run cargo-cache --autoclean run: | - cargo +nightly install cargo-cache --no-default-features --features ci-autoclean cargo-cache + cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache cargo cache integration: needs: integration_build @@ -244,18 +231,11 @@ jobs: with: github_token: "${{ secrets.github_token }}" - - name: rust-toolchain - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: nightly - target: x86_64-unknown-linux-gnu - profile: minimal - - name: Checkout uses: actions/checkout@v2.3.3 - - name: Run cargo update - run: cargo update + - name: Install toolchain + run: rustup show active-toolchain - name: Cache cargo dir uses: actions/cache@v2 @@ -285,7 +265,7 @@ jobs: # Cleanup - name: Run cargo-cache --autoclean run: | - cargo +nightly install cargo-cache --no-default-features --features ci-autoclean cargo-cache + cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache cargo cache # These jobs doesn't actually test anything, but they're only used to tell diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml index 5ee157cf23b8..95da775b7bc3 100644 --- a/.github/workflows/clippy_dev.yml +++ b/.github/workflows/clippy_dev.yml @@ -22,6 +22,12 @@ jobs: steps: # Setup + - name: Checkout + uses: actions/checkout@v2.3.3 + + - name: remove toolchain file + run: rm rust-toolchain + - name: rust-toolchain uses: actions-rs/toolchain@v1.0.6 with: @@ -29,9 +35,7 @@ jobs: target: x86_64-unknown-linux-gnu profile: minimal components: rustfmt - - - name: Checkout - uses: actions/checkout@v2.3.3 + default: true # Run - name: Build From 26dcbf5523fb95c2490862af37c7279244f9a912 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 10 Dec 2020 09:36:19 +0100 Subject: [PATCH 179/719] Stop caching on CI The only thing we now cache is cargo-cache, which we only use for cache. That's a catch-22 if I ever seen one. And for Clippy itself we always want to do a clean build and not cache anything. --- .github/workflows/clippy.yml | 14 ----------- .github/workflows/clippy_bors.yml | 41 ------------------------------- 2 files changed, 55 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 89be0e741aa3..530e60001f72 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -41,14 +41,6 @@ jobs: - name: Install toolchain run: rustup show active-toolchain - - name: Cache cargo dir - uses: actions/cache@v2 - with: - path: ~/.cargo - key: ${{ runner.os }}-x86_64-unknown-linux-gnu-v2-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-x86_64-unknown-linux-gnu - # Run - name: Set LD_LIBRARY_PATH (Linux) run: | @@ -88,9 +80,3 @@ jobs: cargo dev new_lint --name new_late_pass --pass late cargo check git reset --hard HEAD - - # Cleanup - - name: Run cargo-cache --autoclean - run: | - cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache - cargo cache diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index af5ddc022d4a..ae31534b71c2 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -91,14 +91,6 @@ jobs: - name: Install toolchain run: rustup show active-toolchain - - name: Cache cargo dir - uses: actions/cache@v2 - with: - path: ~/.cargo - key: ${{ runner.os }}-${{ matrix.host }}-v2-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.host }} - # Run - name: Set LD_LIBRARY_PATH (Linux) if: runner.os == 'Linux' @@ -144,12 +136,6 @@ jobs: env: OS: ${{ runner.os }} - # Cleanup - - name: Run cargo-cache --autoclean - run: | - cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache - cargo cache - integration_build: needs: changelog runs-on: ubuntu-latest @@ -166,14 +152,6 @@ jobs: - name: Install toolchain run: rustup show active-toolchain - - name: Cache cargo dir - uses: actions/cache@v2 - with: - path: ~/.cargo - key: ${{ runner.os }}-x86_64-unknown-linux-gnu-v2-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-x86_64-unknown-linux-gnu - # Run - name: Build Integration Test run: cargo test --test integration --features integration --no-run @@ -193,11 +171,6 @@ jobs: name: target path: target - # Cleanup - - name: Run cargo-cache --autoclean - run: | - cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache - cargo cache integration: needs: integration_build strategy: @@ -237,14 +210,6 @@ jobs: - name: Install toolchain run: rustup show active-toolchain - - name: Cache cargo dir - uses: actions/cache@v2 - with: - path: ~/.cargo - key: ${{ runner.os }}-x86_64-unknown-linux-gnu-v2-${{ hashFiles('Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-x86_64-unknown-linux-gnu - # Download - name: Download target dir uses: actions/download-artifact@v1 @@ -262,12 +227,6 @@ jobs: INTEGRATION: ${{ matrix.integration }} RUSTUP_TOOLCHAIN: master - # Cleanup - - name: Run cargo-cache --autoclean - run: | - cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache - cargo cache - # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a # workflow is successful listening to webhooks only. From 594b451ccc65329a3f5e60f5b6690bcd0f7e9e7b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Dec 2020 11:07:39 +0100 Subject: [PATCH 180/719] Windows TLS: ManuallyDrop instead of mem::forget --- library/std/src/sys/windows/thread_local_key.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/windows/thread_local_key.rs b/library/std/src/sys/windows/thread_local_key.rs index fb2bb0613ee8..065365e5572f 100644 --- a/library/std/src/sys/windows/thread_local_key.rs +++ b/library/std/src/sys/windows/thread_local_key.rs @@ -1,4 +1,4 @@ -use crate::mem; +use crate::mem::ManuallyDrop; use crate::ptr; use crate::sync::atomic::AtomicPtr; use crate::sync::atomic::Ordering::SeqCst; @@ -111,16 +111,13 @@ struct Node { } unsafe fn register_dtor(key: Key, dtor: Dtor) { - let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() }); + let mut node = ManuallyDrop::new(Box::new(Node { key, dtor, next: ptr::null_mut() })); let mut head = DTORS.load(SeqCst); loop { node.next = head; - match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) { - Ok(_) => { - mem::forget(node); - return; - } + match DTORS.compare_exchange(head, &mut **node, SeqCst, SeqCst) { + Ok(_) => return, // nothing to drop, we successfully added the node to the list Err(cur) => head = cur, } } From 1c55a73b750bcae1bbf05cbafbd36bce8bd993fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:17:41 +0100 Subject: [PATCH 181/719] Implement it with only safe code --- library/alloc/tests/slice.rs | 39 ++++-- library/core/src/slice/iter.rs | 246 ++++++++++++++------------------- library/core/src/slice/mod.rs | 14 +- 3 files changed, 132 insertions(+), 167 deletions(-) diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index e2fdb5a6b5a7..8f03a9240e28 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1904,24 +1904,43 @@ fn test_group_by() { let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; let mut iter = slice.group_by(|a, b| a == b); - assert_eq!(iter.next(), Some(&[1, 1, 1][..])); - - assert_eq!(iter.remaining(), &[3, 3, 2, 2, 2]); - assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next(), None); -} - -#[test] -fn test_group_by_rev() { - let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; let mut iter = slice.group_by(|a, b| a == b); - assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); assert_eq!(iter.next_back(), Some(&[3, 3][..])); assert_eq!(iter.next_back(), Some(&[1, 1, 1][..])); assert_eq!(iter.next_back(), None); + + let mut iter = slice.group_by(|a, b| a == b); + assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next(), Some(&[3, 3][..])); + assert_eq!(iter.next_back(), None); +} + +#[test] +fn test_group_by_mut() { + let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; + + let mut iter = slice.group_by_mut(|a, b| a == b); + assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); + assert_eq!(iter.next(), Some(&mut [3, 3][..])); + assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); + assert_eq!(iter.next(), None); + + let mut iter = slice.group_by_mut(|a, b| a == b); + assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); + assert_eq!(iter.next_back(), Some(&mut [3, 3][..])); + assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..])); + assert_eq!(iter.next_back(), None); + + let mut iter = slice.group_by_mut(|a, b| a == b); + assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); + assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); + assert_eq!(iter.next(), Some(&mut [3, 3][..])); + assert_eq!(iter.next_back(), None); } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 917997f902ae..8f52fa852ba9 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2968,127 +2968,6 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { } } -macro_rules! group_by { - (struct $name:ident, $elem:ty, $mkslice:ident) => { - #[unstable(feature = "slice_group_by", issue = "0")] - impl<'a, T: 'a, P> $name<'a, T, P> { - #[inline] - fn is_empty(&self) -> bool { - self.ptr == self.end - } - - #[inline] - fn remaining_len(&self) -> usize { - unsafe { self.end.offset_from(self.ptr) as usize } - } - } - - #[unstable(feature = "slice_group_by", issue = "0")] - impl<'a, T: 'a, P> Iterator for $name<'a, T, P> - where P: FnMut(&T, &T) -> bool, - { - type Item = $elem; - - fn next(&mut self) -> Option { - // we use an unsafe block to avoid bounds checking here. - // this is safe because the only thing we do here is to get - // two elements at `ptr` and `ptr + 1`, bounds checking is done by hand. - unsafe { - if self.is_empty() { return None } - - let mut i = 0; - let mut ptr = self.ptr; - - // we need to get *two* contiguous elements so we check that: - // - the first element is at the `end - 1` position because - // - the second one will be read from `ptr + 1` that must - // be lower or equal to `end` - while ptr != self.end.sub(1) { - let a = &*ptr; - ptr = ptr.add(1); - let b = &*ptr; - - i += 1; - - if !(self.predicate)(a, b) { - let slice = $mkslice(self.ptr, i); - self.ptr = ptr; - return Some(slice) - } - } - - // `i` is either `0` or the slice `length - 1` because either: - // - we have not entered the loop and so `i` is equal to `0` - // the slice length is necessarily `1` because we ensure it is not empty - // - we have entered the loop and we have not early returned - // so `i` is equal to the slice `length - 1` - let slice = $mkslice(self.ptr, i + 1); - self.ptr = self.end; - Some(slice) - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.is_empty() { return (0, Some(0)) } - let len = self.remaining_len(); - (1, Some(len)) - } - - fn last(mut self) -> Option { - self.next_back() - } - } - - #[unstable(feature = "slice_group_by", issue = "0")] - impl<'a, T: 'a, P> DoubleEndedIterator for $name<'a, T, P> - where P: FnMut(&T, &T) -> bool, - { - fn next_back(&mut self) -> Option { - // during the loop we retrieve two elements at `ptr` and `ptr - 1`. - unsafe { - if self.is_empty() { return None } - - let mut i = 0; - // we ensure that the first element that will be read - // is not under `end` because `end` is out of bound. - let mut ptr = self.end.sub(1); - - while ptr != self.ptr { - // we first get `a` that is at the left of `ptr` - // then `b` that is under the `ptr` position. - let a = &*ptr.sub(1); - let b = &*ptr; - - i += 1; - - if !(self.predicate)(a, b) { - // the slice to return starts at the `ptr` position - // and `i` is the length of it. - let slice = $mkslice(ptr, i); - - // because `end` is always an invalid bound - // we use `ptr` as `end` for the future call to `next`. - self.end = ptr; - return Some(slice) - } - - ptr = ptr.sub(1); - } - - let slice = $mkslice(self.ptr, i + 1); - self.ptr = self.end; - Some(slice) - } - } - } - - #[unstable(feature = "slice_group_by", issue = "0")] - impl<'a, T: 'a, P> FusedIterator for $name<'a, T, P> - where P: FnMut(&T, &T) -> bool, - { } - } -} - /// An iterator over slice in (non-overlapping) chunks separated by a predicate. /// /// This struct is created by the [`group_by`] method on [slices]. @@ -3098,25 +2977,65 @@ macro_rules! group_by { #[unstable(feature = "slice_group_by", issue = "0")] #[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupBy<'a, T: 'a, P> { - ptr: *const T, - end: *const T, + slice: &'a [T], predicate: P, - _phantom: marker::PhantomData<&'a T>, } #[unstable(feature = "slice_group_by", issue = "0")] -impl<'a, T: 'a, P> GroupBy<'a, T, P> -where P: FnMut(&T, &T) -> bool, -{ - /// Returns the remainder of the original slice that is going to be - /// returned by the iterator. - pub fn remaining(&self) -> &[T] { - let len = self.remaining_len(); - unsafe { from_raw_parts(self.ptr, len) } +impl<'a, T: 'a, P> GroupBy<'a, T, P> { + pub(super) fn new(slice: &'a [T], predicate: P) -> Self { + GroupBy { slice, predicate } } } -group_by!{ struct GroupBy, &'a [T], from_raw_parts } +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option { + if self.slice.is_empty() { + None + } else { + let mut len = 1; + let mut iter = self.slice.windows(2); + while let Some([l, r]) = iter.next() { + if (self.predicate)(l, r) { len += 1 } else { break } + } + let (head, tail) = self.slice.split_at(len); + self.slice = tail; + Some(head) + } + } +} + +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option { + if self.slice.is_empty() { + None + } else { + let mut len = 1; + let mut iter = self.slice.windows(2); + while let Some([l, r]) = iter.next_back() { + if (self.predicate)(l, r) { len += 1 } else { break } + } + let (head, tail) = self.slice.split_at(self.slice.len() - len); + self.slice = head; + Some(tail) + } + } +} + +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ } /// An iterator over slice in (non-overlapping) mutable chunks separated /// by a predicate. @@ -3128,22 +3047,59 @@ group_by!{ struct GroupBy, &'a [T], from_raw_parts } #[unstable(feature = "slice_group_by", issue = "0")] #[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupByMut<'a, T: 'a, P> { - ptr: *mut T, - end: *mut T, + slice: &'a mut [T], predicate: P, - _phantom: marker::PhantomData<&'a T>, } #[unstable(feature = "slice_group_by", issue = "0")] -impl<'a, T: 'a, P> GroupByMut<'a, T, P> -where P: FnMut(&T, &T) -> bool, -{ - /// Returns the remainder of the original slice that is going to be - /// returned by the iterator. - pub fn into_remaining(self) -> &'a mut [T] { - let len = self.remaining_len(); - unsafe { from_raw_parts_mut(self.ptr, len) } +impl<'a, T: 'a, P> GroupByMut<'a, T, P> { + pub(super) fn new(slice: &'a mut [T], predicate: P) -> Self { + GroupByMut { slice, predicate } } } -group_by!{ struct GroupByMut, &'a mut [T], from_raw_parts_mut } +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option { + if self.slice.is_empty() { + None + } else { + let mut len = 1; + let mut iter = self.slice.windows(2); + while let Some([l, r]) = iter.next() { + if (self.predicate)(l, r) { len += 1 } else { break } + } + let slice = mem::take(&mut self.slice); + let (head, tail) = slice.split_at_mut(len); + self.slice = tail; + Some(head) + } + } +} + +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option { + if self.slice.is_empty() { + None + } else { + let mut len = 1; + let mut iter = self.slice.windows(2); + while let Some([l, r]) = iter.next_back() { + if (self.predicate)(l, r) { len += 1 } else { break } + } + let slice = mem::take(&mut self.slice); + let (head, tail) = slice.split_at_mut(slice.len() - len); + self.slice = head; + Some(tail) + } + } +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e366baa34c66..2e304cc5d2ea 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1233,12 +1233,7 @@ impl [T] { pub fn group_by(&self, pred: F) -> GroupBy where F: FnMut(&T, &T) -> bool { - GroupBy { - ptr: self.as_ptr(), - end: unsafe { self.as_ptr().add(self.len()) }, - predicate: pred, - _phantom: marker::PhantomData, - } + GroupBy::new(self, pred) } /// Returns an iterator over the slice producing non-overlapping mutable @@ -1267,12 +1262,7 @@ impl [T] { pub fn group_by_mut(&mut self, pred: F) -> GroupByMut where F: FnMut(&T, &T) -> bool { - GroupByMut { - ptr: self.as_mut_ptr(), - end: unsafe { self.as_mut_ptr().add(self.len()) }, - predicate: pred, - _phantom: marker::PhantomData, - } + GroupByMut::new(self, pred) } /// Divides one slice into two at an index. From e16eaeaa11c4119543bfcb5e61f74fcde780727a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:22:20 +0100 Subject: [PATCH 182/719] Implement size_hint on the GroupBy and GroupByMut Iterators --- library/core/src/slice/iter.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 8f52fa852ba9..730009568dd3 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3009,6 +3009,15 @@ where P: FnMut(&T, &T) -> bool, Some(head) } } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.slice.is_empty() { + (0, Some(0)) + } else { + (1, Some(self.slice.len())) + } + } } #[unstable(feature = "slice_group_by", issue = "0")] @@ -3080,6 +3089,15 @@ where P: FnMut(&T, &T) -> bool, Some(head) } } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.slice.is_empty() { + (0, Some(0)) + } else { + (1, Some(self.slice.len())) + } + } } #[unstable(feature = "slice_group_by", issue = "0")] From 005912fce87700c5aee6185701e9c2aea3f216d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:22:29 +0100 Subject: [PATCH 183/719] Implement last on the GroupBy and GroupByMut Iterators --- library/core/src/slice/iter.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 730009568dd3..90afd00f21db 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3018,6 +3018,11 @@ where P: FnMut(&T, &T) -> bool, (1, Some(self.slice.len())) } } + + #[inline] + fn last(self) -> Option { + self.next_back() + } } #[unstable(feature = "slice_group_by", issue = "0")] @@ -3098,6 +3103,11 @@ where P: FnMut(&T, &T) -> bool, (1, Some(self.slice.len())) } } + + #[inline] + fn last(self) -> Option { + self.next_back() + } } #[unstable(feature = "slice_group_by", issue = "0")] From 1b406afe23c17467f43a5c1bd83b4af1d55d08d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:37:40 +0100 Subject: [PATCH 184/719] Use none as the issue instead of 0 --- library/alloc/src/slice.rs | 2 +- library/core/src/slice/iter.rs | 18 +++++++++--------- library/core/src/slice/mod.rs | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index bfa317ffd73c..5f92dfe539fb 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -118,7 +118,7 @@ pub use core::slice::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] pub use core::slice::{GroupBy, GroupByMut}; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 90afd00f21db..9053376bdf24 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2974,21 +2974,21 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { /// /// [`group_by`]: ../../std/primitive.slice.html#method.group_by /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] #[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupBy<'a, T: 'a, P> { slice: &'a [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> GroupBy<'a, T, P> { pub(super) fn new(slice: &'a [T], predicate: P) -> Self { GroupBy { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3025,7 +3025,7 @@ where P: FnMut(&T, &T) -> bool, } } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3046,7 +3046,7 @@ where P: FnMut(&T, &T) -> bool, } } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { } @@ -3058,21 +3058,21 @@ where P: FnMut(&T, &T) -> bool, /// /// [`group_by_mut`]: ../../std/primitive.slice.html#method.group_by_mut /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] #[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupByMut<'a, T: 'a, P> { slice: &'a mut [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> GroupByMut<'a, T, P> { pub(super) fn new(slice: &'a mut [T], predicate: P) -> Self { GroupByMut { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3110,7 +3110,7 @@ where P: FnMut(&T, &T) -> bool, } } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 2e304cc5d2ea..40f480fa85be 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1228,7 +1228,7 @@ impl [T] { /// assert_eq!(iter.next(), Some(&[2, 2, 2][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "0")] + #[unstable(feature = "slice_group_by", issue = "none")] #[inline] pub fn group_by(&self, pred: F) -> GroupBy where F: FnMut(&T, &T) -> bool @@ -1257,7 +1257,7 @@ impl [T] { /// assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "0")] + #[unstable(feature = "slice_group_by", issue = "none")] #[inline] pub fn group_by_mut(&mut self, pred: F) -> GroupByMut where F: FnMut(&T, &T) -> bool From 2363a20b9868ae41ac92cac4b06c167c3cb320aa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Dec 2020 11:38:12 +0100 Subject: [PATCH 185/719] Make search results tab and help button focusable with keyboard --- src/librustdoc/html/layout.rs | 2 +- src/librustdoc/html/static/main.js | 6 +++--- src/librustdoc/html/static/rustdoc.css | 11 ++++++----- src/librustdoc/html/static/themes/ayu.css | 10 +++++----- src/librustdoc/html/static/themes/dark.css | 7 ++++--- src/librustdoc/html/static/themes/light.css | 7 ++++--- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index e8039942f4f8..f2c74c46d7db 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -98,7 +98,7 @@ crate fn render( placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \ type=\"search\">\ \ - ? + \ " + text + - "
(" + nbElems + ")
"; + return ""; } - return "
" + text + "
(" + nbElems + ")
"; + return ""; } function showResults(results) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 8eef65a231d0..61905b8eca8b 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1176,21 +1176,22 @@ pre.rust { height: 35px; } -#titles > div { +#titles > button { float: left; width: 33.3%; text-align: center; font-size: 18px; cursor: pointer; + border: 0; border-top: 2px solid; } -#titles > div:not(:last-child) { +#titles > button:not(:last-child) { margin-right: 1px; width: calc(33.3% - 1px); } -#titles > div > div.count { +#titles > button > div.count { display: inline-block; font-size: 16px; } @@ -1459,7 +1460,7 @@ h4 > .notable-traits { top: 24px; } - #titles > div > div.count { + #titles > button > div.count { float: left; width: 100%; } @@ -1565,7 +1566,7 @@ h4 > .notable-traits { } @media (max-width: 416px) { - #titles, #titles > div { + #titles, #titles > button { height: 73px; } diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index c1f796f09e80..76bbe4f62019 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -403,22 +403,22 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: #5c6773; } -#titles > div.selected { +#titles > button.selected { background-color: #141920 !important; border-bottom: 1px solid #ffb44c !important; border-top: none; } -#titles > div:not(.selected) { +#titles > button:not(.selected) { background-color: transparent !important; border: none; } -#titles > div:hover { +#titles > button:hover { border-bottom: 1px solid rgba(242, 151, 24, 0.3); } -#titles > div > div.count { +#titles > button > div.count { color: #888; } @@ -434,7 +434,7 @@ above the `@media (max-width: 700px)` rules due to a bug in the css checker */ .block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {} .content .highlighted.trait {} .content span.struct,.content a.struct,.block a.current.struct {} -#titles>div:hover,#titles>div.selected {} +#titles>button:hover,#titles>button.selected {} .content .highlighted.traitalias {} .content span.type,.content a.type,.block a.current.type {} .content span.union,.content a.union,.block a.current.union {} diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 946ca0a40c9d..86ce99284eba 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -352,16 +352,17 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: #777; } -#titles > div:not(.selected) { +#titles > button:not(.selected) { background-color: #252525; border-top-color: #252525; } -#titles > div:hover, #titles > div.selected { +#titles > button:hover, #titles > button.selected { border-top-color: #0089ff; + background-color: #353535; } -#titles > div > div.count { +#titles > button > div.count { color: #888; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index e0b9a04921a8..52cfdf6f7a38 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -343,16 +343,17 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: #999; } -#titles > div:not(.selected) { +#titles > button:not(.selected) { background-color: #e6e6e6; border-top-color: #e6e6e6; } -#titles > div:hover, #titles > div.selected { +#titles > button:hover, #titles > button.selected { border-top-color: #0089ff; + background-color: #353535; } -#titles > div > div.count { +#titles > button > div.count { color: #888; } From 0ebf8e13f096c5e68f1e436c8f039642e90c8a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:41:43 +0100 Subject: [PATCH 186/719] Import the GroupBy and GroupByMut in the slice module --- library/core/src/slice/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 40f480fa85be..9d51a4779cff 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -57,6 +57,9 @@ pub use iter::{ArrayChunks, ArrayChunksMut}; #[unstable(feature = "array_windows", issue = "75027")] pub use iter::ArrayWindows; +#[unstable(feature = "slice_group_by", issue = "none")] +pub use iter::{GroupBy, GroupByMut}; + #[unstable(feature = "split_inclusive", issue = "72360")] pub use iter::{SplitInclusive, SplitInclusiveMut}; From 6a5a60048d98e0d0c545703ff5a9ba39beef49a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:47:15 +0100 Subject: [PATCH 187/719] Indicate the anonymous lifetime of the GroupBy and GroupByMut --- library/core/src/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 9d51a4779cff..218cd2c25a29 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1233,7 +1233,7 @@ impl [T] { /// ``` #[unstable(feature = "slice_group_by", issue = "none")] #[inline] - pub fn group_by(&self, pred: F) -> GroupBy + pub fn group_by(&self, pred: F) -> GroupBy<'_, T, F> where F: FnMut(&T, &T) -> bool { GroupBy::new(self, pred) @@ -1262,7 +1262,7 @@ impl [T] { /// ``` #[unstable(feature = "slice_group_by", issue = "none")] #[inline] - pub fn group_by_mut(&mut self, pred: F) -> GroupByMut + pub fn group_by_mut(&mut self, pred: F) -> GroupByMut<'_, T, F> where F: FnMut(&T, &T) -> bool { GroupByMut::new(self, pred) From 5190fe4979f90b2912aed5a2cf9b77e3dcfb1a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:58:52 +0100 Subject: [PATCH 188/719] Mark the Iterator last self parameter as mut --- library/core/src/slice/iter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 9053376bdf24..71106c66f125 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3020,7 +3020,7 @@ where P: FnMut(&T, &T) -> bool, } #[inline] - fn last(self) -> Option { + fn last(mut self) -> Option { self.next_back() } } @@ -3105,7 +3105,7 @@ where P: FnMut(&T, &T) -> bool, } #[inline] - fn last(self) -> Option { + fn last(mut self) -> Option { self.next_back() } } From 718fba92b0f319a271265df53fd0221447897311 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 10 Dec 2020 13:24:47 +0200 Subject: [PATCH 189/719] tests: codegen/transmute-scalar needs optimizations enabled. --- src/test/codegen/transmute-scalar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/codegen/transmute-scalar.rs b/src/test/codegen/transmute-scalar.rs index f16335fdc74f..78b4aa3fb885 100644 --- a/src/test/codegen/transmute-scalar.rs +++ b/src/test/codegen/transmute-scalar.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -O -C no-prepopulate-passes #![crate_type = "lib"] From 3f41fe2704e331399568890f41874c2fc086e838 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 10 Dec 2020 10:44:33 +0100 Subject: [PATCH 190/719] Error in integration test, if required toolchain is not installed --- tests/integration.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration.rs b/tests/integration.rs index a78273ce0da4..1718089e8bd2 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -72,6 +72,8 @@ fn integration_test() { panic!("incompatible crate versions"); } else if stderr.contains("failed to run `rustc` to learn about target-specific information") { panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`"); + } else if stderr.contains("toolchain") && stderr.contains("is not installed") { + panic!("missing required toolchain"); } match output.status.code() { From 836325e9d9530114b296f73306c03318d8a52c0a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 10 Dec 2020 11:00:05 +0100 Subject: [PATCH 191/719] Fix integration test runner --- .github/workflows/clippy_bors.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index ae31534b71c2..5d846eb64c78 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -222,10 +222,11 @@ jobs: # Run - name: Test ${{ matrix.integration }} - run: $CARGO_TARGET_DIR/debug/integration + run: | + RUSTUP_TOOLCHAIN="$(rustup show active-toolchain | grep -o -E "nightly-[0-9]{4}-[0-9]{2}-[0-9]{2}")" \ + $CARGO_TARGET_DIR/debug/integration env: INTEGRATION: ${{ matrix.integration }} - RUSTUP_TOOLCHAIN: master # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a From 9940c47885df3d6873aab9a78a7725cb41e8d957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 13:42:31 +0100 Subject: [PATCH 192/719] Update the slice GroupBy/Mut test --- library/alloc/tests/slice.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 8f03a9240e28..777c10b1bf74 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1901,15 +1901,19 @@ fn subslice_patterns() { #[test] fn test_group_by() { - let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + let slice = &[1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; let mut iter = slice.group_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next(), Some(&[1][..])); + assert_eq!(iter.next(), Some(&[0][..])); assert_eq!(iter.next(), None); let mut iter = slice.group_by(|a, b| a == b); + assert_eq!(iter.next_back(), Some(&[0][..])); + assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); assert_eq!(iter.next_back(), Some(&[3, 3][..])); assert_eq!(iter.next_back(), Some(&[1, 1, 1][..])); @@ -1917,22 +1921,28 @@ fn test_group_by() { let mut iter = slice.group_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); - assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next_back(), Some(&[0][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); + assert_eq!(iter.next_back(), Some(&[1][..])); + assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next_back(), None); } #[test] fn test_group_by_mut() { - let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; + let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; let mut iter = slice.group_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); + assert_eq!(iter.next(), Some(&mut [1][..])); + assert_eq!(iter.next(), Some(&mut [0][..])); assert_eq!(iter.next(), None); let mut iter = slice.group_by_mut(|a, b| a == b); + assert_eq!(iter.next_back(), Some(&mut [0][..])); + assert_eq!(iter.next_back(), Some(&mut [1][..])); assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); assert_eq!(iter.next_back(), Some(&mut [3, 3][..])); assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..])); @@ -1940,7 +1950,9 @@ fn test_group_by_mut() { let mut iter = slice.group_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); - assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); + assert_eq!(iter.next_back(), Some(&mut [0][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); + assert_eq!(iter.next_back(), Some(&mut [1][..])); + assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); assert_eq!(iter.next_back(), None); } From caab16fa20c582f1c7e39f835286482eaa51710a Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Thu, 10 Dec 2020 01:03:44 +0900 Subject: [PATCH 193/719] Update const-fn doc in unstable-book Update src/doc/unstable-book/src/language-features/const-fn.md Co-authored-by: Ivan Tham --- .../src/language-features/const-fn.md | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/const-fn.md b/src/doc/unstable-book/src/language-features/const-fn.md index 50dbbaf56743..bcf7f78b8fe0 100644 --- a/src/doc/unstable-book/src/language-features/const-fn.md +++ b/src/doc/unstable-book/src/language-features/const-fn.md @@ -6,24 +6,5 @@ The tracking issue for this feature is: [#57563] ------------------------ -The `const_fn` feature allows marking free functions and inherent methods as -`const`, enabling them to be called in constants contexts, with constant -arguments. - -## Examples - -```rust -#![feature(const_fn)] - -const fn double(x: i32) -> i32 { - x * 2 -} - -const FIVE: i32 = 5; -const TEN: i32 = double(FIVE); - -fn main() { - assert_eq!(5, FIVE); - assert_eq!(10, TEN); -} -``` +The `const_fn` feature enables additional functionality not stabilized in the +[minimal subset of `const_fn`](https://github.com/rust-lang/rust/issues/53555) From fb75c329c568e610e5251f7419f10a9a639f3d42 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 29 Nov 2020 15:22:36 +0000 Subject: [PATCH 194/719] ci: use 20.04 on x86_64-gnu-nopt builder This commit switches the x86_64-gnu-nopt builder to use Ubuntu 20.04, which contains a more recent gdb version than Ubuntu 16.04 (newer gdb versions fix a bug that Split DWARF can trigger, see rust-lang/rust#77177 for motivation). x86_64-gnu-nopt is chosen because it runs compare modes, which is how Split DWARF testing is implemented in rust-lang/rust#77177. Signed-off-by: David Wood --- src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile index f4071961f8e1..77510d7ac62d 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile @@ -1,6 +1,7 @@ -FROM ubuntu:16.04 +FROM ubuntu:20.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ +# Avoid interactive prompts while installing `tzdata` dependency with `DEBIAN_FRONTEND`. +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ g++ \ make \ ninja-build \ From a6bb9276f7964b96899d04d680bc04bf99c8bf47 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 9 Nov 2020 23:38:08 +0100 Subject: [PATCH 195/719] Lint wrong self convention in trait also --- clippy_lints/src/methods/mod.rs | 49 +++++++++++++++++++++++---- tests/ui/wrong_self_convention.rs | 26 ++++++++++++++ tests/ui/wrong_self_convention.stderr | 34 ++++++++++++++++++- 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8002c27a5e91..3c89c1b6ed2c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -22,6 +22,7 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; +use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; @@ -1623,10 +1624,15 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let item = cx.tcx.hir().expect_item(parent); let def_id = cx.tcx.hir().local_def_id(item.hir_id); let self_ty = cx.tcx.type_of(def_id); + + // if this impl block implements a trait, lint in trait definition instead + if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind { + return; + } + if_chain! { if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind; if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next(); - if let hir::ItemKind::Impl{ of_trait: None, .. } = item.kind; let method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id); let method_sig = cx.tcx.fn_sig(method_def_id); @@ -1697,11 +1703,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - // if this impl block implements a trait, lint in trait definition instead - if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind { - return; - } - if let hir::ImplItemKind::Fn(_, _) = impl_item.kind { let ret_ty = return_ty(cx, impl_item.hir_id); @@ -1735,8 +1736,42 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if in_external_macro(cx.tcx.sess, item.span) { + return; + } + + if_chain! { + if let TraitItemKind::Fn(ref sig, _) = item.kind; + if let Some(first_arg_ty) = sig.decl.inputs.iter().next(); + let first_arg_span = first_arg_ty.span; + let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); + let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty(); + + then { + if let Some((ref conv, self_kinds)) = &CONVENTIONS + .iter() + .find(|(ref conv, _)| conv.check(&item.ident.name.as_str())) + { + if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { + span_lint( + cx, + WRONG_PUB_SELF_CONVENTION, + first_arg_span, + &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name", + conv, + &self_kinds + .iter() + .map(|k| k.description()) + .collect::>() + .join(" or ") + ), + ); + } + } + } + } + if_chain! { - if !in_external_macro(cx.tcx.sess, item.span); if item.ident.name == sym::new; if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id); diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index f44305d7e483..275866b8248f 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -88,3 +88,29 @@ mod issue4037 { } } } + +// Lint also in trait definition (see #6307) +mod issue6307{ + trait T: Sized { + fn as_i32(self) {} + fn as_u32(&self) {} + fn into_i32(&self) {} + fn into_u32(self) {} + fn is_i32(self) {} + fn is_u32(&self) {} + fn to_i32(self) {} + fn to_u32(&self) {} + fn from_i32(self) {} + // check whether the lint can be allowed at the function level + #[allow(clippy::wrong_pub_self_convention)] + fn from_cake(self) {} + + // test for false positives + fn as_(self) {} + fn into_(&self) {} + fn is_(self) {} + fn to_(self) {} + fn from_(self) {} + fn to_mut(&mut self) {} + } +} \ No newline at end of file diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index ef3ad73ebc7c..64aa957fed6a 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -72,5 +72,37 @@ error: methods called `from_*` usually take no self; consider choosing a less am LL | pub fn from_i64(self) {} | ^^^^ -error: aborting due to 12 previous errors +error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:95:19 + | +LL | fn as_i32(self) {} + | ^^^^ + | + = note: `-D clippy::wrong-pub-self-convention` implied by `-D warnings` + +error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:97:21 + | +LL | fn into_i32(&self) {} + | ^^^^^ + +error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:99:19 + | +LL | fn is_i32(self) {} + | ^^^^ + +error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:101:19 + | +LL | fn to_i32(self) {} + | ^^^^ + +error: methods called `from_*` usually take no self; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:103:21 + | +LL | fn from_i32(self) {} + | ^^^^ + +error: aborting due to 17 previous errors From 4af9382bec3f49d9c7e0f03e9cfb5e8f1c70fdbe Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 10 Nov 2020 08:56:17 +0100 Subject: [PATCH 196/719] Common function to lint wrong self convention from impl and trait def --- clippy_lints/src/methods/mod.rs | 88 +++++++++++++-------------- tests/ui/wrong_self_convention.rs | 6 +- tests/ui/wrong_self_convention.stderr | 2 - 3 files changed, 45 insertions(+), 51 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3c89c1b6ed2c..9a082a89229b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1674,32 +1674,14 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - if let Some((ref conv, self_kinds)) = &CONVENTIONS - .iter() - .find(|(ref conv, _)| conv.check(&name)) - { - if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { - let lint = if item.vis.node.is_pub() { - WRONG_PUB_SELF_CONVENTION - } else { - WRONG_SELF_CONVENTION - }; - - span_lint( - cx, - lint, - first_arg.pat.span, - &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name", - conv, - &self_kinds - .iter() - .map(|k| k.description()) - .collect::>() - .join(" or ") - ), - ); - } - } + lint_wrong_self_convention( + cx, + &name, + item.vis.node.is_pub(), + self_ty, + first_arg_ty, + first_arg.pat.span + ); } } @@ -1748,26 +1730,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty(); then { - if let Some((ref conv, self_kinds)) = &CONVENTIONS - .iter() - .find(|(ref conv, _)| conv.check(&item.ident.name.as_str())) - { - if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { - span_lint( - cx, - WRONG_PUB_SELF_CONVENTION, - first_arg_span, - &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name", - conv, - &self_kinds - .iter() - .map(|k| k.description()) - .collect::>() - .join(" or ") - ), - ); - } - } + lint_wrong_self_convention(cx, &item.ident.name.as_str(), false, self_ty, first_arg_ty, first_arg_span); } } @@ -1792,6 +1755,39 @@ impl<'tcx> LateLintPass<'tcx> for Methods { extract_msrv_attr!(LateContext); } +fn lint_wrong_self_convention<'tcx>( + cx: &LateContext<'tcx>, + item_name: &str, + is_pub: bool, + self_ty: &'tcx TyS<'tcx>, + first_arg_ty: &'tcx TyS<'tcx>, + first_arg_span: Span, +) { + let lint = if is_pub { + WRONG_PUB_SELF_CONVENTION + } else { + WRONG_SELF_CONVENTION + }; + if let Some((ref conv, self_kinds)) = &CONVENTIONS.iter().find(|(ref conv, _)| conv.check(item_name)) { + if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { + span_lint( + cx, + lint, + first_arg_span, + &format!( + "methods called `{}` usually take {}; consider choosing a less ambiguous name", + conv, + &self_kinds + .iter() + .map(|k| k.description()) + .collect::>() + .join(" or ") + ), + ); + } + } +} + /// Checks for the `OR_FUN_CALL` lint. #[allow(clippy::too_many_lines)] fn lint_or_fun_call<'tcx>( diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 275866b8248f..795ba77274c8 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -90,7 +90,7 @@ mod issue4037 { } // Lint also in trait definition (see #6307) -mod issue6307{ +mod issue6307 { trait T: Sized { fn as_i32(self) {} fn as_u32(&self) {} @@ -102,7 +102,7 @@ mod issue6307{ fn to_u32(&self) {} fn from_i32(self) {} // check whether the lint can be allowed at the function level - #[allow(clippy::wrong_pub_self_convention)] + #[allow(clippy::wrong_self_convention)] fn from_cake(self) {} // test for false positives @@ -113,4 +113,4 @@ mod issue6307{ fn from_(self) {} fn to_mut(&mut self) {} } -} \ No newline at end of file +} diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 64aa957fed6a..289da6f059eb 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -77,8 +77,6 @@ error: methods called `as_*` usually take self by reference or self by mutable r | LL | fn as_i32(self) {} | ^^^^ - | - = note: `-D clippy::wrong-pub-self-convention` implied by `-D warnings` error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name --> $DIR/wrong_self_convention.rs:97:21 From db98651e722ca1cc12f2ffe159c1bc128880f8a4 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 10 Nov 2020 12:26:09 +0100 Subject: [PATCH 197/719] Allow `wrong_self_convention` in `use_self` test for trait def --- tests/ui/use_self.fixed | 1 + tests/ui/use_self.rs | 1 + tests/ui/use_self.stderr | 38 +++++++++++++++++++------------------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index ebb3aa28daf3..ded3fbb56ebb 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -71,6 +71,7 @@ mod lifetimes { mod issue2894 { trait IntoBytes { + #[allow(clippy::clippy::wrong_self_convention)] fn into_bytes(&self) -> Vec; } diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 8a182192ab34..a4f7b0bfd249 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -71,6 +71,7 @@ mod lifetimes { mod issue2894 { trait IntoBytes { + #[allow(clippy::clippy::wrong_self_convention)] fn into_bytes(&self) -> Vec; } diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index b33928597c14..80e1bfc75e80 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -37,19 +37,19 @@ LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:89:56 + --> $DIR/use_self.rs:90:56 | LL | fn bad(foos: &[Self]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:104:13 + --> $DIR/use_self.rs:105:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:112:25 + --> $DIR/use_self.rs:113:25 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -60,7 +60,7 @@ LL | use_self_expand!(); // Should lint in local macros = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: unnecessary structure name repetition - --> $DIR/use_self.rs:113:17 + --> $DIR/use_self.rs:114:17 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` @@ -71,91 +71,91 @@ LL | use_self_expand!(); // Should lint in local macros = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: unnecessary structure name repetition - --> $DIR/use_self.rs:148:21 + --> $DIR/use_self.rs:149:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:149:13 + --> $DIR/use_self.rs:150:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:136:29 + --> $DIR/use_self.rs:137:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:137:21 + --> $DIR/use_self.rs:138:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:166:21 + --> $DIR/use_self.rs:167:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:167:21 + --> $DIR/use_self.rs:168:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:168:21 + --> $DIR/use_self.rs:169:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:199:13 + --> $DIR/use_self.rs:200:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:200:13 + --> $DIR/use_self.rs:201:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:202:13 + --> $DIR/use_self.rs:203:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:221:13 + --> $DIR/use_self.rs:222:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:235:25 + --> $DIR/use_self.rs:236:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:236:13 + --> $DIR/use_self.rs:237:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:240:16 + --> $DIR/use_self.rs:241:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:240:22 + --> $DIR/use_self.rs:241:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` From 1e0f85b2640e9c2a90c197780c534a96148138bc Mon Sep 17 00:00:00 2001 From: Thibaud Date: Tue, 24 Nov 2020 18:04:58 +0100 Subject: [PATCH 198/719] Update tests/ui/use_self.rs Co-authored-by: Eduardo Broto --- tests/ui/use_self.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index a4f7b0bfd249..b04d9ce75b2a 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -71,7 +71,7 @@ mod lifetimes { mod issue2894 { trait IntoBytes { - #[allow(clippy::clippy::wrong_self_convention)] + #[allow(clippy::wrong_self_convention)] fn into_bytes(&self) -> Vec; } From 90a16e43972f8039e1f045752f04b4011a38b92f Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 10 Dec 2020 17:00:55 +0100 Subject: [PATCH 199/719] Add tests for unsized trait in `wrong_self_convention` lint --- tests/ui/use_self.fixed | 2 +- tests/ui/wrong_self_convention.rs | 23 +++++++++++++++++++ tests/ui/wrong_self_convention.stderr | 32 ++++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index ded3fbb56ebb..d6a890014e68 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -71,7 +71,7 @@ mod lifetimes { mod issue2894 { trait IntoBytes { - #[allow(clippy::clippy::wrong_self_convention)] + #[allow(clippy::wrong_self_convention)] fn into_bytes(&self) -> Vec; } diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 795ba77274c8..5282eba74fd1 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -113,4 +113,27 @@ mod issue6307 { fn from_(self) {} fn to_mut(&mut self) {} } + + trait U { + fn as_i32(self); + fn as_u32(&self); + fn into_i32(&self); + fn into_u32(self); + fn is_i32(self); + fn is_u32(&self); + fn to_i32(self); + fn to_u32(&self); + fn from_i32(self); + // check whether the lint can be allowed at the function level + #[allow(clippy::wrong_self_convention)] + fn from_cake(self); + + // test for false positives + fn as_(self); + fn into_(&self); + fn is_(self); + fn to_(self); + fn from_(self); + fn to_mut(&mut self); + } } diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 289da6f059eb..86467eb0fc73 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -102,5 +102,35 @@ error: methods called `from_*` usually take no self; consider choosing a less am LL | fn from_i32(self) {} | ^^^^ -error: aborting due to 17 previous errors +error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:118:19 + | +LL | fn as_i32(self); + | ^^^^ + +error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:120:21 + | +LL | fn into_i32(&self); + | ^^^^^ + +error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:122:19 + | +LL | fn is_i32(self); + | ^^^^ + +error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:124:19 + | +LL | fn to_i32(self); + | ^^^^ + +error: methods called `from_*` usually take no self; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:126:21 + | +LL | fn from_i32(self); + | ^^^^ + +error: aborting due to 22 previous errors From 45693b43a5e779545cf6c6af909ab5c27d94e4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 18:36:07 +0100 Subject: [PATCH 200/719] Mute the file-length error --- library/core/src/slice/iter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 71106c66f125..a10ebacf5fb0 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! Definitions of a bunch of iterators for `[T]`. #[macro_use] // import iterator! and forward_iterator! From 7952ea5a04aa34dc5441a47f7d4d227193c8fdf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 19:10:09 +0100 Subject: [PATCH 201/719] Fix the fmt issues --- library/alloc/src/slice.rs | 4 ++-- library/core/src/slice/iter.rs | 31 ++++++++++++++----------------- library/core/src/slice/mod.rs | 6 ++++-- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 5f92dfe539fb..72da781da3cc 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -110,6 +110,8 @@ pub use core::slice::{Chunks, Windows}; pub use core::slice::{ChunksExact, ChunksExactMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{ChunksMut, Split, SplitMut}; +#[unstable(feature = "slice_group_by", issue = "none")] +pub use core::slice::{GroupBy, GroupByMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Iter, IterMut}; #[stable(feature = "rchunks", since = "1.31.0")] @@ -118,8 +120,6 @@ pub use core::slice::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; -#[unstable(feature = "slice_group_by", issue = "none")] -pub use core::slice::{GroupBy, GroupByMut}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index a10ebacf5fb0..423cbd113501 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2991,7 +2991,8 @@ impl<'a, T: 'a, P> GroupBy<'a, T, P> { #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> -where P: FnMut(&T, &T) -> bool, +where + P: FnMut(&T, &T) -> bool, { type Item = &'a [T]; @@ -3013,11 +3014,7 @@ where P: FnMut(&T, &T) -> bool, #[inline] fn size_hint(&self) -> (usize, Option) { - if self.slice.is_empty() { - (0, Some(0)) - } else { - (1, Some(self.slice.len())) - } + if self.slice.is_empty() { (0, Some(0)) } else { (1, Some(self.slice.len())) } } #[inline] @@ -3028,7 +3025,8 @@ where P: FnMut(&T, &T) -> bool, #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> -where P: FnMut(&T, &T) -> bool, +where + P: FnMut(&T, &T) -> bool, { #[inline] fn next_back(&mut self) -> Option { @@ -3048,9 +3046,7 @@ where P: FnMut(&T, &T) -> bool, } #[unstable(feature = "slice_group_by", issue = "none")] -impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> -where P: FnMut(&T, &T) -> bool, -{ } +impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} /// An iterator over slice in (non-overlapping) mutable chunks separated /// by a predicate. @@ -3075,7 +3071,8 @@ impl<'a, T: 'a, P> GroupByMut<'a, T, P> { #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> -where P: FnMut(&T, &T) -> bool, +where + P: FnMut(&T, &T) -> bool, { type Item = &'a mut [T]; @@ -3098,11 +3095,7 @@ where P: FnMut(&T, &T) -> bool, #[inline] fn size_hint(&self) -> (usize, Option) { - if self.slice.is_empty() { - (0, Some(0)) - } else { - (1, Some(self.slice.len())) - } + if self.slice.is_empty() { (0, Some(0)) } else { (1, Some(self.slice.len())) } } #[inline] @@ -3113,7 +3106,8 @@ where P: FnMut(&T, &T) -> bool, #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> -where P: FnMut(&T, &T) -> bool, +where + P: FnMut(&T, &T) -> bool, { #[inline] fn next_back(&mut self) -> Option { @@ -3132,3 +3126,6 @@ where P: FnMut(&T, &T) -> bool, } } } + +#[unstable(feature = "slice_group_by", issue = "none")] +impl<'a, T: 'a, P> FusedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 218cd2c25a29..648cf88b7ef7 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1234,7 +1234,8 @@ impl [T] { #[unstable(feature = "slice_group_by", issue = "none")] #[inline] pub fn group_by(&self, pred: F) -> GroupBy<'_, T, F> - where F: FnMut(&T, &T) -> bool + where + F: FnMut(&T, &T) -> bool, { GroupBy::new(self, pred) } @@ -1263,7 +1264,8 @@ impl [T] { #[unstable(feature = "slice_group_by", issue = "none")] #[inline] pub fn group_by_mut(&mut self, pred: F) -> GroupByMut<'_, T, F> - where F: FnMut(&T, &T) -> bool + where + F: FnMut(&T, &T) -> bool, { GroupByMut::new(self, pred) } From b2a7076b10d69ede61092a62a9d5245f5077d184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 19:13:34 +0100 Subject: [PATCH 202/719] Implement a user friendly Debug on GroupBy and GroupByMut --- library/core/src/slice/iter.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 423cbd113501..6bb9cf99402e 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2976,7 +2976,6 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { /// [`group_by`]: ../../std/primitive.slice.html#method.group_by /// [slices]: ../../std/primitive.slice.html #[unstable(feature = "slice_group_by", issue = "none")] -#[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupBy<'a, T: 'a, P> { slice: &'a [T], predicate: P, @@ -3048,6 +3047,13 @@ where #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[unstable(feature = "slice_group_by", issue = "none")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupBy<'a, T, P> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("GroupBy").field("slice", &self.slice).finish() + } +} + /// An iterator over slice in (non-overlapping) mutable chunks separated /// by a predicate. /// @@ -3056,7 +3062,6 @@ impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> /// [`group_by_mut`]: ../../std/primitive.slice.html#method.group_by_mut /// [slices]: ../../std/primitive.slice.html #[unstable(feature = "slice_group_by", issue = "none")] -#[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupByMut<'a, T: 'a, P> { slice: &'a mut [T], predicate: P, @@ -3129,3 +3134,10 @@ where #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> FusedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} + +#[unstable(feature = "slice_group_by", issue = "none")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupByMut<'a, T, P> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("GroupByMut").field("slice", &self.slice).finish() + } +} From 2443f642e351705a999db70110b673593efebeaf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Dec 2020 19:42:01 +0100 Subject: [PATCH 203/719] CTFE: tweak abort-on-uninhabited message --- compiler/rustc_mir/src/interpret/intrinsics.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 2ffb7a05f25c..dfd77a8fca96 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -414,7 +414,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if layout.abi.is_uninhabited() { // The run-time intrinsic panics just to get a good backtrace; here we abort // since there is no problem showing a backtrace even for aborts. - M::abort(self, format!("attempted to instantiate uninhabited type `{}`", ty))?; + M::abort( + self, + format!( + "aborted execution: attempted to instantiate uninhabited type `{}`", + ty + ), + )?; } } sym::simd_insert => { From d8ee8e769f56203de792a4e48289aaf0126e2208 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Dec 2020 21:08:13 +0100 Subject: [PATCH 204/719] re-bless tests --- src/test/ui/{ => consts}/assume-type-intrinsics.rs | 0 src/test/ui/{ => consts}/assume-type-intrinsics.stderr | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/test/ui/{ => consts}/assume-type-intrinsics.rs (100%) rename src/test/ui/{ => consts}/assume-type-intrinsics.stderr (89%) diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/consts/assume-type-intrinsics.rs similarity index 100% rename from src/test/ui/assume-type-intrinsics.rs rename to src/test/ui/consts/assume-type-intrinsics.rs diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/consts/assume-type-intrinsics.stderr similarity index 89% rename from src/test/ui/assume-type-intrinsics.stderr rename to src/test/ui/consts/assume-type-intrinsics.stderr index 6f400086a548..ed09f74e9b1f 100644 --- a/src/test/ui/assume-type-intrinsics.stderr +++ b/src/test/ui/consts/assume-type-intrinsics.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | intrinsics::assert_inhabited::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | attempted to instantiate uninhabited type `!` + | aborted execution: attempted to instantiate uninhabited type `!` | inside `MaybeUninit::::assume_init` at $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL | inside `_BAD` at $DIR/assume-type-intrinsics.rs:11:9 | From 59abdb6a7eef003b1a1b0711ceb9a1edb1d1b84c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 27 Jul 2020 21:25:36 -0700 Subject: [PATCH 205/719] Mark `-1` as an available niche for file descriptors Based on discussion from https://internals.rust-lang.org/t/can-the-standard-library-shrink-option-file/12768, the file descriptor -1 is chosen based on the POSIX API designs that use it as a sentinel to report errors. A bigger niche could've been chosen, particularly on Linux, but would not necessarily be portable. This PR also adds a test case to ensure that the -1 niche (which is kind of hacky and has no obvious test case) works correctly. It requires the "upper" bound, which is actually -1, to be expressed in two's complement. --- library/std/src/sys/unix/fd.rs | 8 +++++++- src/test/ui/print_type_sizes/niche-filling.rs | 16 ++++++++++++---- .../ui/print_type_sizes/niche-filling.stdout | 6 ++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index d3a279a23553..0eeaa68d55a7 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -12,6 +12,11 @@ use crate::sys_common::AsInner; use libc::{c_int, c_void}; #[derive(Debug)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] pub struct FileDesc { fd: c_int, } @@ -63,7 +68,8 @@ const fn max_iov() -> usize { impl FileDesc { pub fn new(fd: c_int) -> FileDesc { - FileDesc { fd } + assert_ne!(fd, -1); + unsafe { FileDesc { fd } } } pub fn raw(&self) -> c_int { diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index 37ac45f7e053..0716cee21c66 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -15,12 +15,19 @@ // padding and overall computed sizes can be quite different. #![feature(start)] +#![feature(rustc_attrs)] #![allow(dead_code)] use std::num::NonZeroU32; pub enum MyOption { None, Some(T) } +#[rustc_layout_scalar_valid_range_start(0)] +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +pub struct MyNotNegativeOne { + _i: i32, +} + impl Default for MyOption { fn default() -> Self { MyOption::None } } @@ -77,17 +84,18 @@ fn start(_: isize, _: *const *const u8) -> isize { let _a: MyOption = Default::default(); let _b: MyOption = Default::default(); let _c: MyOption = Default::default(); - let _b: MyOption> = Default::default(); + let _d: MyOption> = Default::default(); let _e: Enum4<(), char, (), ()> = Enum4::One(()); let _f: Enum4<(), (), bool, ()> = Enum4::One(()); let _g: Enum4<(), (), (), MyOption> = Enum4::One(()); + let _h: MyOption = Default::default(); // Unions do not currently participate in niche filling. - let _h: MyOption> = Default::default(); + let _i: MyOption> = Default::default(); // ...even when theoretically possible. - let _i: MyOption> = Default::default(); - let _j: MyOption> = Default::default(); + let _j: MyOption> = Default::default(); + let _k: MyOption> = Default::default(); 0 } diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout index 1894cd218ee3..d1753c26ca83 100644 --- a/src/test/ui/print_type_sizes/niche-filling.stdout +++ b/src/test/ui/print_type_sizes/niche-filling.stdout @@ -43,6 +43,12 @@ print-type-size variant `Three`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Four`: 0 bytes print-type-size field `.0`: 0 bytes +print-type-size type: `MyNotNegativeOne`: 4 bytes, alignment: 4 bytes +print-type-size field `._i`: 4 bytes +print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes From a50811a214b50d4a835ba1ad8eac546f9c7af9fa Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 30 Jul 2020 12:11:30 -0700 Subject: [PATCH 206/719] Add safety note to library/std/src/sys/unix/fd.rs Co-authored-by: Elichai Turkel --- library/std/src/sys/unix/fd.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 0eeaa68d55a7..08c63444e2bb 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -69,6 +69,7 @@ const fn max_iov() -> usize { impl FileDesc { pub fn new(fd: c_int) -> FileDesc { assert_ne!(fd, -1); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) unsafe { FileDesc { fd } } } From 169c59ff0fcbd606c6f639c2318f71b51f6c9207 Mon Sep 17 00:00:00 2001 From: Lyndon Brown Date: Thu, 10 Dec 2020 07:00:17 +0000 Subject: [PATCH 207/719] Add some core::cmp::Ordering helpers ...to allow easier greater-than-or-equal-to and less-than-or-equal-to comparisons, and variant checking without needing to import the enum, similar to `Option::is_none()` / `Option::is_some()`, in situations where you are dealing with an `Ordering` value. (Simple `PartialOrd` / `Ord` based evaluation may not be suitable for all situations). Prior to Rust 1.42 a greater-than-or-equal-to comparison might be written either as a match block, or a traditional conditional check like this: ```rust if cmp == Ordering::Equal || cmp == Ordering::Greater { // Do something } ``` Which requires two instances of `cmp`. Don't forget that while `cmp` here is very short, it could be something much longer in real use cases. From Rust 1.42 a nicer alternative is possible: ```rust if matches!(cmp, Ordering::Equal | Ordering::Greater) { // Do something } ``` The commit adds another alternative which may be even better in some cases: ```rust if cmp.is_ge() { // Do something } ``` The earlier examples could be cleaner than they are if the variants of `Ordering` are imported such that `Equal`, `Greater` and `Less` can be referred to directly, but not everyone will want to do that. The new solution can shorten lines, help avoid logic mistakes, and avoids having to import `Ordering` / `Ordering::*`. --- library/core/src/cmp.rs | 114 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 47ae1a64190e..f752472c3ba8 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -325,6 +325,120 @@ pub enum Ordering { } impl Ordering { + /// Returns `true` if the ordering is the `Equal` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_eq(), false); + /// assert_eq!(Ordering::Equal.is_eq(), true); + /// assert_eq!(Ordering::Greater.is_eq(), false); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_eq(self) -> bool { + matches!(self, Equal) + } + + /// Returns `true` if the ordering is not the `Equal` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_ne(), true); + /// assert_eq!(Ordering::Equal.is_ne(), false); + /// assert_eq!(Ordering::Greater.is_ne(), true); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_ne(self) -> bool { + !matches!(self, Equal) + } + + /// Returns `true` if the ordering is the `Less` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_lt(), true); + /// assert_eq!(Ordering::Equal.is_lt(), false); + /// assert_eq!(Ordering::Greater.is_lt(), false); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_lt(self) -> bool { + matches!(self, Less) + } + + /// Returns `true` if the ordering is the `Greater` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_gt(), false); + /// assert_eq!(Ordering::Equal.is_gt(), false); + /// assert_eq!(Ordering::Greater.is_gt(), true); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_gt(self) -> bool { + matches!(self, Greater) + } + + /// Returns `true` if the ordering is either the `Less` or `Equal` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_le(), true); + /// assert_eq!(Ordering::Equal.is_le(), true); + /// assert_eq!(Ordering::Greater.is_le(), false); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_le(self) -> bool { + !matches!(self, Greater) + } + + /// Returns `true` if the ordering is either the `Greater` or `Equal` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_ge(), false); + /// assert_eq!(Ordering::Equal.is_ge(), true); + /// assert_eq!(Ordering::Greater.is_ge(), true); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_ge(self) -> bool { + !matches!(self, Less) + } + /// Reverses the `Ordering`. /// /// * `Less` becomes `Greater`. From 3918b82993708db5ddcfd476252cf7632281ce19 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 10 Dec 2020 15:27:07 -0500 Subject: [PATCH 208/719] Use `def_path_hash_to_def_id` when re-using a `RawDefId` Fixes #79890 Previously, we just copied a `RawDefId` from the 'old' map to the 'new' map. However, the `RawDefId` for a given `DefPathHash` may be different in the current compilation session. Using `def_path_hash_to_def_id` ensures that the `RawDefId` we use is valid in the current session. --- compiler/rustc_middle/src/dep_graph/mod.rs | 2 +- .../src/ty/query/on_disk_cache.rs | 24 ++++++++++++++++--- .../rustc_query_system/src/dep_graph/graph.rs | 4 ++-- src/test/incremental/auxiliary/issue-79890.rs | 1 + .../issue-79890-imported-crates-changed.rs | 7 ++++++ 5 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 src/test/incremental/auxiliary/issue-79890.rs create mode 100644 src/test/incremental/issue-79890-imported-crates-changed.rs diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index a94f6d25fc71..e641c1cd77bd 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -93,7 +93,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { fn register_reused_dep_path_hash(&self, hash: DefPathHash) { if let Some(cache) = self.queries.on_disk_cache.as_ref() { - cache.register_reused_dep_path_hash(hash) + cache.register_reused_dep_path_hash(*self, hash) } } diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 898cc24992ba..3eed94b1ffbc 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -454,6 +454,7 @@ impl<'sess> OnDiskCache<'sess> { fn try_remap_cnum(&self, tcx: TyCtxt<'_>, cnum: u32) -> Option { let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..])); + debug!("try_remap_cnum({}): cnum_map={:?}", cnum, cnum_map); cnum_map[CrateNum::from_u32(cnum)] } @@ -466,9 +467,22 @@ impl<'sess> OnDiskCache<'sess> { .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); } - pub fn register_reused_dep_path_hash(&self, hash: DefPathHash) { - if let Some(old_id) = self.foreign_def_path_hashes.get(&hash) { - self.latest_foreign_def_path_hashes.lock().insert(hash, *old_id); + /// If the given `hash` still exists in the current compilation, + /// calls `store_foreign_def_id` with its current `DefId`. + /// + /// Normally, `store_foreign_def_id_hash` can be called directly by + /// the dependency graph when we construct a `DepNode`. However, + /// when we re-use a deserialized `DepNode` from the previous compilation + /// session, we only have the `DefPathHash` available. This method is used + /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written + /// out for usage in the next compilation session. + pub fn register_reused_dep_path_hash(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) { + // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to + // `latest_foreign_def_path_hashes`, since the `RawDefId` might have + // changed in the current compilation session (e.g. we've added/removed crates, + // or added/removed definitions before/after the target definition). + if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { + self.store_foreign_def_id_hash(def_id, hash); } } @@ -592,6 +606,7 @@ impl<'sess> OnDiskCache<'sess> { match cache.entry(hash) { Entry::Occupied(e) => *e.get(), Entry::Vacant(e) => { + debug!("def_path_hash_to_def_id({:?})", hash); // Check if the `DefPathHash` corresponds to a definition in the current // crate if let Some(def_id) = self.local_def_path_hash_to_def_id.get(&hash).cloned() { @@ -605,9 +620,11 @@ impl<'sess> OnDiskCache<'sess> { // current compilation session, the crate is guaranteed to be the same // (otherwise, we would compute a different `DefPathHash`). let raw_def_id = self.get_raw_def_id(&hash)?; + debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); // If the owning crate no longer exists, the corresponding definition definitely // no longer exists. let krate = self.try_remap_cnum(tcx, raw_def_id.krate)?; + debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); // If our `DefPathHash` corresponded to a definition in the local crate, // we should have either found it in `local_def_path_hash_to_def_id`, or // never attempted to load it in the first place. Any query result or `DepNode` @@ -621,6 +638,7 @@ impl<'sess> OnDiskCache<'sess> { // Try to find a definition in the current session, using the previous `DefIndex` // as an initial guess. let opt_def_id = tcx.cstore.def_path_hash_to_def_id(krate, raw_def_id.index, hash); + debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); e.insert(opt_def_id); opt_def_id } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 8bde552e2d49..956d476d973e 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -596,9 +596,9 @@ impl DepGraph { // an eval_always node, let's try to mark it green recursively. if !dep_dep_node.kind.is_eval_always() { debug!( - "try_mark_previous_green({:?}) --- state of dependency {:?} \ + "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \ is unknown, trying to mark it green", - dep_node, dep_dep_node + dep_node, dep_dep_node, dep_dep_node.hash, ); let node_index = self.try_mark_previous_green( diff --git a/src/test/incremental/auxiliary/issue-79890.rs b/src/test/incremental/auxiliary/issue-79890.rs new file mode 100644 index 000000000000..8eaeafa5207d --- /dev/null +++ b/src/test/incremental/auxiliary/issue-79890.rs @@ -0,0 +1 @@ +pub trait MyTrait {} diff --git a/src/test/incremental/issue-79890-imported-crates-changed.rs b/src/test/incremental/issue-79890-imported-crates-changed.rs new file mode 100644 index 000000000000..93daa5ca9358 --- /dev/null +++ b/src/test/incremental/issue-79890-imported-crates-changed.rs @@ -0,0 +1,7 @@ +// aux-build:issue-79890.rs +// revisions:rpass1 rpass2 rpass3 +// compile-flags:--extern issue_79890 --test +// edition:2018 + +// Tests that we don't ICE when the set of imported crates changes +#[cfg(rpass2)] use issue_79890::MyTrait; From 40ed0f68574db71ec71afe77a9882ee723cc46a1 Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Thu, 10 Dec 2020 13:51:56 -0800 Subject: [PATCH 209/719] Use Symbol for inline asm register class names This takes care of one "FIXME": // FIXME: use direct symbol comparison for register class names Instead of using string literals, this uses Symbol for register class names. --- compiler/rustc_span/src/symbol.rs | 23 +++++++++++++ compiler/rustc_target/src/asm/mod.rs | 51 ++++++++++++---------------- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b9c942d61a92..b60d466c3a79 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -460,6 +460,9 @@ symbols! { document_private_items, dotdot_in_tuple_patterns, dotdoteq_in_patterns, + dreg, + dreg_low16, + dreg_low8, drop, drop_in_place, drop_types_in_const, @@ -544,6 +547,7 @@ symbols! { format_args_capture, format_args_nl, freeze, + freg, frem_fast, from, from_desugaring, @@ -627,6 +631,7 @@ symbols! { iter, keyword, kind, + kreg, label, label_break_value, lang, @@ -652,6 +657,7 @@ symbols! { lint_reasons, literal, llvm_asm, + local, local_inner_macros, log10f32, log10f64, @@ -854,6 +860,9 @@ symbols! { pub_restricted, pure, pushpop_unsafe, + qreg, + qreg_low4, + qreg_low8, quad_precision_float, question_mark, quote, @@ -875,6 +884,13 @@ symbols! { reexport_test_harness_main, reference, reflect, + reg, + reg16, + reg32, + reg64, + reg_abcd, + reg_byte, + reg_thumb, register_attr, register_tool, relaxed_adts, @@ -1060,6 +1076,8 @@ symbols! { spotlight, sqrtf32, sqrtf64, + sreg, + sreg_low16, sse4a_target_feature, stable, staged_api, @@ -1215,6 +1233,8 @@ symbols! { volatile_load, volatile_set_memory, volatile_store, + vreg, + vreg_low16, warn, wasm_import_module, wasm_target_feature, @@ -1226,6 +1246,9 @@ symbols! { wrapping_mul, wrapping_sub, write_bytes, + xmm_reg, + ymm_reg, + zmm_reg, } } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index aff1ff92d31b..3c65c84b0de4 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -20,16 +20,16 @@ macro_rules! def_reg_class { } impl $arch_regclass { - pub fn name(self) -> &'static str { + pub fn name(self) -> rustc_span::Symbol { match self { - $(Self::$class => stringify!($class),)* + $(Self::$class => rustc_span::symbol::sym::$class,)* } } - pub fn parse(_arch: super::InlineAsmArch, name: &str) -> Result { + pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result { match name { $( - stringify!($class) => Ok(Self::$class), + rustc_span::sym::$class => Ok(Self::$class), )* _ => Err("unknown register class"), } @@ -327,7 +327,7 @@ pub enum InlineAsmRegClass { } impl InlineAsmRegClass { - pub fn name(self) -> &'static str { + pub fn name(self) -> Symbol { match self { Self::X86(r) => r.name(), Self::Arm(r) => r.name(), @@ -422,29 +422,22 @@ impl InlineAsmRegClass { } pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result { - // FIXME: use direct symbol comparison for register class names - name.with(|name| { - Ok(match arch { - InlineAsmArch::X86 | InlineAsmArch::X86_64 => { - Self::X86(X86InlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?), - InlineAsmArch::AArch64 => { - Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { - Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), - InlineAsmArch::Hexagon => { - Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::Mips | InlineAsmArch::Mips64 => { - Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?), - InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?), - }) + Ok(match arch { + InlineAsmArch::X86 | InlineAsmArch::X86_64 => { + Self::X86(X86InlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { + Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Mips | InlineAsmArch::Mips64 => { + Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?), }) } @@ -484,7 +477,7 @@ impl fmt::Display for InlineAsmRegOrRegClass { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Reg(r) => write!(f, "\"{}\"", r.name()), - Self::RegClass(r) => f.write_str(r.name()), + Self::RegClass(r) => write!(f, "{}", r.name()), } } } From 08b70eda2c2767951dbd8a421187d6922164afde Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 10 Dec 2020 15:05:22 -0700 Subject: [PATCH 210/719] Fix fd test case --- library/std/src/sys/unix/fd/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/fd/tests.rs b/library/std/src/sys/unix/fd/tests.rs index a932043cbc62..c9520485c3c7 100644 --- a/library/std/src/sys/unix/fd/tests.rs +++ b/library/std/src/sys/unix/fd/tests.rs @@ -3,7 +3,7 @@ use core::mem::ManuallyDrop; #[test] fn limit_vector_count() { - let stdout = ManuallyDrop::new(FileDesc { fd: 1 }); + let stdout = ManuallyDrop::new(unsafe { FileDesc { fd: 1 } }); let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); assert!(stdout.write_vectored(&bufs).is_ok()); } From f7306b1b63435a8c782334728be3111a3954faf4 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 4 Dec 2020 12:10:55 +0100 Subject: [PATCH 211/719] Add tracking issue template for library features. --- .../ISSUE_TEMPLATE/library_tracking_issue.md | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/library_tracking_issue.md diff --git a/.github/ISSUE_TEMPLATE/library_tracking_issue.md b/.github/ISSUE_TEMPLATE/library_tracking_issue.md new file mode 100644 index 000000000000..b8544e6a4e0f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/library_tracking_issue.md @@ -0,0 +1,63 @@ +--- +name: Library Tracking Issue +about: A tracking issue for an unstable library feature. +title: Tracking Issue for XXX +labels: C-tracking-issue T-libs +--- + + +Feature gate: `#![feature(...)]` + +This is a tracking issue for ... + + + +### Public API + + + +```rust +... +``` + +### Steps / History + + + +- [ ] Implementation: ... +- [ ] Stabilization PR + +### Unresolved Questions + + + +- None yet. From 9cf2516251c5379d3e8429342e8a392df81b9aaa Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 10 Dec 2020 17:47:28 -0500 Subject: [PATCH 212/719] doc(array,vec): add notes about side effects when empty-initializing --- library/alloc/src/macros.rs | 3 +++ library/std/src/primitive_docs.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index a992d768d631..bbff1d3dc4d2 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -29,6 +29,9 @@ /// to the same boxed integer value, not five references pointing to independently /// boxed integers. /// +/// Also, note that `[T; 0]` is a valid initializer. This will initialize (or call) +/// `T` but not populate the vector with it, so be mindful of side effects. +/// /// [`Vec`]: crate::vec::Vec #[cfg(not(test))] #[macro_export] diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 55171ef2292d..b22adbbe3d35 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -489,6 +489,9 @@ mod prim_pointer {} /// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. /// The type of `x` must be [`Copy`]. /// +/// Note that `[x; 0]` is a valid repeat expression. This will produce an empty array +/// but will also initialize (or call) `x`, which may produce side effects. +/// /// Arrays of *any* size implement the following traits if the element type allows it: /// /// - [`Copy`] From b6f7eef946d4b9830bef2a4264c4b62f880f032b Mon Sep 17 00:00:00 2001 From: Tunahan Karlibas Date: Fri, 11 Dec 2020 01:59:05 +0300 Subject: [PATCH 213/719] Remove unnecessary check and fix local_def_id parameter --- compiler/rustc_mir/src/const_eval/eval_queries.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 4d14e45c2e93..058a5ced2abd 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -7,7 +7,7 @@ use crate::interpret::{ }; use rustc_errors::ErrorReported; -use rustc_hir::def::DefKind; +use rustc_hir::{ConstContext, def::DefKind}; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::traits::Reveal; @@ -30,14 +30,14 @@ fn eval_body_using_ecx<'mir, 'tcx>( body: &'mir mir::Body<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); + let tcx = *ecx.tcx; assert!( cid.promoted.is_some() || matches!( - ecx.tcx.hir().body_const_context(def_id), + ecx.tcx.hir().body_const_context(cid.instance.def_id().expect_local()), Some(ConstContext::Const | ConstContext::Static(_)) ) ); - let tcx = *ecx.tcx; let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack); @@ -47,14 +47,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); - // Assert all args (if any) are zero-sized types; `eval_body_using_ecx` doesn't - // make sense if the body is expecting nontrivial arguments. - // (The alternative would be to use `eval_fn_call` with an args slice.) - for arg in body.args_iter() { - let decl = body.local_decls.get(arg).expect("arg missing from local_decls"); - let layout = ecx.layout_of(decl.ty.subst(tcx, cid.instance.substs))?; - assert!(layout.is_zst()) - } + ecx.push_stack_frame( cid.instance, From 5ba7e9974fc34273574c9f30ccaf08885dc4dd0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 11 Dec 2020 00:00:00 +0000 Subject: [PATCH 214/719] Update stdarch submodule --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index 777efaf56447..f1ed22803f09 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 777efaf5644706b36706a7a5c51edb63835e05ca +Subproject commit f1ed22803f09e3b2c2b86d773db07ce70804987a From 686237c49aed588bf266e8dece3130b779605109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 11 Dec 2020 00:00:00 +0000 Subject: [PATCH 215/719] Lower `discriminant_value` intrinsic This allows const propagation to evaluate comparisons involving field-less enums using derived implementations of `PartialEq` (after inlining `eq`). --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 1 + compiler/rustc_middle/src/ty/sty.rs | 39 +++++- .../src/transform/lower_intrinsics.rs | 15 +++ ...trinsics.discriminant.LowerIntrinsics.diff | 124 ++++++++++++++++++ src/test/mir-opt/lower_intrinsics.rs | 18 ++- 5 files changed, 191 insertions(+), 6 deletions(-) create mode 100644 src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2ad470c2693d..e3a6cabd6005 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -489,6 +489,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Discriminant(ref place) => { let discr_ty = rvalue.ty(self.mir, bx.tcx()); + let discr_ty = self.monomorphize(discr_ty); let discr = self .codegen_place(&mut bx, place.as_ref()) .codegen_get_discr(&mut bx, discr_ty); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 78994c6e1c77..8d452399ba52 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2213,13 +2213,44 @@ impl<'tcx> TyS<'tcx> { } /// Returns the type of the discriminant of this type. - pub fn discriminant_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx), ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), - _ => { - // This can only be `0`, for now, so `u8` will suffice. - tcx.types.u8 + + ty::Param(_) | ty::Projection(_) | ty::Opaque(..) | ty::Infer(ty::TyVar(_)) => { + let assoc_items = + tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap()); + let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id; + tcx.mk_projection(discriminant_def_id, tcx.mk_substs([self.into()].iter())) + } + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Foreign(_) + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::GeneratorWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Error(_) + | ty::Infer(IntVar(_) | FloatVar(_)) => tcx.types.u8, + + ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("`discriminant_ty` applied to unexpected type: {:?}", self) } } } diff --git a/compiler/rustc_mir/src/transform/lower_intrinsics.rs b/compiler/rustc_mir/src/transform/lower_intrinsics.rs index 543acb74acbc..f5968532eb39 100644 --- a/compiler/rustc_mir/src/transform/lower_intrinsics.rs +++ b/compiler/rustc_mir/src/transform/lower_intrinsics.rs @@ -83,6 +83,21 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } } + sym::discriminant_value => { + if let (Some((destination, target)), Some(arg)) = + (*destination, args[0].place()) + { + let arg = tcx.mk_place_deref(arg); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(box ( + destination, + Rvalue::Discriminant(arg), + )), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } _ => {} } } diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff new file mode 100644 index 000000000000..a21cbfa767ed --- /dev/null +++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -0,0 +1,124 @@ +- // MIR for `discriminant` before LowerIntrinsics ++ // MIR for `discriminant` after LowerIntrinsics + + fn discriminant(_1: T) -> () { + debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:68:24: 68:25 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:68:30: 68:30 + let _2: ::Discriminant; // in scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 + let mut _3: &T; // in scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 + let _4: &T; // in scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 + let _5: u8; // in scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 + let mut _6: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 + let _7: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 + let _8: i32; // in scope 0 at $DIR/lower_intrinsics.rs:70:43: 70:44 + let _9: u8; // in scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 + let mut _10: &(); // in scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 + let _11: &(); // in scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 + let _12: (); // in scope 0 at $DIR/lower_intrinsics.rs:71:43: 71:45 + let _13: isize; // in scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 + let mut _14: &E; // in scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 + let _15: &E; // in scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 + let _16: E; // in scope 0 at $DIR/lower_intrinsics.rs:72:43: 72:47 + let mut _17: &E; // in scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 + let mut _18: &(); // in scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 + let mut _19: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 + StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 + StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 + _4 = &_1; // scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 + _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 +- _2 = discriminant_value::(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:69:5: 69:41 +- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> ::Discriminant {std::intrinsics::discriminant_value::}, val: Value(Scalar()) } ++ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:69:44: 69:45 + StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:69:45: 69:46 + StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:69:45: 69:46 + StorageLive(_5); // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 + StorageLive(_6); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 + StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 + _19 = const discriminant::::promoted[2]; // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 + // ty::Const + // + ty: &i32 + // + val: Unevaluated(WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, [T], Some(promoted[2])) + // mir::Constant + // + span: $DIR/lower_intrinsics.rs:70:42: 70:44 + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, [T], Some(promoted[2])) } + _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 + _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 +- _5 = discriminant_value::(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:70:5: 70:41 +- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> ::Discriminant {std::intrinsics::discriminant_value::}, val: Value(Scalar()) } ++ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 ++ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 + } + + bb2: { + StorageDead(_6); // scope 0 at $DIR/lower_intrinsics.rs:70:44: 70:45 + StorageDead(_7); // scope 0 at $DIR/lower_intrinsics.rs:70:45: 70:46 + StorageDead(_5); // scope 0 at $DIR/lower_intrinsics.rs:70:45: 70:46 + StorageLive(_9); // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 + StorageLive(_10); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 + StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 + _18 = const discriminant::::promoted[1]; // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 + // ty::Const + // + ty: &() + // + val: Unevaluated(WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, [T], Some(promoted[1])) + // mir::Constant + // + span: $DIR/lower_intrinsics.rs:71:42: 71:45 + // + literal: Const { ty: &(), val: Unevaluated(WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, [T], Some(promoted[1])) } + _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 + _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 +- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:71:5: 71:41 +- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as std::marker::DiscriminantKind>::Discriminant {std::intrinsics::discriminant_value::<()>}, val: Value(Scalar()) } ++ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 ++ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 + } + + bb3: { + StorageDead(_10); // scope 0 at $DIR/lower_intrinsics.rs:71:45: 71:46 + StorageDead(_11); // scope 0 at $DIR/lower_intrinsics.rs:71:46: 71:47 + StorageDead(_9); // scope 0 at $DIR/lower_intrinsics.rs:71:46: 71:47 + StorageLive(_13); // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 + StorageLive(_14); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 + StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 + _17 = const discriminant::::promoted[0]; // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 + // ty::Const + // + ty: &E + // + val: Unevaluated(WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, [T], Some(promoted[0])) + // mir::Constant + // + span: $DIR/lower_intrinsics.rs:72:42: 72:47 + // + literal: Const { ty: &E, val: Unevaluated(WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, [T], Some(promoted[0])) } + _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 + _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 +- _13 = discriminant_value::(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:72:5: 72:41 +- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> ::Discriminant {std::intrinsics::discriminant_value::}, val: Value(Scalar()) } ++ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 ++ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 + } + + bb4: { + StorageDead(_14); // scope 0 at $DIR/lower_intrinsics.rs:72:47: 72:48 + StorageDead(_15); // scope 0 at $DIR/lower_intrinsics.rs:72:48: 72:49 + StorageDead(_13); // scope 0 at $DIR/lower_intrinsics.rs:72:48: 72:49 + _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:68:30: 73:2 + drop(_1) -> bb5; // scope 0 at $DIR/lower_intrinsics.rs:73:1: 73:2 + } + + bb5: { + return; // scope 0 at $DIR/lower_intrinsics.rs:73:2: 73:2 + } + } + diff --git a/src/test/mir-opt/lower_intrinsics.rs b/src/test/mir-opt/lower_intrinsics.rs index de5f692b7da2..8d28354a5f14 100644 --- a/src/test/mir-opt/lower_intrinsics.rs +++ b/src/test/mir-opt/lower_intrinsics.rs @@ -45,11 +45,11 @@ pub fn f_dispatch(t: T) { } #[inline(never)] -pub fn f_zst(t: T) { +pub fn f_zst(_t: T) { } #[inline(never)] -pub fn f_non_zst(t: T) {} +pub fn f_non_zst(_t: T) {} // EMIT_MIR lower_intrinsics.non_const.LowerIntrinsics.diff pub fn non_const() -> usize { @@ -57,3 +57,17 @@ pub fn non_const() -> usize { let size_of_t = core::intrinsics::size_of::; size_of_t() } + +pub enum E { + A, + B, + C, +} + +// EMIT_MIR lower_intrinsics.discriminant.LowerIntrinsics.diff +pub fn discriminant(t: T) { + core::intrinsics::discriminant_value(&t); + core::intrinsics::discriminant_value(&0); + core::intrinsics::discriminant_value(&()); + core::intrinsics::discriminant_value(&E::B); +} From 97cd55e962928f08a4958ba7edc199d0b2e87a43 Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 10 Dec 2020 20:36:12 -0800 Subject: [PATCH 216/719] Improve wording of `flatten()` docs --- library/core/src/iter/traits/iterator.rs | 4 ++-- library/core/src/option.rs | 6 +++++- library/core/src/result.rs | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 19484bfd0419..7ba16f89284e 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1332,7 +1332,7 @@ pub trait Iterator { /// assert_eq!(merged, "alphabetagamma"); /// ``` /// - /// Flattening once only removes one level of nesting: + /// Flattening only removes one level of nesting at a time: /// /// ``` /// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]; @@ -1346,7 +1346,7 @@ pub trait Iterator { /// /// Here we see that `flatten()` does not perform a "deep" flatten. /// Instead, only one level of nesting is removed. That is, if you - /// `flatten()` a three-dimensional array the result will be + /// `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. /// diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 3daf26208b93..1afa30f5843f 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1695,7 +1695,9 @@ impl Option> { /// Converts from `Option>` to `Option` /// /// # Examples + /// /// Basic usage: + /// /// ``` /// let x: Option> = Some(Some(6)); /// assert_eq!(Some(6), x.flatten()); @@ -1706,7 +1708,9 @@ impl Option> { /// let x: Option> = None; /// assert_eq!(None, x.flatten()); /// ``` - /// Flattening once only removes one level of nesting: + /// + /// Flattening only removes one level of nesting at a time: + /// /// ``` /// let x: Option>> = Some(Some(Some(6))); /// assert_eq!(Some(Some(6)), x.flatten()); diff --git a/library/core/src/result.rs b/library/core/src/result.rs index b6d9f13d881e..0b4ca2b72141 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1184,7 +1184,9 @@ impl Result, E> { /// Converts from `Result, E>` to `Result` /// /// # Examples + /// /// Basic usage: + /// /// ``` /// #![feature(result_flattening)] /// let x: Result, u32> = Ok(Ok("hello")); @@ -1197,7 +1199,7 @@ impl Result, E> { /// assert_eq!(Err(6), x.flatten()); /// ``` /// - /// Flattening once only removes one level of nesting: + /// Flattening only removes one level of nesting at a time: /// /// ``` /// #![feature(result_flattening)] From a7cfffef263a8b5a5dadfad0b7f56acd83d02b9b Mon Sep 17 00:00:00 2001 From: suyash458 Date: Sat, 5 Dec 2020 04:59:22 -0800 Subject: [PATCH 217/719] add MSRV to more lints specified in #6097 update tests --- clippy_lints/src/checked_conversions.rs | 26 ++++++- clippy_lints/src/lib.rs | 15 ++-- clippy_lints/src/mem_replace.rs | 27 +++++-- clippy_lints/src/methods/mod.rs | 23 +++++- clippy_lints/src/missing_const_for_fn.rs | 29 +++++++- clippy_lints/src/ranges.rs | 29 ++++++-- clippy_lints/src/redundant_field_names.rs | 25 ++++++- .../src/redundant_static_lifetimes.rs | 26 ++++++- clippy_lints/src/use_self.rs | 25 ++++++- tests/ui/min_rust_version_attr.rs | 74 ++++++++++++++++++- tests/ui/min_rust_version_attr.stderr | 55 ++++++-------- 11 files changed, 284 insertions(+), 70 deletions(-) diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 28c1a54d2c5a..54bc69e058bc 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -6,9 +6,12 @@ use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{meets_msrv, snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; + +const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0); declare_clippy_lint! { /// **What it does:** Checks for explicit bounds checking when casting. @@ -39,10 +42,25 @@ declare_clippy_lint! { "`try_from` could replace manual bounds checking when casting" } -declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); +pub struct CheckedConversions { + msrv: Option, +} + +impl CheckedConversions { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { + if !meets_msrv(self.msrv.as_ref(), &CHECKED_CONVERSIONS_MSRV) { + return; + } + let result = if_chain! { if !in_external_macro(cx.sess(), item.span); if let ExprKind::Binary(op, ref left, ref right) = &item.kind; @@ -74,6 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions { } } } + + extract_msrv_attr!(LateContext); } /// Searches for a single check from unsigned to _ is done diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a92ae9ed8d93..38a25d22aa26 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1003,6 +1003,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box matches::Matches::new(msrv)); store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); + store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)); + store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv)); + store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv)); + store.register_late_pass(move || box mem_replace::MemReplace::new(msrv)); + store.register_late_pass(move || box ranges::Ranges::new(msrv)); + store.register_late_pass(move || box use_self::UseSelf::new(msrv)); + store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv)); + store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount); store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); @@ -1013,7 +1021,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box main_recursion::MainRecursion::default()); store.register_late_pass(|| box lifetimes::Lifetimes); store.register_late_pass(|| box entry::HashMapPass); - store.register_late_pass(|| box ranges::Ranges); store.register_late_pass(|| box types::Casts); let type_complexity_threshold = conf.type_complexity_threshold; store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold)); @@ -1058,7 +1065,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box neg_multiply::NegMultiply); store.register_late_pass(|| box mem_discriminant::MemDiscriminant); store.register_late_pass(|| box mem_forget::MemForget); - store.register_late_pass(|| box mem_replace::MemReplace); store.register_late_pass(|| box arithmetic::Arithmetic::default()); store.register_late_pass(|| box assign_ops::AssignOps); store.register_late_pass(|| box let_if_seq::LetIfSeq); @@ -1080,7 +1086,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box pass_by_ref_or_value); store.register_late_pass(|| box ref_option_ref::RefOptionRef); store.register_late_pass(|| box try_err::TryErr); - store.register_late_pass(|| box use_self::UseSelf); store.register_late_pass(|| box bytecount::ByteCount); store.register_late_pass(|| box infinite_iter::InfiniteIter); store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody); @@ -1106,10 +1111,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); - store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); store.register_late_pass(|| box transmuting_null::TransmutingNull); store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite); - store.register_late_pass(|| box checked_conversions::CheckedConversions); store.register_late_pass(|| box integer_division::IntegerDivision); store.register_late_pass(|| box inherent_to_string::InherentToString); let max_trait_bounds = conf.max_trait_bounds; @@ -1138,7 +1141,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box redundant_else::RedundantElse); store.register_late_pass(|| box create_dir::CreateDir); store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); - store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes); store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); @@ -1178,7 +1180,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box mut_mutex_lock::MutMutexLock); store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); - store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index bb0acecc5a92..19087b020771 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,13 +1,14 @@ use crate::utils::{ - in_macro, match_def_path, match_qpath, paths, snippet, snippet_with_applicability, span_lint_and_help, + in_macro, match_def_path, match_qpath, meets_msrv, paths, snippet, snippet_with_applicability, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::sym; @@ -94,7 +95,7 @@ declare_clippy_lint! { "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`" } -declare_lint_pass!(MemReplace => +impl_lint_pass!(MemReplace => [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { @@ -224,6 +225,19 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< } } +const MEM_REPLACE_WITH_DEFAULT_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); + +pub struct MemReplace { + msrv: Option, +} + +impl MemReplace { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + impl<'tcx> LateLintPass<'tcx> for MemReplace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { @@ -236,8 +250,11 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); - check_replace_with_default(cx, src, dest, expr.span); + if meets_msrv(self.msrv.as_ref(), &MEM_REPLACE_WITH_DEFAULT_MSRV) { + check_replace_with_default(cx, src, dest, expr.span); + } } } } + extract_msrv_attr!(LateContext); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8002c27a5e91..5133f31e0e7b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1487,7 +1487,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["expect", ..] => lint_expect(cx, expr, arg_lists[0]), ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), ["unwrap_or_else", "map"] => { - if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) { + if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0], self.msrv.as_ref()) { unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"); } }, @@ -1509,7 +1509,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), - ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]), + ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()), ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), @@ -2733,6 +2733,8 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } } +const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); + /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s /// Return true if lint triggered fn lint_map_unwrap_or_else<'tcx>( @@ -2740,7 +2742,11 @@ fn lint_map_unwrap_or_else<'tcx>( expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>], unwrap_args: &'tcx [hir::Expr<'_>], + msrv: Option<&RustcVersion>, ) -> bool { + if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) { + return false; + } // lint if the caller of `map()` is an `Option` let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type); @@ -2923,9 +2929,20 @@ fn lint_filter_map<'tcx>( } } +const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0); + /// lint use of `filter_map().next()` for `Iterators` -fn lint_filter_map_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { +fn lint_filter_map_next<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + filter_args: &'tcx [hir::Expr<'_>], + msrv: Option<&RustcVersion>, +) { if match_trait_method(cx, expr, &paths::ITERATOR) { + if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) { + return; + } + let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find_map(..)` instead."; let filter_snippet = snippet(cx, filter_args[1].span, ".."); diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 38e2ce563eeb..6ebeaced62a3 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,14 +1,19 @@ use crate::utils::qualify_min_const_fn::is_min_const_fn; -use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method}; +use crate::utils::{ + fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, meets_msrv, span_lint, trait_ref_of_method, +}; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; use rustc_typeck::hir_ty_to_ty; +const MISSING_CONST_FOR_FN_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); + declare_clippy_lint! { /// **What it does:** /// @@ -69,7 +74,18 @@ declare_clippy_lint! { "Lint functions definitions that could be made `const fn`" } -declare_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]); +impl_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]); + +pub struct MissingConstForFn { + msrv: Option, +} + +impl MissingConstForFn { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { fn check_fn( @@ -81,6 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { span: Span, hir_id: HirId, ) { + if !meets_msrv(self.msrv.as_ref(), &MISSING_CONST_FOR_FN_MSRV) { + return; + } + let def_id = cx.tcx.hir().local_def_id(hir_id); if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) { @@ -126,6 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); } } + extract_msrv_attr!(LateContext); } /// Returns true if any of the method parameters is a type that implements `Drop`. The method diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 4b514bbd42ca..f9173808089c 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -3,9 +3,10 @@ use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::sym; use rustc_span::symbol::Ident; @@ -13,8 +14,8 @@ use std::cmp::Ordering; use crate::utils::sugg::Sugg; use crate::utils::{ - get_parent_expr, is_integer_const, single_segment_path, snippet, snippet_opt, snippet_with_applicability, - span_lint, span_lint_and_sugg, span_lint_and_then, + get_parent_expr, is_integer_const, meets_msrv, single_segment_path, snippet, snippet_opt, + snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then, }; use crate::utils::{higher, SpanlessEq}; @@ -160,7 +161,20 @@ declare_clippy_lint! { "manually reimplementing {`Range`, `RangeInclusive`}`::contains`" } -declare_lint_pass!(Ranges => [ +const MANUAL_RANGE_CONTAINS_MSRV: RustcVersion = RustcVersion::new(1, 35, 0); + +pub struct Ranges { + msrv: Option, +} + +impl Ranges { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(Ranges => [ RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE, @@ -175,7 +189,9 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { check_range_zip_with_len(cx, path, args, expr.span); }, ExprKind::Binary(ref op, ref l, ref r) => { - check_possible_range_contains(cx, op.node, l, r, expr.span); + if meets_msrv(self.msrv.as_ref(), &MANUAL_RANGE_CONTAINS_MSRV) { + check_possible_range_contains(cx, op.node, l, r, expr.span); + } }, _ => {}, } @@ -184,6 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { check_inclusive_range_minus_one(cx, expr); check_reversed_empty_range(cx, expr); } + extract_msrv_attr!(LateContext); } fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'_>, r: &Expr<'_>, span: Span) { diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 2a81170e49e7..38dcf7a192c8 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,9 +1,12 @@ -use crate::utils::span_lint_and_sugg; +use crate::utils::{meets_msrv, span_lint_and_sugg}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +const REDUNDANT_FIELD_NAMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0); declare_clippy_lint! { /// **What it does:** Checks for fields in struct literals where shorthands @@ -33,10 +36,25 @@ declare_clippy_lint! { "checks for fields in struct literals where shorthands could be used" } -declare_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); +pub struct RedundantFieldNames { + msrv: Option, +} + +impl RedundantFieldNames { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); impl EarlyLintPass for RedundantFieldNames { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_FIELD_NAMES_MSRV) { + return; + } + if in_external_macro(cx.sess, expr.span) { return; } @@ -64,4 +82,5 @@ impl EarlyLintPass for RedundantFieldNames { } } } + extract_msrv_attr!(EarlyContext); } diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 7bbcc67aa2dd..fcfa3c12755a 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,8 +1,11 @@ -use crate::utils::{snippet, span_lint_and_then}; +use crate::utils::{meets_msrv, snippet, span_lint_and_then}; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +const REDUNDANT_STATIC_LIFETIMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0); declare_clippy_lint! { /// **What it does:** Checks for constants and statics with an explicit `'static` lifetime. @@ -29,7 +32,18 @@ declare_clippy_lint! { "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them." } -declare_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]); +pub struct RedundantStaticLifetimes { + msrv: Option, +} + +impl RedundantStaticLifetimes { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]); impl RedundantStaticLifetimes { // Recursively visit types @@ -84,6 +98,10 @@ impl RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_STATIC_LIFETIMES_MSRV) { + return; + } + if !item.span.from_expansion() { if let ItemKind::Const(_, ref var_type, _) = item.kind { self.visit_type(var_type, cx, "constants have by default a `'static` lifetime"); @@ -96,4 +114,6 @@ impl EarlyLintPass for RedundantStaticLifetimes { } } } + + extract_msrv_attr!(EarlyContext); } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 5ac4797680bc..3b23f885e08d 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -12,11 +12,12 @@ use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_middle::ty::{DefIdTree, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::kw; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{differing_macro_contexts, span_lint_and_sugg}; +use crate::utils::{differing_macro_contexts, meets_msrv, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for unnecessary repetition of structure name when a @@ -53,7 +54,7 @@ declare_clippy_lint! { "unnecessary structure name repetition whereas `Self` is applicable" } -declare_lint_pass!(UseSelf => [USE_SELF]); +impl_lint_pass!(UseSelf => [USE_SELF]); const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element"; @@ -157,8 +158,25 @@ fn check_trait_method_impl_decl<'tcx>( } } +const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); + +pub struct UseSelf { + msrv: Option, +} + +impl UseSelf { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) { + return; + } + if in_external_macro(cx.sess(), item.span) { return; } @@ -204,6 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } } } + extract_msrv_attr!(LateContext); } struct UseSelfVisitor<'a, 'tcx> { diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index 1026cc40d3b0..ac75f5e46c3f 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![clippy::msrv = "1.0.0"] -use std::ops::Deref; +use std::ops::{Deref, RangeFrom}; fn option_as_ref_deref() { let mut opt = Some(String::from("123")); @@ -42,12 +42,84 @@ pub fn manual_strip_msrv() { } } +pub fn redundant_fieldnames() { + let start = 0; + let _ = RangeFrom { start: start }; +} + +pub fn redundant_static_lifetime() { + const VAR_ONE: &'static str = "Test constant #1"; +} + +pub fn checked_conversion() { + let value: i64 = 42; + let _ = value <= (u32::max_value() as i64) && value >= 0; + let _ = value <= (u32::MAX as i64) && value >= 0; +} + +pub fn filter_map_next() { + let a = ["1", "lol", "3", "NaN", "5"]; + + #[rustfmt::skip] + let _: Option = vec![1, 2, 3, 4, 5, 6] + .into_iter() + .filter_map(|x| { + if x == 2 { + Some(x * 2) + } else { + None + } + }) + .next(); +} + +pub fn manual_range_contains() { + x >= 8 && x < 12; +} + +pub fn use_self() { + struct Foo {} + + impl Foo { + fn new() -> Foo { + Foo {} + } + fn test() -> Foo { + Foo::new() + } + } +} + +fn replace_with_default() { + let mut s = String::from("foo"); + let _ = std::mem::replace(s, String::default()); +} + +fn map_unwrap_or() { + let opt = Some(1); + + // Check for `option.map(_).unwrap_or(_)` use. + // Single line case. + let _ = opt + .map(|x| x + 1) + // Should lint even though this call is on a separate line. + .unwrap_or(0); +} + fn main() { + filter_map_next(); + checked_conversion(); + redundant_fieldnames(); + redundant_static_lifetime(); option_as_ref_deref(); match_like_matches(); match_same_arms(); match_same_arms2(); manual_strip_msrv(); + manual_range_contains(); + use_self(); + replace_with_default(); + map_unwrap_or(); } mod meets_msrv { diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index 3e1af046e7a2..d3eafe7312f4 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -1,37 +1,28 @@ -error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:60:24 - | -LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::manual-strip` implied by `-D warnings` -note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:59:9 - | -LL | if s.starts_with("hello, ") { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: try using the `strip_prefix` method - | -LL | if let Some() = s.strip_prefix("hello, ") { -LL | assert_eq!(.to_uppercase(), "WORLD!"); +error[E0425]: cannot find value `x` in this scope + --> $DIR/min_rust_version_attr.rs:77:5 | +LL | x >= 8 && x < 12; + | ^ not found in this scope -error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:72:24 - | -LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); - | ^^^^^^^^^^^^^^^^^^^^ - | -note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:71:9 - | -LL | if s.starts_with("hello, ") { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: try using the `strip_prefix` method - | -LL | if let Some() = s.strip_prefix("hello, ") { -LL | assert_eq!(.to_uppercase(), "WORLD!"); +error[E0425]: cannot find value `x` in this scope + --> $DIR/min_rust_version_attr.rs:77:15 | +LL | x >= 8 && x < 12; + | ^ not found in this scope -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/min_rust_version_attr.rs:95:31 + | +LL | let _ = std::mem::replace(s, String::default()); + | ^ + | | + | expected `&mut _`, found struct `std::string::String` + | help: consider mutably borrowing here: `&mut s` + | + = note: expected mutable reference `&mut _` + found struct `std::string::String` +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0308, E0425. +For more information about an error, try `rustc --explain E0308`. From 8df11e431b71caa7b4c891c70e9cc48144603067 Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Tue, 8 Dec 2020 22:25:20 +0530 Subject: [PATCH 218/719] add instructions to include msrv in lints --- doc/adding_lints.md | 57 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/doc/adding_lints.md b/doc/adding_lints.md index b1dacfc9c6d2..a723b0a4c20f 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -226,13 +226,13 @@ store.register_early_pass(|| box foo_functions::FooFunctions); ``` As one may expect, there is a corresponding `register_late_pass` method -available as well. Without a call to one of `register_early_pass` or +available as well. Without a call to one of `register_early_pass` or `register_late_pass`, the lint pass in question will not be run. -One reason that `cargo dev` does not automate this step is that multiple lints +One reason that `cargo dev` does not automate this step is that multiple lints can use the same lint pass, so registering the lint pass may already be done when adding a new lint. Another reason that this step is not automated is that -the order that the passes are registered determines the order the passes +the order that the passes are registered determines the order the passes actually run, which in turn affects the order that any emitted lints are output in. @@ -380,6 +380,57 @@ pass. [`FnKind::Fn`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html#variant.Fn [ident]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html +## Specifying the lint's minimum supported Rust version (msrv) + +Projects supporting older versions of Rust would need to disable a lint if it targets features +present in later versions. Support for this can be added by specifying an msrv in your lint like so, + +```rust +const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0); +``` + +The project's msrv will also have to be an attribute in the lint so you'll have to add a struct +and constructor for your lint. The project's msrv needs to be passed when the lint is registered +in `lib.rs` + +```rust +pub struct ManualStrip { + msrv: Option, +} + +impl ManualStrip { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} +``` + +The project's msrv can then be matched against the lint's msrv in the LintPass using the `meets_msrv` utility +function. + +``` rust +if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) { + return; +} +``` + +The project's msrv can also be specified as an inner attribute, which overrides the value from +`clippy.toml`. This can be accounted for using the `extract_msrv_attr!(LintContext)` macro and passing +LateContext/EarlyContext. + +```rust +impl<'tcx> LateLintPass<'tcx> for ManualStrip { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + ... + } + extract_msrv_attr!(LateContext); +} +``` + +Once the msrv is added to the lint, a relevant test case should be added to `tests/ui/min_rust_version_attr.rs` +which verifies that the lint isn't emitted if the project's msrv is lower. + ## Author lint If you have trouble implementing your lint, there is also the internal `author` From 9f27b7428307ecc6995a06f3bd666eccdbed6c99 Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Wed, 9 Dec 2020 16:39:33 +0530 Subject: [PATCH 219/719] add test for missing_const_for_fn. fix test stderr --- tests/ui/min_rust_version_attr.rs | 12 +++++- tests/ui/min_rust_version_attr.stderr | 53 ++++++++++++++++----------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index ac75f5e46c3f..3848bca32075 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -73,7 +73,11 @@ pub fn filter_map_next() { .next(); } +#[allow(clippy::no_effect)] +#[allow(clippy::short_circuit_statement)] +#[allow(clippy::unnecessary_operation)] pub fn manual_range_contains() { + let x = 5; x >= 8 && x < 12; } @@ -92,7 +96,7 @@ pub fn use_self() { fn replace_with_default() { let mut s = String::from("foo"); - let _ = std::mem::replace(s, String::default()); + let _ = std::mem::replace(&mut s, String::default()); } fn map_unwrap_or() { @@ -106,6 +110,11 @@ fn map_unwrap_or() { .unwrap_or(0); } +// Could be const +fn missing_const_for_fn() -> i32 { + 1 +} + fn main() { filter_map_next(); checked_conversion(); @@ -120,6 +129,7 @@ fn main() { use_self(); replace_with_default(); map_unwrap_or(); + missing_const_for_fn(); } mod meets_msrv { diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index d3eafe7312f4..348052631049 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -1,28 +1,37 @@ -error[E0425]: cannot find value `x` in this scope - --> $DIR/min_rust_version_attr.rs:77:5 +error: stripping a prefix manually + --> $DIR/min_rust_version_attr.rs:142:24 | -LL | x >= 8 && x < 12; - | ^ not found in this scope - -error[E0425]: cannot find value `x` in this scope - --> $DIR/min_rust_version_attr.rs:77:15 +LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + | ^^^^^^^^^^^^^^^^^^^^ | -LL | x >= 8 && x < 12; - | ^ not found in this scope - -error[E0308]: mismatched types - --> $DIR/min_rust_version_attr.rs:95:31 + = note: `-D clippy::manual-strip` implied by `-D warnings` +note: the prefix was tested here + --> $DIR/min_rust_version_attr.rs:141:9 | -LL | let _ = std::mem::replace(s, String::default()); - | ^ - | | - | expected `&mut _`, found struct `std::string::String` - | help: consider mutably borrowing here: `&mut s` +LL | if s.starts_with("hello, ") { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix("hello, ") { +LL | assert_eq!(.to_uppercase(), "WORLD!"); | - = note: expected mutable reference `&mut _` - found struct `std::string::String` -error: aborting due to 3 previous errors +error: stripping a prefix manually + --> $DIR/min_rust_version_attr.rs:154:24 + | +LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the prefix was tested here + --> $DIR/min_rust_version_attr.rs:153:9 + | +LL | if s.starts_with("hello, ") { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix("hello, ") { +LL | assert_eq!(.to_uppercase(), "WORLD!"); + | + +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0308, E0425. -For more information about an error, try `rustc --explain E0308`. From 01df56343bf1884d5e1d82e813e2930c6d9d5dd6 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Wed, 25 Nov 2020 15:15:55 -0500 Subject: [PATCH 220/719] Test cases for RFC 2229 --- .../diagnostics/arrays.rs | 86 ++++++++++++++ .../diagnostics/arrays.stderr | 111 ++++++++++++++++++ .../2229_closure_analysis/diagnostics/box.rs | 65 ++++++++++ .../diagnostics/box.stderr | 55 +++++++++ .../diagnostics/multilevel-path.rs | 28 +++++ .../diagnostics/multilevel-path.stderr | 26 ++++ .../diagnostics/simple-struct-min-capture.rs | 26 ++++ .../simple-struct-min-capture.stderr | 26 ++++ .../2229_closure_analysis/run_pass/box.rs | 97 +++++++++++++++ .../2229_closure_analysis/run_pass/box.stderr | 11 ++ .../run_pass/capture-disjoint-field-struct.rs | 28 +++++ .../capture-disjoint-field-struct.stderr | 11 ++ .../capture-disjoint-field-tuple-mut.rs | 23 ++++ .../capture-disjoint-field-tuple-mut.stderr | 11 ++ .../run_pass/capture-disjoint-field-tuple.rs | 24 ++++ .../capture-disjoint-field-tuple.stderr | 11 ++ .../disjoint-capture-in-same-closure.rs | 27 +++++ .../disjoint-capture-in-same-closure.stderr | 11 ++ .../run_pass/filter-on-struct-member.rs | 41 +++++++ .../run_pass/filter-on-struct-member.stderr | 11 ++ .../run_pass/multilevel-path-1.rs | 36 ++++++ .../run_pass/multilevel-path-1.stderr | 11 ++ .../run_pass/multilevel-path-2.rs | 34 ++++++ .../run_pass/multilevel-path-2.stderr | 11 ++ .../run_pass/multilevel-path-3.rs | 31 +++++ .../run_pass/multilevel-path-3.stderr | 11 ++ .../run_pass/nested-closure.rs | 40 +++++++ .../run_pass/nested-closure.stderr | 11 ++ 28 files changed, 914 insertions(+) create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/box.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs new file mode 100644 index 000000000000..0b94317fd713 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs @@ -0,0 +1,86 @@ +// Test that arrays are completely captured by closures by relying on the borrow check diagnostics + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +fn arrays_1() { + let mut arr = [1, 2, 3, 4, 5]; + + let mut c = || { + arr[0] += 10; + }; + + // c will capture `arr` completely, therefore another index into the + // array can't be modified here + arr[1] += 10; + //~^ ERROR: cannot use `arr` because it was mutably borrowed + //~| ERROR: cannot use `arr[_]` because it was mutably borrowed + c(); +} + +fn arrays_2() { + let mut arr = [1, 2, 3, 4, 5]; + + let c = || { + println!("{:#?}", &arr[3..4]); + }; + + // c will capture `arr` completely, therefore another index into the + // array can't be modified here + arr[1] += 10; + //~^ ERROR: cannot assign to `arr[_]` because it is borrowed + c(); +} + +fn arrays_3() { + let mut arr = [1, 2, 3, 4, 5]; + + let c = || { + println!("{}", arr[3]); + }; + + // c will capture `arr` completely, therefore another index into the + // array can't be modified here + arr[1] += 10; + //~^ ERROR: cannot assign to `arr[_]` because it is borrowed + c(); +} + +fn arrays_4() { + let mut arr = [1, 2, 3, 4, 5]; + + let mut c = || { + arr[1] += 10; + }; + + // c will capture `arr` completely, therefore we cannot borrow another index + // into the array. + println!("{}", arr[3]); + //~^ ERROR: cannot use `arr` because it was mutably borrowed + //~| ERROR: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable + + c(); +} + +fn arrays_5() { + let mut arr = [1, 2, 3, 4, 5]; + + let mut c = || { + arr[1] += 10; + }; + + // c will capture `arr` completely, therefore we cannot borrow other indecies + // into the array. + println!("{:#?}", &arr[3..2]); + //~^ ERROR: cannot borrow `arr` as immutable because it is also borrowed as mutable + + c(); +} + +fn main() { + arrays_1(); + arrays_2(); + arrays_3(); + arrays_4(); + arrays_5(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr new file mode 100644 index 000000000000..77e3e71bc612 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr @@ -0,0 +1,111 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/arrays.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0503]: cannot use `arr` because it was mutably borrowed + --> $DIR/arrays.rs:15:5 + | +LL | let mut c = || { + | -- borrow of `arr` occurs here +LL | arr[0] += 10; + | --- borrow occurs due to use of `arr` in closure +... +LL | arr[1] += 10; + | ^^^^^^ use of borrowed `arr` +... +LL | c(); + | - borrow later used here + +error[E0503]: cannot use `arr[_]` because it was mutably borrowed + --> $DIR/arrays.rs:15:5 + | +LL | let mut c = || { + | -- borrow of `arr` occurs here +LL | arr[0] += 10; + | --- borrow occurs due to use of `arr` in closure +... +LL | arr[1] += 10; + | ^^^^^^^^^^^^ use of borrowed `arr` +... +LL | c(); + | - borrow later used here + +error[E0506]: cannot assign to `arr[_]` because it is borrowed + --> $DIR/arrays.rs:30:5 + | +LL | let c = || { + | -- borrow of `arr[_]` occurs here +LL | println!("{:#?}", &arr[3..4]); + | --- borrow occurs due to use in closure +... +LL | arr[1] += 10; + | ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here +LL | +LL | c(); + | - borrow later used here + +error[E0506]: cannot assign to `arr[_]` because it is borrowed + --> $DIR/arrays.rs:44:5 + | +LL | let c = || { + | -- borrow of `arr[_]` occurs here +LL | println!("{}", arr[3]); + | --- borrow occurs due to use in closure +... +LL | arr[1] += 10; + | ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here +LL | +LL | c(); + | - borrow later used here + +error[E0503]: cannot use `arr` because it was mutably borrowed + --> $DIR/arrays.rs:58:20 + | +LL | let mut c = || { + | -- borrow of `arr` occurs here +LL | arr[1] += 10; + | --- borrow occurs due to use of `arr` in closure +... +LL | println!("{}", arr[3]); + | ^^^^^^ use of borrowed `arr` +... +LL | c(); + | - borrow later used here + +error[E0502]: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable + --> $DIR/arrays.rs:58:20 + | +LL | let mut c = || { + | -- mutable borrow occurs here +LL | arr[1] += 10; + | --- first borrow occurs due to use of `arr` in closure +... +LL | println!("{}", arr[3]); + | ^^^^^^ immutable borrow occurs here +... +LL | c(); + | - mutable borrow later used here + +error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable + --> $DIR/arrays.rs:74:24 + | +LL | let mut c = || { + | -- mutable borrow occurs here +LL | arr[1] += 10; + | --- first borrow occurs due to use of `arr` in closure +... +LL | println!("{:#?}", &arr[3..2]); + | ^^^ immutable borrow occurs here +... +LL | c(); + | - mutable borrow later used here + +error: aborting due to 7 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0502, E0503, E0506. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs new file mode 100644 index 000000000000..15be1d8c7220 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs @@ -0,0 +1,65 @@ +// Test borrow checker when we precise capture when using boxes + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +struct MetaData { x: String, name: String } +struct Data { m: MetaData } +struct BoxedData(Box); +struct EvenMoreBoxedData(Box); + +// Check diagnostics when the same path is mutated both inside and outside the closure +fn box_1() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let mut c = || { + e.0.0.m.x = format!("not-x"); + }; + + e.0.0.m.x = format!("not-x"); + //~^ ERROR: cannot assign to `e.0.0.m.x` because it is borrowed + c(); +} + +// Check diagnostics when a path is mutated inside a closure while attempting to read it outside +// the closure. +fn box_2() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let mut c = || { + e.0.0.m.x = format!("not-x"); + }; + + println!("{}", e.0.0.m.x); + //~^ ERROR: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed as mutable + c(); +} + +// Check diagnostics when a path is read inside a closure while attempting to mutate it outside +// the closure. +fn box_3() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let c = || { + println!("{}", e.0.0.m.x); + }; + + e.0.0.m.x = format!("not-x"); + //~^ ERROR: cannot assign to `e.0.0.m.x` because it is borrowed + c(); +} + +fn main() { + box_1(); + box_2(); + box_3(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr new file mode 100644 index 000000000000..17a9332fb3e6 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr @@ -0,0 +1,55 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/box.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed + --> $DIR/box.rs:22:5 + | +LL | let mut c = || { + | -- borrow of `e.0.0.m.x` occurs here +LL | e.0.0.m.x = format!("not-x"); + | - borrow occurs due to use in closure +... +LL | e.0.0.m.x = format!("not-x"); + | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here +LL | +LL | c(); + | - borrow later used here + +error[E0502]: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed as mutable + --> $DIR/box.rs:39:20 + | +LL | let mut c = || { + | -- mutable borrow occurs here +LL | e.0.0.m.x = format!("not-x"); + | - first borrow occurs due to use of `e.0.0.m.x` in closure +... +LL | println!("{}", e.0.0.m.x); + | ^^^^^^^^^ immutable borrow occurs here +LL | +LL | c(); + | - mutable borrow later used here + +error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed + --> $DIR/box.rs:56:5 + | +LL | let c = || { + | -- borrow of `e.0.0.m.x` occurs here +LL | println!("{}", e.0.0.m.x); + | - borrow occurs due to use in closure +... +LL | e.0.0.m.x = format!("not-x"); + | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here +LL | +LL | c(); + | - borrow later used here + +error: aborting due to 3 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0502, E0506. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs new file mode 100644 index 000000000000..39b04c833e38 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs @@ -0,0 +1,28 @@ +// Test that when a borrow checker diagnostics are emitted, it's as precise +// as the capture by the closure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +#![allow(unused)] + +struct Point { + x: i32, + y: i32, +} +struct Wrapper { + p: Point, +} + +fn main() { + let mut w = Wrapper { p: Point { x: 10, y: 10 } }; + + let mut c = || { + w.p.x += 20; + }; + + let py = &mut w.p.x; + //~^ ERROR: cannot borrow `w.p.x` as mutable more than once at a time + c(); + + *py = 20 +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr new file mode 100644 index 000000000000..e5a396c4e98a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr @@ -0,0 +1,26 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multilevel-path.rs:4:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0499]: cannot borrow `w.p.x` as mutable more than once at a time + --> $DIR/multilevel-path.rs:23:14 + | +LL | let mut c = || { + | -- first mutable borrow occurs here +LL | w.p.x += 20; + | - first borrow occurs due to use of `w.p.x` in closure +... +LL | let py = &mut w.p.x; + | ^^^^^^^^^^ second mutable borrow occurs here +LL | +LL | c(); + | - first borrow later used here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs new file mode 100644 index 000000000000..e78d8715e489 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs @@ -0,0 +1,26 @@ +// Test that borrow checker error is accurate and that min capture pass of the +// closure analysis is working as expected. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut p = Point { x: 10, y: 20 }; + + // `p` is captured via mutable borrow. + let mut c = || { + p.x += 10; + println!("{:?}", p); + }; + + + println!("{:?}", p); + //~^ ERROR: cannot borrow `p` as immutable because it is also borrowed as mutable + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr new file mode 100644 index 000000000000..45a61cd98b10 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr @@ -0,0 +1,26 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/simple-struct-min-capture.rs:4:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable + --> $DIR/simple-struct-min-capture.rs:23:22 + | +LL | let mut c = || { + | -- mutable borrow occurs here +LL | p.x += 10; + | - first borrow occurs due to use of `p` in closure +... +LL | println!("{:?}", p); + | ^ immutable borrow occurs here +LL | +LL | c(); + | - mutable borrow later used here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/box.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/box.rs new file mode 100644 index 000000000000..3a66399d0289 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/box.rs @@ -0,0 +1,97 @@ +// run-pass + +// Test precise capture when using boxes + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + + +struct MetaData { x: String, name: String } +struct Data { m: MetaData } +struct BoxedData(Box); +struct EvenMoreBoxedData(Box); + +// Mutate disjoint paths, one inside one outside the closure +fn box_1() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let mut c = || { + e.0.0.m.x = format!("not-x"); + }; + + e.0.0.m.name = format!("not-name"); + c(); +} + +// Mutate a path inside the closure and read a disjoint path outside the closure +fn box_2() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let mut c = || { + e.0.0.m.x = format!("not-x"); + }; + + println!("{}", e.0.0.m.name); + c(); +} + +// Read a path inside the closure and mutate a disjoint path outside the closure +fn box_3() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let c = || { + println!("{}", e.0.0.m.name); + }; + + e.0.0.m.x = format!("not-x"); + c(); +} + +// Read disjoint paths, one inside the closure and one outside the closure. +fn box_4() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let e = EvenMoreBoxedData(Box::new(b)); + + let c = || { + println!("{}", e.0.0.m.name); + }; + + println!("{}", e.0.0.m.x); + c(); +} + +// Read the same path, once inside the closure and once outside the closure. +fn box_5() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let e = EvenMoreBoxedData(Box::new(b)); + + let c = || { + println!("{}", e.0.0.m.name); + }; + + println!("{}", e.0.0.m.name); + c(); +} + +fn main() { + box_1(); + box_2(); + box_3(); + box_4(); + box_5(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr new file mode 100644 index 000000000000..9883c01b946c --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/box.rs:5:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs new file mode 100644 index 000000000000..2c359519b769 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs @@ -0,0 +1,28 @@ +// run-pass + +// Test that we can immutably borrow field of an instance of a structure from within a closure, +// while having a mutable borrow to another field of the same instance outside the closure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut p = Point { x: 10, y: 10 }; + + let c = || { + println!("{}", p.x); + }; + + // `c` should only capture `p.x`, therefore mutating `p.y` is allowed. + let py = &mut p.y; + + c(); + *py = 20; +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr new file mode 100644 index 000000000000..9b0dea770fba --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/capture-disjoint-field-struct.rs:6:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs new file mode 100644 index 000000000000..2c6679feabe4 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs @@ -0,0 +1,23 @@ +// run-pass + +// Test that we can mutate an element of a tuple from within a closure +// while immutably borrowing another element of the same tuple outside the closure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![feature(rustc_attrs)] + +fn main() { + let mut t = (10, 10); + + let mut c = || { + let t1 = &mut t.1; + *t1 = 20; + }; + + // Test that `c` only captures t.1, therefore reading t.0 is allowed. + println!("{}", t.0); + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr new file mode 100644 index 000000000000..28d091539527 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/capture-disjoint-field-tuple-mut.rs:6:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs new file mode 100644 index 000000000000..52f5cef9f01c --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs @@ -0,0 +1,24 @@ +// run-pass + +// Test that we can immutably borrow an element of a tuple from within a closure, +// while having a mutable borrow to another element of the same tuple outside the closure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![feature(rustc_attrs)] + +fn main() { + let mut t = (10, 10); + + let c = || { + println!("{}", t.0); + }; + + // `c` only captures t.0, therefore mutating t.1 is allowed. + let t1 = &mut t.1; + + c(); + *t1 = 20; +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr new file mode 100644 index 000000000000..4fb37f85f88b --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/capture-disjoint-field-tuple.rs:6:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs new file mode 100644 index 000000000000..3f8e197b7837 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs @@ -0,0 +1,27 @@ +// run-pass + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + +// Tests that if a closure uses indivual fields of the same object +// then that case is handled properly. + +#![allow(unused)] + +struct Struct { + x: i32, + y: i32, + s: String, +} + +fn main() { + let mut s = Struct { x: 10, y: 10, s: String::new() }; + + let mut c = { + s.x += 10; + s.y += 42; + s.s = String::from("new"); + }; +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr new file mode 100644 index 000000000000..bba90f8917ac --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/disjoint-capture-in-same-closure.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs new file mode 100644 index 000000000000..8c12593430ef --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs @@ -0,0 +1,41 @@ +// run-pass + +// Test disjoint capture within an impl block + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + +struct Filter { + div: i32, +} +impl Filter { + fn allowed(&self, x: i32) -> bool { + x % self.div == 1 + } +} + +struct Data { + filter: Filter, + list: Vec, +} +impl Data { + fn update(&mut self) { + // The closure passed to filter only captures self.filter, + // therefore mutating self.list is allowed. + self.list.retain( + |v| self.filter.allowed(*v), + ); + } +} + +fn main() { + let mut d = Data { filter: Filter { div: 3 }, list: Vec::new() }; + + for i in 1..10 { + d.list.push(i); + } + + d.update(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr new file mode 100644 index 000000000000..6930e18992ae --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/filter-on-struct-member.rs:5:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs new file mode 100644 index 000000000000..142c156bd56e --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs @@ -0,0 +1,36 @@ +// run-pass + +// Test that closures can catpure paths that are more precise than just one level +// from the root variable. +// +// If the closures can handle such precison we should be able to mutate one path in the closure +// while being able to mutate another path outside the closure, where the two paths are disjoint +// after applying two projections on the root variable. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![allow(unused)] + +struct Point { + x: i32, + y: i32, +} +struct Wrapper { + p: Point, +} + +fn main() { + let mut w = Wrapper { p: Point { x: 10, y: 10 } }; + + let mut c = || { + w.p.x += 20; + }; + + // `c` only captures `w.p.x`, therefore it's safe to mutate `w.p.y`. + let py = &mut w.p.y; + c(); + + *py = 20 +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr new file mode 100644 index 000000000000..94b877522f4a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multilevel-path-1.rs:10:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs new file mode 100644 index 000000000000..d8f7d55d5aa7 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs @@ -0,0 +1,34 @@ +// run-pass + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![allow(unused)] + +// If the closures can handle such precison we should be able to read one path in the closure +// while being able mutate another path outside the closure, where the two paths are disjoint +// after applying two projections on the root variable. + + +struct Point { + x: i32, + y: i32, +} +struct Wrapper { + p: Point, +} + +fn main() { + let mut w = Wrapper { p: Point { x: 10, y: 10 } }; + + let c = || { + println!("{}", w.p.x); + }; + + // `c` only captures `w.p.x`, therefore it's safe to mutate `w.p.y`. + let py = &mut w.p.y; + c(); + + *py = 20 +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr new file mode 100644 index 000000000000..100a0e167c58 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multilevel-path-2.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs new file mode 100644 index 000000000000..fc3d48ec4581 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs @@ -0,0 +1,31 @@ +// run-pass + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![allow(unused)] + +// Test that when `capture_disjoint_fields` is enabled we can read a path +// both inside and outside the closure at the same time. + +struct Point { + x: i32, + y: i32, +} +struct Wrapper { + p: Point, +} + +fn main() { + let mut w = Wrapper { p: Point { x: 10, y: 10 } }; + + let c = || { + println!("{}", w.p.x); + }; + + let px = &w.p.x; + c(); + + println!("{}", px); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr new file mode 100644 index 000000000000..cf5be6a00e9a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multilevel-path-3.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs new file mode 100644 index 000000000000..238580929ef1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs @@ -0,0 +1,40 @@ +// run-pass + +// Test whether if we can do precise capture when using nested clsoure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut p = Point { x: 5, y: 20 }; + + // c1 should capture `p.x` via immutable borrow and + // `p.y` via mutable borrow. + let mut c1 = || { + println!("{}", p.x); + + let incr = 10; + + let mut c2 = || p.y += incr; + c2(); + + println!("{}", p.y); + }; + + c1(); + + // This should not throw an error because `p.x` is borrowed via Immutable borrow, + // and multiple immutable borrow of the same place are allowed. + let px = &p.x; + + println!("{}", px); + + c1(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr new file mode 100644 index 000000000000..293aa82ce9fe --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/nested-closure.rs:5:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + From 78deacc2ec5ea47404de1f19fa7f47d53b55e1db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Nov 2020 20:23:00 +0100 Subject: [PATCH 221/719] make redundant StorageLive UB --- .../rustc_mir/src/interpret/eval_context.rs | 33 ++++++++----------- compiler/rustc_mir/src/interpret/step.rs | 6 ++-- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index d48b7fb3b924..3d955576f0ff 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -840,36 +840,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - /// Mark a storage as live, killing the previous content and returning it. - /// Remember to deallocate that! - pub fn storage_live( - &mut self, - local: mir::Local, - ) -> InterpResult<'tcx, LocalValue> { + /// Mark a storage as live, killing the previous content. + pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> { assert!(local != mir::RETURN_PLACE, "Cannot make return place live"); trace!("{:?} is now live", local); let local_val = LocalValue::Uninitialized; - // StorageLive *always* kills the value that's currently stored. - // However, we do not error if the variable already is live; - // see . - Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val)) + // StorageLive expects the local to be dead, and marks it live. + let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); + if !matches!(old, LocalValue::Dead) { + throw_ub_format!("StorageLive on a local that was already live"); + } + Ok(()) } - /// Returns the old value of the local. - /// Remember to deallocate that! - pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue { + pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> { assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); trace!("{:?} is now dead", local); - mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead) + // It is entirely okay for this local to be already dead (at least that's how we currently generate MIR) + let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead); + self.deallocate_local(old)?; + Ok(()) } - pub(super) fn deallocate_local( - &mut self, - local: LocalValue, - ) -> InterpResult<'tcx> { - // FIXME: should we tell the user that there was a local which was never written to? + fn deallocate_local(&mut self, local: LocalValue) -> InterpResult<'tcx> { if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { // All locals have a backing allocation, even if the allocation is empty // due to the local having ZST type. diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs index 156da84f2910..95738db1f553 100644 --- a/compiler/rustc_mir/src/interpret/step.rs +++ b/compiler/rustc_mir/src/interpret/step.rs @@ -95,14 +95,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Mark locals as alive StorageLive(local) => { - let old_val = self.storage_live(*local)?; - self.deallocate_local(old_val)?; + self.storage_live(*local)?; } // Mark locals as dead StorageDead(local) => { - let old_val = self.storage_dead(*local); - self.deallocate_local(old_val)?; + self.storage_dead(*local)?; } // No dynamic semantics attached to `FakeRead`; MIR From 26c61c7e49b173c8ae7c54c3a4c90b60cd9f71b8 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Wed, 25 Nov 2020 17:07:50 +0900 Subject: [PATCH 222/719] Fix FP of `manual_range_contains` in `const fn` --- clippy_lints/src/ranges.rs | 11 ++++++++--- tests/ui/range_contains.fixed | 5 +++++ tests/ui/range_contains.rs | 5 +++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index f9173808089c..3e454eecd970 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -14,7 +14,7 @@ use std::cmp::Ordering; use crate::utils::sugg::Sugg; use crate::utils::{ - get_parent_expr, is_integer_const, meets_msrv, single_segment_path, snippet, snippet_opt, + get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path, snippet, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then, }; use crate::utils::{higher, SpanlessEq}; @@ -190,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { }, ExprKind::Binary(ref op, ref l, ref r) => { if meets_msrv(self.msrv.as_ref(), &MANUAL_RANGE_CONTAINS_MSRV) { - check_possible_range_contains(cx, op.node, l, r, expr.span); + check_possible_range_contains(cx, op.node, l, r, expr); } }, _ => {}, @@ -203,7 +203,12 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { extract_msrv_attr!(LateContext); } -fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'_>, r: &Expr<'_>, span: Span) { +fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'_>, r: &Expr<'_>, expr: &Expr<'_>) { + if in_constant(cx, expr.hir_id) { + return; + } + + let span = expr.span; let combine_and = match op { BinOpKind::And | BinOpKind::BitAnd => true, BinOpKind::Or | BinOpKind::BitOr => false, diff --git a/tests/ui/range_contains.fixed b/tests/ui/range_contains.fixed index 048874a7f829..47c974e614b9 100644 --- a/tests/ui/range_contains.fixed +++ b/tests/ui/range_contains.fixed @@ -44,3 +44,8 @@ fn main() { (0. ..1.).contains(&y); !(0. ..=1.).contains(&y); } + +// Fix #6373 +pub const fn in_range(a: i32) -> bool { + 3 <= a && a <= 20 +} diff --git a/tests/ui/range_contains.rs b/tests/ui/range_contains.rs index 60ad259f404d..835deced5e4c 100644 --- a/tests/ui/range_contains.rs +++ b/tests/ui/range_contains.rs @@ -44,3 +44,8 @@ fn main() { y >= 0. && y < 1.; y < 0. || y > 1.; } + +// Fix #6373 +pub const fn in_range(a: i32) -> bool { + 3 <= a && a <= 20 +} From d986924eb13a103fc79c474eded47a663c91bb7f Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Fri, 11 Dec 2020 10:09:40 -0500 Subject: [PATCH 223/719] doc: apply suggestions --- library/alloc/src/macros.rs | 5 +++-- library/std/src/primitive_docs.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index bbff1d3dc4d2..7d4eff6185db 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -29,8 +29,9 @@ /// to the same boxed integer value, not five references pointing to independently /// boxed integers. /// -/// Also, note that `[T; 0]` is a valid initializer. This will initialize (or call) -/// `T` but not populate the vector with it, so be mindful of side effects. +/// Also, note that `vec![expr; 0]` is allowed, and produces an empty vector. +/// This will still evaluate `expr`, however, and immediately drop the resulting value, so +/// be mindful of side effects. /// /// [`Vec`]: crate::vec::Vec #[cfg(not(test))] diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index b22adbbe3d35..7aca5451ebc2 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -489,8 +489,9 @@ mod prim_pointer {} /// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. /// The type of `x` must be [`Copy`]. /// -/// Note that `[x; 0]` is a valid repeat expression. This will produce an empty array -/// but will also initialize (or call) `x`, which may produce side effects. +/// Note that `[expr; 0]` is allowed, and produces an empty array. +/// This will still evaluate `expr`, however, and immediately drop the resulting value, so +/// be mindful of side effects. /// /// Arrays of *any* size implement the following traits if the element type allows it: /// From a03feaae550b17d53ed5edd137ffaeaa530cae92 Mon Sep 17 00:00:00 2001 From: Tunahan Karlibas Date: Fri, 11 Dec 2020 18:19:30 +0300 Subject: [PATCH 224/719] add missing constraints --- .../rustc_mir/src/const_eval/eval_queries.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 058a5ced2abd..f13b4b7b9192 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -7,7 +7,7 @@ use crate::interpret::{ }; use rustc_errors::ErrorReported; -use rustc_hir::{ConstContext, def::DefKind}; +use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::traits::Reveal; @@ -34,9 +34,15 @@ fn eval_body_using_ecx<'mir, 'tcx>( assert!( cid.promoted.is_some() || matches!( - ecx.tcx.hir().body_const_context(cid.instance.def_id().expect_local()), - Some(ConstContext::Const | ConstContext::Static(_)) - ) + ecx.tcx.def_kind(cid.instance.def_id()), + DefKind::Const + | DefKind::Static + | DefKind::ConstParam + | DefKind::AnonConst + | DefKind::AssocConst + ), + "Unexpected DefKind: {:?}", + ecx.tcx.def_kind(cid.instance.def_id()) ); let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); @@ -47,8 +53,6 @@ fn eval_body_using_ecx<'mir, 'tcx>( let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); - - ecx.push_stack_frame( cid.instance, body, From ebfea6224bc3b72f3159cd8240a0f3e98366a604 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Dec 2020 18:02:23 +0100 Subject: [PATCH 225/719] Fix item name display on mobile --- src/librustdoc/html/static/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 8eef65a231d0..f208281d3b66 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1571,7 +1571,7 @@ h4 > .notable-traits { #main > table:not(.table-display) td { word-break: break-word; - min-width: 10%; + width: 50%; } .search-container > div { From 17230b40686360c26e1c8b87a648c0a83968761c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Dec 2020 18:08:44 +0100 Subject: [PATCH 226/719] update Miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index e54c5db4f0ed..2065b52dfef3 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit e54c5db4f0edbe51db42d2c3e63e9821537ed4f4 +Subproject commit 2065b52dfef3cd5a5216e65c21a056a69574bddc From 56d89364a5d097c73a1a148bd0c2760784ce0b9c Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Fri, 11 Dec 2020 18:42:36 +0000 Subject: [PATCH 227/719] Add post-initialization hook for static memory initialized using the interpereter. --- compiler/rustc_mir/src/interpret/machine.rs | 10 ++++++++++ compiler/rustc_mir/src/interpret/traits.rs | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 74625569432c..67166062d40d 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -9,6 +9,7 @@ use std::hash::Hash; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; use rustc_span::def_id::DefId; +use rustc_target::abi::Size; use super::{ AllocId, Allocation, AllocationExtra, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, @@ -299,6 +300,15 @@ pub trait Machine<'mir, 'tcx>: Sized { Ok(()) } + /// Called after initializing static memory using the interpreter. + fn after_static_mem_initialized( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ptr: Pointer, + _size: Size + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Executes a retagging operation #[inline] fn retag( diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index fa7036f4e5b0..18dba4775980 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -56,8 +56,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // If you touch this code, be sure to also make the corresponding changes to // `get_vtable` in `rust_codegen_llvm/meth.rs`. // ///////////////////////////////////////////////////////////////////////////////////////// + let vtable_size = ptr_size * u64::try_from(methods.len()).unwrap().checked_add(3).unwrap(); let vtable = self.memory.allocate( - ptr_size * u64::try_from(methods.len()).unwrap().checked_add(3).unwrap(), + vtable_size, ptr_align, MemoryKind::Vtable, ); @@ -93,6 +94,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + M::after_static_mem_initialized(self, vtable, vtable_size)?; + self.memory.mark_immutable(vtable.alloc_id)?; assert!(self.vtables.insert((ty, poly_trait_ref), vtable).is_none()); From 9c36491538476dd3ff5ec834944aacdaceb12f30 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Dec 2020 20:07:24 +0100 Subject: [PATCH 228/719] Fix main section position so that the search input remains clickable --- src/librustdoc/html/static/rustdoc.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index f208281d3b66..ebb8f98756d6 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1569,6 +1569,10 @@ h4 > .notable-traits { height: 73px; } + #main { + margin-top: 100px; + } + #main > table:not(.table-display) td { word-break: break-word; width: 50%; From 6ce29906f1fce80284cb050605f46a2959924a83 Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Fri, 11 Dec 2020 19:11:39 +0000 Subject: [PATCH 229/719] Fix rustfmt failure --- compiler/rustc_mir/src/interpret/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 67166062d40d..f50cc6c16ea1 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -304,7 +304,7 @@ pub trait Machine<'mir, 'tcx>: Sized { fn after_static_mem_initialized( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer, - _size: Size + _size: Size, ) -> InterpResult<'tcx> { Ok(()) } From 175226a01c53a9b9779e05e2d1076d4a3ed37911 Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Fri, 11 Dec 2020 19:28:20 +0000 Subject: [PATCH 230/719] Rustfmt --- compiler/rustc_mir/src/interpret/traits.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index 18dba4775980..09ce6bc0fb75 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -57,11 +57,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `get_vtable` in `rust_codegen_llvm/meth.rs`. // ///////////////////////////////////////////////////////////////////////////////////////// let vtable_size = ptr_size * u64::try_from(methods.len()).unwrap().checked_add(3).unwrap(); - let vtable = self.memory.allocate( - vtable_size, - ptr_align, - MemoryKind::Vtable, - ); + let vtable = self.memory.allocate(vtable_size, ptr_align, MemoryKind::Vtable); let drop = Instance::resolve_drop_in_place(tcx, ty); let drop = self.memory.create_fn_alloc(FnVal::Instance(drop)); From ed80815bf2554c99c1cd140d5ce3ee7df19f90d7 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Fri, 11 Dec 2020 15:02:46 -0500 Subject: [PATCH 231/719] Move binder for dyn to each list item --- .../src/value_and_place.rs | 24 +-- .../src/infer/error_reporting/mod.rs | 2 +- compiler/rustc_lint/src/context.rs | 2 +- compiler/rustc_lint/src/unused.rs | 6 +- compiler/rustc_middle/src/ty/codec.rs | 10 +- compiler/rustc_middle/src/ty/context.rs | 34 ++-- compiler/rustc_middle/src/ty/error.rs | 2 +- compiler/rustc_middle/src/ty/flags.rs | 20 +-- compiler/rustc_middle/src/ty/print/mod.rs | 6 +- compiler/rustc_middle/src/ty/print/pretty.rs | 145 ++++++++++++------ compiler/rustc_middle/src/ty/relate.rs | 20 ++- .../rustc_middle/src/ty/structural_impls.rs | 4 +- compiler/rustc_middle/src/ty/sty.rs | 60 +++----- .../src/interpret/intrinsics/type_name.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 4 +- compiler/rustc_symbol_mangling/src/legacy.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 41 ++--- .../error_reporting/on_unimplemented.rs | 4 +- .../src/traits/object_safety.rs | 28 ++-- .../src/traits/select/confirmation.rs | 53 ++++--- .../rustc_trait_selection/src/traits/wf.rs | 4 +- compiler/rustc_traits/src/chalk/lowering.rs | 63 ++++---- compiler/rustc_typeck/src/astconv/mod.rs | 20 +-- .../rustc_typeck/src/check/method/suggest.rs | 8 +- .../clippy/clippy_lints/src/utils/mod.rs | 4 +- 25 files changed, 307 insertions(+), 261 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index cb40d4ed9a6d..5bcb11fd515a 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -480,17 +480,19 @@ impl<'tcx> CPlace<'tcx> { // fn(&T) -> for<'l> fn(&'l T) is allowed } (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { - let from_traits = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from_traits); - let to_traits = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_traits); - assert_eq!( - from_traits, to_traits, - "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", - from_traits, to_traits, fx, - ); + for (from, to) in from_traits.iter().zip(to_traits) { + let from = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); + let to = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); + assert_eq!( + from, to, + "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", + from_traits, to_traits, fx, + ); + } // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed } _ => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 183fb314a00d..fdec3c9fb736 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -496,7 +496,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn print_dyn_existential( self, - _predicates: &'tcx ty::List>, + _predicates: &'tcx ty::List>>, ) -> Result { Err(NonTrivialPath) } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 16563d21ff13..bfeef4904893 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -786,7 +786,7 @@ impl<'tcx> LateContext<'tcx> { fn print_dyn_existential( self, - _predicates: &'tcx ty::List>, + _predicates: &'tcx ty::List>>, ) -> Result { Ok(()) } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 2a5ad5e6c98a..5e1f94c071c6 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -218,8 +218,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } ty::Dynamic(binder, _) => { let mut has_emitted = false; - for predicate in binder.skip_binder().iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = + predicate.skip_binder() + { let def_id = trait_ref.def_id; let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post,); diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index b2fc3710cd67..cd3bd96f9fcf 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -321,10 +321,14 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> + for ty::List>> +{ fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { let len = decoder.read_usize()?; - Ok(decoder.tcx().mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) + Ok(decoder + .tcx() + .mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) } } @@ -373,7 +377,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::N impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List>, - &'tcx ty::List>, + &'tcx ty::List>>, &'tcx Allocation, &'tcx mir::Body<'tcx>, &'tcx mir::UnsafetyCheckResult, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1b3416e112ba..9218040be9c1 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -87,7 +87,7 @@ pub struct CtxtInterners<'tcx> { substs: InternedSet<'tcx, InternalSubsts<'tcx>>, canonical_var_infos: InternedSet<'tcx, List>>, region: InternedSet<'tcx, RegionKind>, - existential_predicates: InternedSet<'tcx, List>>, + poly_existential_predicates: InternedSet<'tcx, List>>>, predicate: InternedSet<'tcx, PredicateInner<'tcx>>, predicates: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, @@ -103,7 +103,7 @@ impl<'tcx> CtxtInterners<'tcx> { type_list: Default::default(), substs: Default::default(), region: Default::default(), - existential_predicates: Default::default(), + poly_existential_predicates: Default::default(), canonical_var_infos: Default::default(), predicate: Default::default(), predicates: Default::default(), @@ -1610,7 +1610,7 @@ nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} -nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} +nop_list_lift! {poly_existential_predicates; ty::Binder> => ty::Binder>} nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>} nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>} nop_list_lift! {projs; ProjectionKind => ProjectionKind} @@ -2051,7 +2051,8 @@ slice_interners!( type_list: _intern_type_list(Ty<'tcx>), substs: _intern_substs(GenericArg<'tcx>), canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo<'tcx>), - existential_predicates: _intern_existential_predicates(ExistentialPredicate<'tcx>), + poly_existential_predicates: + _intern_poly_existential_predicates(ty::Binder>), predicates: _intern_predicates(Predicate<'tcx>), projs: _intern_projs(ProjectionKind), place_elems: _intern_place_elems(PlaceElem<'tcx>), @@ -2282,7 +2283,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_dynamic( self, - obj: ty::Binder<&'tcx List>>, + obj: &'tcx List>>, reg: ty::Region<'tcx>, ) -> Ty<'tcx> { self.mk_ty(Dynamic(obj, reg)) @@ -2412,13 +2413,17 @@ impl<'tcx> TyCtxt<'tcx> { Place { local: place.local, projection: self.intern_place_elems(&projection) } } - pub fn intern_existential_predicates( + pub fn intern_poly_existential_predicates( self, - eps: &[ExistentialPredicate<'tcx>], - ) -> &'tcx List> { + eps: &[ty::Binder>], + ) -> &'tcx List>> { assert!(!eps.is_empty()); - assert!(eps.array_windows().all(|[a, b]| a.stable_cmp(self, b) != Ordering::Greater)); - self._intern_existential_predicates(eps) + assert!( + eps.array_windows() + .all(|[a, b]| a.skip_binder().stable_cmp(self, &b.skip_binder()) + != Ordering::Greater) + ); + self._intern_poly_existential_predicates(eps) } pub fn intern_predicates(self, preds: &[Predicate<'tcx>]) -> &'tcx List> { @@ -2475,13 +2480,16 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn mk_existential_predicates< - I: InternAs<[ExistentialPredicate<'tcx>], &'tcx List>>, + pub fn mk_poly_existential_predicates< + I: InternAs< + [ty::Binder>], + &'tcx List>>, + >, >( self, iter: I, ) -> I::Output { - iter.intern_with(|xs| self.intern_existential_predicates(xs)) + iter.intern_with(|xs| self.intern_poly_existential_predicates(xs)) } pub fn mk_predicates], &'tcx List>>>( diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 5ec0ec0c56ad..97af927dfcba 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -58,7 +58,7 @@ pub enum TypeError<'tcx> { CyclicTy(Ty<'tcx>), CyclicConst(&'tcx ty::Const<'tcx>), ProjectionMismatched(ExpectedFound), - ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), + ExistentialMismatch(ExpectedFound<&'tcx ty::List>>>), ObjectUnsafeCoercion(DefId), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 8b97a87f214b..4de3d1592486 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -160,19 +160,15 @@ impl FlagComputation { } &ty::Dynamic(obj, r) => { - self.bound_computation(obj, |computation, obj| { - for predicate in obj.iter() { - match predicate { - ty::ExistentialPredicate::Trait(tr) => { - computation.add_substs(tr.substs) - } - ty::ExistentialPredicate::Projection(p) => { - computation.add_existential_projection(&p); - } - ty::ExistentialPredicate::AutoTrait(_) => {} + for predicate in obj.iter() { + self.bound_computation(predicate, |computation, predicate| match predicate { + ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), + ty::ExistentialPredicate::Projection(p) => { + computation.add_existential_projection(&p); } - } - }); + ty::ExistentialPredicate::AutoTrait(_) => {} + }); + } self.add_region(r); } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 2e00be2395b8..c79e06b7fdd3 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -63,7 +63,7 @@ pub trait Printer<'tcx>: Sized { fn print_dyn_existential( self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result; fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result; @@ -343,7 +343,9 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { } } -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List> { +impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> + for &'tcx ty::List>> +{ type Output = P::DynExistential; type Error = P::Error; fn print(&self, cx: P) -> Result { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 38f8e779f6a9..09ef69e9690a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -209,6 +209,17 @@ pub trait PrettyPrinter<'tcx>: value.as_ref().skip_binder().print(self) } + fn wrap_binder Result>( + self, + value: &ty::Binder, + f: F, + ) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, + { + f(value.as_ref().skip_binder(), self) + } + /// Prints comma-separated elements. fn comma_sep(mut self, mut elems: impl Iterator) -> Result where @@ -753,72 +764,77 @@ pub trait PrettyPrinter<'tcx>: fn pretty_print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { - define_scoped_cx!(self); - // Generate the main trait ref, including associated types. let mut first = true; if let Some(principal) = predicates.principal() { - p!(print_def_path(principal.def_id, &[])); + self = self.wrap_binder(&principal, |principal, mut cx| { + define_scoped_cx!(cx); + p!(print_def_path(principal.def_id, &[])); - let mut resugared = false; + let mut resugared = false; - // Special-case `Fn(...) -> ...` and resugar it. - let fn_trait_kind = self.tcx().fn_trait_kind_from_lang_item(principal.def_id); - if !self.tcx().sess.verbose() && fn_trait_kind.is_some() { - if let ty::Tuple(ref args) = principal.substs.type_at(0).kind() { - let mut projections = predicates.projection_bounds(); - if let (Some(proj), None) = (projections.next(), projections.next()) { - let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); - p!(pretty_fn_sig(&tys, false, proj.ty)); - resugared = true; + // Special-case `Fn(...) -> ...` and resugar it. + let fn_trait_kind = cx.tcx().fn_trait_kind_from_lang_item(principal.def_id); + if !cx.tcx().sess.verbose() && fn_trait_kind.is_some() { + if let ty::Tuple(ref args) = principal.substs.type_at(0).kind() { + let mut projections = predicates.projection_bounds(); + if let (Some(proj), None) = (projections.next(), projections.next()) { + let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); + p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty)); + resugared = true; + } } } - } - // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, - // in order to place the projections inside the `<...>`. - if !resugared { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx().mk_ty_infer(ty::FreshTy(0)); - let principal = principal.with_self_ty(self.tcx(), dummy_self); + // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, + // in order to place the projections inside the `<...>`. + if !resugared { + // Use a type that can't appear in defaults of type parameters. + let dummy_cx = cx.tcx().mk_ty_infer(ty::FreshTy(0)); + let principal = principal.with_self_ty(cx.tcx(), dummy_cx); - let args = self.generic_args_to_print( - self.tcx().generics_of(principal.def_id), - principal.substs, - ); + let args = cx.generic_args_to_print( + cx.tcx().generics_of(principal.def_id), + principal.substs, + ); - // Don't print `'_` if there's no unerased regions. - let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, - _ => false, - }); - let mut args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => print_regions, - _ => true, - }); - let mut projections = predicates.projection_bounds(); + // Don't print `'_` if there's no unerased regions. + let print_regions = args.iter().any(|arg| match arg.unpack() { + GenericArgKind::Lifetime(r) => *r != ty::ReErased, + _ => false, + }); + let mut args = args.iter().cloned().filter(|arg| match arg.unpack() { + GenericArgKind::Lifetime(_) => print_regions, + _ => true, + }); + let mut projections = predicates.projection_bounds(); - let arg0 = args.next(); - let projection0 = projections.next(); - if arg0.is_some() || projection0.is_some() { - let args = arg0.into_iter().chain(args); - let projections = projection0.into_iter().chain(projections); + let arg0 = args.next(); + let projection0 = projections.next(); + if arg0.is_some() || projection0.is_some() { + let args = arg0.into_iter().chain(args); + let projections = projection0.into_iter().chain(projections); - p!(generic_delimiters(|mut cx| { - cx = cx.comma_sep(args)?; - if arg0.is_some() && projection0.is_some() { - write!(cx, ", ")?; - } - cx.comma_sep(projections) - })); + p!(generic_delimiters(|mut cx| { + cx = cx.comma_sep(args)?; + if arg0.is_some() && projection0.is_some() { + write!(cx, ", ")?; + } + cx.comma_sep(projections) + })); + } } - } + Ok(cx) + })?; + first = false; } + define_scoped_cx!(self); + // Builtin bounds. // FIXME(eddyb) avoid printing twice (needed to ensure // that the auto traits are sorted *and* printed via cx). @@ -1391,7 +1407,7 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { fn print_dyn_existential( self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { self.pretty_print_dyn_existential(predicates) } @@ -1537,6 +1553,17 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { self.pretty_in_binder(value) } + fn wrap_binder Result>( + self, + value: &ty::Binder, + f: C, + ) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, + { + self.pretty_wrap_binder(value, f) + } + fn typed_value( mut self, f: impl FnOnce(Self) -> Result, @@ -1790,6 +1817,22 @@ impl FmtPrinter<'_, 'tcx, F> { Ok(inner) } + pub fn pretty_wrap_binder Result>( + self, + value: &ty::Binder, + f: C, + ) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>, + { + let old_region_index = self.region_index; + let (new, new_value) = self.name_all_regions(value)?; + let mut inner = f(&new_value.0, new)?; + inner.region_index = old_region_index; + inner.binder_depth -= 1; + Ok(inner) + } + fn prepare_late_bound_region_info(&mut self, value: &ty::Binder) where T: TypeFoldable<'tcx>, @@ -1906,12 +1949,12 @@ impl ty::Binder> { forward_display_to_print! { Ty<'tcx>, - &'tcx ty::List>, + &'tcx ty::List>>, &'tcx ty::Const<'tcx>, // HACK(eddyb) these are exhaustive instead of generic, // because `for<'tcx>` isn't possible yet. - ty::Binder<&'tcx ty::List>>, + ty::Binder>, ty::Binder>, ty::Binder>, ty::Binder>, diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index ef5034e218da..8a3a6305d01b 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -603,7 +603,7 @@ pub fn super_relate_consts>( new_const_val.map(|val| tcx.mk_const(ty::Const { val, ty: a.ty })) } -impl<'tcx> Relate<'tcx> for &'tcx ty::List> { +impl<'tcx> Relate<'tcx> for &'tcx ty::List>> { fn relate>( relation: &mut R, a: Self, @@ -616,9 +616,9 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { // in `a`. let mut a_v: Vec<_> = a.into_iter().collect(); let mut b_v: Vec<_> = b.into_iter().collect(); - a_v.sort_by(|a, b| a.stable_cmp(tcx, b)); + a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); a_v.dedup(); - b_v.sort_by(|a, b| a.stable_cmp(tcx, b)); + b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); b_v.dedup(); if a_v.len() != b_v.len() { return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))); @@ -626,14 +626,18 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { let v = a_v.into_iter().zip(b_v.into_iter()).map(|(ep_a, ep_b)| { use crate::ty::ExistentialPredicate::*; - match (ep_a, ep_b) { - (Trait(a), Trait(b)) => Ok(Trait(relation.relate(a, b)?)), - (Projection(a), Projection(b)) => Ok(Projection(relation.relate(a, b)?)), - (AutoTrait(a), AutoTrait(b)) if a == b => Ok(AutoTrait(a)), + match (ep_a.skip_binder(), ep_b.skip_binder()) { + (Trait(a), Trait(b)) => Ok(ty::Binder::bind(Trait( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + (Projection(a), Projection(b)) => Ok(ty::Binder::bind(Projection( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + (AutoTrait(a), AutoTrait(b)) if a == b => Ok(ep_a.rebind(AutoTrait(a))), _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))), } }); - Ok(tcx.mk_existential_predicates(v)?) + Ok(tcx.mk_poly_existential_predicates(v)?) } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 94e69a93a6b1..8af5792b3fb6 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -843,9 +843,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List>> { fn super_fold_with>(self, folder: &mut F) -> Self { - ty::util::fold_list(self, folder, |tcx, v| tcx.intern_existential_predicates(v)) + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 78994c6e1c77..f85a08005eb8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -152,7 +152,7 @@ pub enum TyKind<'tcx> { FnPtr(PolyFnSig<'tcx>), /// A trait, defined with `trait`. - Dynamic(Binder<&'tcx List>>, ty::Region<'tcx>), + Dynamic(&'tcx List>>, ty::Region<'tcx>), /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. @@ -762,7 +762,7 @@ impl<'tcx> Binder> { } } -impl<'tcx> List> { +impl<'tcx> List>> { /// Returns the "principal `DefId`" of this set of existential predicates. /// /// A Rust trait object type consists (in addition to a lifetime bound) @@ -788,64 +788,42 @@ impl<'tcx> List> { /// is `{Send, Sync}`, while there is no principal. These trait objects /// have a "trivial" vtable consisting of just the size, alignment, /// and destructor. - pub fn principal(&self) -> Option> { - match self[0] { - ExistentialPredicate::Trait(tr) => Some(tr), - _ => None, - } + pub fn principal(&self) -> Option>> { + self[0] + .map_bound(|this| match this { + ExistentialPredicate::Trait(tr) => Some(tr), + _ => None, + }) + .transpose() } pub fn principal_def_id(&self) -> Option { - self.principal().map(|trait_ref| trait_ref.def_id) + self.principal().map(|trait_ref| trait_ref.skip_binder().def_id) } #[inline] pub fn projection_bounds<'a>( &'a self, - ) -> impl Iterator> + 'a { - self.iter().filter_map(|predicate| match predicate { - ExistentialPredicate::Projection(projection) => Some(projection), - _ => None, + ) -> impl Iterator>> + 'a { + self.iter().filter_map(|predicate| { + predicate + .map_bound(|pred| match pred { + ExistentialPredicate::Projection(projection) => Some(projection), + _ => None, + }) + .transpose() }) } #[inline] pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { - self.iter().filter_map(|predicate| match predicate { + self.iter().filter_map(|predicate| match predicate.skip_binder() { ExistentialPredicate::AutoTrait(did) => Some(did), _ => None, }) } } -impl<'tcx> Binder<&'tcx List>> { - pub fn principal(&self) -> Option>> { - self.map_bound(|b| b.principal()).transpose() - } - - pub fn principal_def_id(&self) -> Option { - self.skip_binder().principal_def_id() - } - - #[inline] - pub fn projection_bounds<'a>( - &'a self, - ) -> impl Iterator> + 'a { - self.skip_binder().projection_bounds().map(Binder::bind) - } - - #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { - self.skip_binder().auto_traits() - } - - pub fn iter<'a>( - &'a self, - ) -> impl DoubleEndedIterator>> + 'tcx { - self.skip_binder().iter().map(Binder::bind) - } -} - /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where-clause: /// diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index 554ada1ab254..e1ec4cc5e973 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -74,7 +74,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { let mut first = true; for p in predicates { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 4414bf57c6b7..3b4249a93e1f 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -184,8 +184,8 @@ where ty::Dynamic(predicates, ..) => { // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. - for predicate in predicates.skip_binder() { - let trait_ref = match predicate { + for predicate in predicates { + let trait_ref = match predicate.skip_binder() { ty::ExistentialPredicate::Trait(trait_ref) => trait_ref, ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), ty::ExistentialPredicate::AutoTrait(def_id) => { diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index eba8e1a0613f..6356a7e78325 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -222,7 +222,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { let mut first = true; for p in predicates { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index c28c2fecfbb4..0294fb23c568 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -465,9 +465,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { ty::Dynamic(predicates, r) => { self.push("D"); - self = self.in_binder(&predicates, |cx, predicates| { - cx.print_dyn_existential(predicates) - })?; + self = self.print_dyn_existential(predicates)?; self = r.print(self)?; } @@ -486,26 +484,29 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { for predicate in predicates { - match predicate { - ty::ExistentialPredicate::Trait(trait_ref) => { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0)); - let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self); - self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; + self = self.in_binder(&predicate, |mut cx, predicate| { + match predicate { + ty::ExistentialPredicate::Trait(trait_ref) => { + // Use a type that can't appear in defaults of type parameters. + let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0)); + let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self); + cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + ty::ExistentialPredicate::Projection(projection) => { + let name = cx.tcx.associated_item(projection.item_def_id).ident; + cx.push("p"); + cx.push_ident(&name.as_str()); + cx = projection.ty.print(cx)?; + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + cx = cx.print_def_path(*def_id, &[])?; + } } - ty::ExistentialPredicate::Projection(projection) => { - let name = self.tcx.associated_item(projection.item_def_id).ident; - self.push("p"); - self.push_ident(&name.as_str()); - self = projection.ty.print(self)?; - } - ty::ExistentialPredicate::AutoTrait(def_id) => { - self = self.print_def_path(def_id, &[])?; - } - } + Ok(cx) + })?; } self.push("E"); Ok(self) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 1b5375938af6..69f66f6e6b1a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -219,8 +219,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } if let ty::Dynamic(traits, _) = self_ty.kind() { - for t in traits.skip_binder() { - if let ty::ExistentialPredicate::Trait(trait_ref) = t { + for t in traits.iter() { + if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index d912a00d6b70..8b275db89f19 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -551,8 +551,9 @@ fn object_ty_for_trait<'tcx>( let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); - let trait_predicate = - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait( + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), + )); let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) .flat_map(|super_trait_ref| { @@ -569,24 +570,19 @@ fn object_ty_for_trait<'tcx>( let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { // We *can* get bound lifetimes here in cases like // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. - // - // binder moved to (*)... - let super_trait_ref = super_trait_ref.skip_binder(); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), - item_def_id: item.def_id, - substs: super_trait_ref.substs, + super_trait_ref.map_bound(|super_trait_ref| { + ty::ExistentialPredicate::Projection(ty::ExistentialProjection { + ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), + item_def_id: item.def_id, + substs: super_trait_ref.substs, + }) }) }); - let existential_predicates = - tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); + let existential_predicates = tcx + .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - let object_ty = tcx.mk_dynamic( - // (*) ... binder re-introduced here - ty::Binder::bind(existential_predicates), - lifetime, - ); + let object_ty = tcx.mk_dynamic(existential_predicates, lifetime); debug!("object_ty_for_trait: object_ty=`{}`", object_ty); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index a42c80213464..f873a6ceb60f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -375,24 +375,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref); let data = match *self_ty.kind() { - ty::Dynamic(data, ..) => { - self.infcx - .replace_bound_vars_with_fresh_vars( - obligation.cause.span, - HigherRankedType, - data, - ) - .0 - } + ty::Dynamic(data, ..) => data, _ => span_bug!(obligation.cause.span, "object candidate with non-object"), }; - let object_trait_ref = data - .principal() - .unwrap_or_else(|| { - span_bug!(obligation.cause.span, "object candidate with no principal") - }) - .with_self_ty(self.tcx(), self_ty); + let object_trait_ref = data.principal().unwrap_or_else(|| { + span_bug!(obligation.cause.span, "object candidate with no principal") + }); + let object_trait_ref = self + .infcx + .replace_bound_vars_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + object_trait_ref, + ) + .0; + let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty); let mut nested = vec![]; @@ -711,15 +709,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { // See `assemble_candidates_for_unsizing` for more info. - let existential_predicates = data_a.map_bound(|data_a| { - let iter = data_a - .principal() - .map(ty::ExistentialPredicate::Trait) - .into_iter() - .chain(data_a.projection_bounds().map(ty::ExistentialPredicate::Projection)) - .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); - tcx.mk_existential_predicates(iter) - }); + let iter = data_a + .principal() + .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) + .into_iter() + .chain( + data_a + .projection_bounds() + .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), + ) + .chain( + data_b + .auto_traits() + .map(ty::ExistentialPredicate::AutoTrait) + .map(ty::Binder::dummy), + ); + let existential_predicates = tcx.mk_poly_existential_predicates(iter); let source_trait = tcx.mk_dynamic(existential_predicates, r_b); // Require that the traits involved in this upcast are **equal**; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 5bcb16d21e09..3f58fd72f409 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -706,7 +706,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { fn from_object_ty( &mut self, ty: Ty<'tcx>, - data: ty::Binder<&'tcx ty::List>>, + data: &'tcx ty::List>>, region: ty::Region<'tcx>, ) { // Imagine a type like this: @@ -769,7 +769,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// `infer::required_region_bounds`, see that for more information. pub fn object_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, - existential_predicates: ty::Binder<&'tcx ty::List>>, + existential_predicates: &'tcx ty::List>>, ) -> Vec> { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 9afb980f84d2..3a747b09cd4c 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -615,7 +615,7 @@ impl<'tcx> LowerInto<'tcx, Option LowerInto<'tcx, chalk_ir::Binders>>> - for Binder<&'tcx ty::List>> + for &'tcx ty::List>> { fn lower_into( self, @@ -627,48 +627,53 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders>]> // This means that any variables that are escaping `self` need to be // shifted in by one so that they are still escaping. - let shifted_predicates = ty::fold::shift_vars(interner.tcx, self, 1); + let predicates = ty::fold::shift_vars(interner.tcx, self, 1); - let (predicates, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, shifted_predicates); let self_ty = interner.tcx.mk_ty(ty::Bound( // This is going to be wrapped in a binder ty::DebruijnIndex::from_usize(1), ty::BoundTy { var: ty::BoundVar::from_usize(0), kind: ty::BoundTyKind::Anon }, )); - let where_clauses = predicates.into_iter().map(|predicate| match predicate { - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { - chalk_ir::Binders::new( + let where_clauses = predicates.into_iter().map(|predicate| { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, predicate); + match predicate { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { + chalk_ir::Binders::new( + binders.clone(), + chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { + trait_id: chalk_ir::TraitId(def_id), + substitution: interner + .tcx + .mk_substs_trait(self_ty, substs) + .lower_into(interner), + }), + ) + } + ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new( + binders.clone(), + chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { + alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { + associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id), + substitution: interner + .tcx + .mk_substs_trait(self_ty, predicate.substs) + .lower_into(interner), + }), + ty: predicate.ty.lower_into(interner), + }), + ), + ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( binders.clone(), chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { trait_id: chalk_ir::TraitId(def_id), substitution: interner .tcx - .mk_substs_trait(self_ty, substs) + .mk_substs_trait(self_ty, &[]) .lower_into(interner), }), - ) + ), } - ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new( - binders.clone(), - chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { - alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id), - substitution: interner - .tcx - .mk_substs_trait(self_ty, predicate.substs) - .lower_into(interner), - }), - ty: predicate.ty.lower_into(interner), - }), - ), - ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( - binders.clone(), - chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { - trait_id: chalk_ir::TraitId(def_id), - substitution: interner.tcx.mk_substs_trait(self_ty, &[]).lower_into(interner), - }), - ), }); // Binder for the bound variable representing the concrete underlying type. diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 7888cb1b9f59..693cd236299a 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1254,22 +1254,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) }); - // Calling `skip_binder` is okay because the predicates are re-bound. - let regular_trait_predicates = existential_trait_refs - .map(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref.skip_binder())); - let auto_trait_predicates = auto_traits - .into_iter() - .map(|trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())); + let regular_trait_predicates = existential_trait_refs.map(|trait_ref| { + trait_ref.map_bound(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref)) + }); + let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { + ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) + }); let mut v = regular_trait_predicates .chain(auto_trait_predicates) .chain( existential_projections - .map(|x| ty::ExistentialPredicate::Projection(x.skip_binder())), + .map(|x| x.map_bound(|x| ty::ExistentialPredicate::Projection(x))), ) .collect::>(); - v.sort_by(|a, b| a.stable_cmp(tcx, b)); + v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); v.dedup(); - let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter())); + let existential_predicates = tcx.mk_poly_existential_predicates(v.into_iter()); // Use explicitly-specified region bound. let region_bound = if !lifetime.is_elided() { @@ -2331,7 +2331,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn compute_object_lifetime_bound( &self, span: Span, - existential_predicates: ty::Binder<&'tcx ty::List>>, + existential_predicates: &'tcx ty::List>>, ) -> Option> // if None, use the default { let tcx = self.tcx(); diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 7ed2933c08bb..369db87360b1 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -619,8 +619,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)), // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _) => { - for pred in preds.skip_binder() { - match pred { + for pred in preds.iter() { + match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => { bound_spans.push((def_span(tr.def_id), msg.clone())) } @@ -673,9 +673,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .filter_map(|(pred, parent_pred)| { format_pred(*pred).map(|(p, self_ty)| match parent_pred { - None => format!("`{}`", p), + None => format!("`{}`", &p), Some(parent_pred) => match format_pred(*parent_pred) { - None => format!("`{}`", p), + None => format!("`{}`", &p), Some((parent_p, _)) => { collect_type_param_suggestions(self_ty, parent_pred, &p); format!("`{}`\nwhich is required by `{}`", p, parent_p) diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 3a6b64c90e8f..0deaee3a944a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1449,8 +1449,8 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { false }, ty::Dynamic(binder, _) => { - for predicate in binder.skip_binder().iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() { return true; } From 42b267d22137218588d75708ad99a5d9acefa9ab Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Fri, 11 Dec 2020 15:02:46 -0500 Subject: [PATCH 232/719] Move binder for dyn to each list item --- src/value_and_place.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index cb40d4ed9a6d..5bcb11fd515a 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -480,17 +480,19 @@ impl<'tcx> CPlace<'tcx> { // fn(&T) -> for<'l> fn(&'l T) is allowed } (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { - let from_traits = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from_traits); - let to_traits = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_traits); - assert_eq!( - from_traits, to_traits, - "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", - from_traits, to_traits, fx, - ); + for (from, to) in from_traits.iter().zip(to_traits) { + let from = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); + let to = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); + assert_eq!( + from, to, + "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", + from_traits, to_traits, fx, + ); + } // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed } _ => { From 30ef1770d379e5d269d9b311392a012f66648c65 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Fri, 11 Dec 2020 15:02:46 -0500 Subject: [PATCH 233/719] Move binder for dyn to each list item --- clippy_lints/src/utils/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 3a6b64c90e8f..0deaee3a944a 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1449,8 +1449,8 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { false }, ty::Dynamic(binder, _) => { - for predicate in binder.skip_binder().iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() { return true; } From 5c8de1cf4971e5800e2dd33393eef7ad7b8b78be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 11 Dec 2020 17:32:03 +0100 Subject: [PATCH 234/719] use strip_prefix over slicing (clippy::manual_strip) --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 +-- compiler/rustc_llvm/build.rs | 36 ++++++++++---------- src/bootstrap/dist.rs | 2 +- src/librustdoc/html/markdown.rs | 4 +-- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index ec557b7a682e..bf0d499e6c49 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -854,8 +854,8 @@ fn generic_simd_intrinsic( )); } - if name_str.starts_with("simd_shuffle") { - let n: u64 = name_str["simd_shuffle".len()..].parse().unwrap_or_else(|_| { + if let Some(stripped) = name_str.strip_prefix("simd_shuffle") { + let n: u64 = stripped.parse().unwrap_or_else(|_| { span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") }); diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 54b22ca49a29..621363bed80e 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -201,10 +201,10 @@ fn main() { cmd.args(&components); for lib in output(&mut cmd).split_whitespace() { - let name = if lib.starts_with("-l") { - &lib[2..] - } else if lib.starts_with('-') { - &lib[1..] + let name = if let Some(stripped) = lib.strip_prefix("-l") { + stripped + } else if let Some(stripped) = lib.strip_prefix('-') { + stripped } else if Path::new(lib).exists() { // On MSVC llvm-config will print the full name to libraries, but // we're only interested in the name part @@ -241,17 +241,17 @@ fn main() { cmd.arg(llvm_link_arg).arg("--ldflags"); for lib in output(&mut cmd).split_whitespace() { if is_crossed { - if lib.starts_with("-LIBPATH:") { - println!("cargo:rustc-link-search=native={}", lib[9..].replace(&host, &target)); - } else if lib.starts_with("-L") { - println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target)); + if let Some(stripped) = lib.strip_prefix("-LIBPATH:") { + println!("cargo:rustc-link-search=native={}", stripped.replace(&host, &target)); + } else if let Some(stripped) = lib.strip_prefix("-L") { + println!("cargo:rustc-link-search=native={}", stripped.replace(&host, &target)); } - } else if lib.starts_with("-LIBPATH:") { - println!("cargo:rustc-link-search=native={}", &lib[9..]); - } else if lib.starts_with("-l") { - println!("cargo:rustc-link-lib={}", &lib[2..]); - } else if lib.starts_with("-L") { - println!("cargo:rustc-link-search=native={}", &lib[2..]); + } else if let Some(stripped) = lib.strip_prefix("-LIBPATH:") { + println!("cargo:rustc-link-search=native={}", stripped); + } else if let Some(stripped) = lib.strip_prefix("-l") { + println!("cargo:rustc-link-lib={}", stripped); + } else if let Some(stripped) = lib.strip_prefix("-L") { + println!("cargo:rustc-link-search=native={}", stripped); } } @@ -262,10 +262,10 @@ fn main() { let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS"); if let Some(s) = llvm_linker_flags { for lib in s.into_string().unwrap().split_whitespace() { - if lib.starts_with("-l") { - println!("cargo:rustc-link-lib={}", &lib[2..]); - } else if lib.starts_with("-L") { - println!("cargo:rustc-link-search=native={}", &lib[2..]); + if let Some(stripped) = lib.strip_prefix("-l") { + println!("cargo:rustc-link-lib={}", stripped); + } else if let Some(stripped) = lib.strip_prefix("-L") { + println!("cargo:rustc-link-search=native={}", stripped); } } } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 354be109cf2f..360e51ed2bb2 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1186,7 +1186,7 @@ pub fn sanitize_sh(path: &Path) -> String { return change_drive(unc_to_lfs(&path)).unwrap_or(path); fn unc_to_lfs(s: &str) -> &str { - if s.starts_with("//?/") { &s[4..] } else { s } + s.strip_prefix("//?/").unwrap_or(s) } fn change_drive(s: &str) -> Option { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index bdbb90837c7c..22096203d4ce 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -139,9 +139,9 @@ fn map_line(s: &str) -> Line<'_> { let trimmed = s.trim(); if trimmed.starts_with("##") { Line::Shown(Cow::Owned(s.replacen("##", "#", 1))) - } else if trimmed.starts_with("# ") { + } else if let Some(stripped) = trimmed.strip_prefix("# ") { // # text - Line::Hidden(&trimmed[2..]) + Line::Hidden(&stripped) } else if trimmed == "#" { // We cannot handle '#text' because it could be #[attr]. Line::Hidden("") From 82fe5c16622051a71a37c9c4909dd1f4e0857584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 11 Dec 2020 17:40:59 +0100 Subject: [PATCH 235/719] don't convert types into identical types with .into() (clippy::useless_conversion) --- compiler/rustc_mir/src/transform/coverage/debug.rs | 4 ++-- src/librustdoc/passes/collect_intra_doc_links.rs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs index af81d9af0e29..b66e37436a66 100644 --- a/compiler/rustc_mir/src/transform/coverage/debug.rs +++ b/compiler/rustc_mir/src/transform/coverage/debug.rs @@ -285,7 +285,7 @@ impl DebugCounters { ), }; counters - .insert(id.into(), DebugCounter::new(counter_kind.clone(), some_block_label)) + .insert(id, DebugCounter::new(counter_kind.clone(), some_block_label)) .expect_none( "attempt to add the same counter_kind to DebugCounters more than once", ); @@ -340,7 +340,7 @@ impl DebugCounters { if self.some_counters.is_some() && (counter_format.block || !counter_format.id) { let counters = self.some_counters.as_ref().unwrap(); if let Some(DebugCounter { some_block_label: Some(block_label), .. }) = - counters.get(&id.into()) + counters.get(&id) { return if counter_format.id { format!("{}#{}", block_label, id.index()) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5ce64c4cd83c..d8d6f862921e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1012,7 +1012,6 @@ impl LinkCollector<'_, '_> { } else { // This is a bug. debug!("attempting to resolve item without parent module: {}", path_str); - let err_kind = ResolutionFailure::NoParentItem.into(); resolution_failure( self, &item, @@ -1020,7 +1019,7 @@ impl LinkCollector<'_, '_> { disambiguator, dox, link_range, - smallvec![err_kind], + smallvec![ResolutionFailure::NoParentItem], ); return None; }; From db6c50998c929c9bab5ea2ffdddf5e0eef25d3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 11 Dec 2020 17:49:00 +0100 Subject: [PATCH 236/719] don't clone types that are copy (clippy::clone_on_copy) --- compiler/rustc_mir/src/transform/early_otherwise_branch.rs | 2 +- .../rustc_trait_selection/src/traits/select/confirmation.rs | 4 ++-- compiler/rustc_typeck/src/check/upvar.rs | 2 +- src/bootstrap/sanity.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index f91477911a48..0460ebe0c0d5 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -217,7 +217,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { // go through each target, finding a discriminant read, and a switch let results = discr.targets_with_values.iter().map(|(value, target)| { - self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone()) + self.find_discriminant_switch_pairing(&discr, *target, *value) }); // if the optimization did not apply for one of the targets, then abort diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index a42c80213464..ed22d5849e2b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -447,7 +447,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); nested.push(Obligation::new( obligation.cause.clone(), - obligation.param_env.clone(), + obligation.param_env, normalized_super_trait, )); } @@ -485,7 +485,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); nested.push(Obligation::new( obligation.cause.clone(), - obligation.param_env.clone(), + obligation.param_env, normalized_bound, )); } diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 019fa78fb1e0..373f23070192 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -303,7 +303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // upvar_capture_map only stores the UpvarCapture (CaptureKind), // so we create a fake capture info with no expression. let fake_capture_info = - ty::CaptureInfo { expr_id: None, capture_kind: capture_kind.clone() }; + ty::CaptureInfo { expr_id: None, capture_kind: *capture_kind }; determine_capture_info(fake_capture_info, capture_info).capture_kind } else { capture_info.capture_kind diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 4cfcf6ca407b..aafb71629ad7 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -162,7 +162,7 @@ pub fn check(build: &mut Build) { build .config .target_config - .entry(target.clone()) + .entry(*target) .or_insert(Target::from_triple(&target.triple)); if target.contains("-none-") || target.contains("nvptx") { @@ -176,7 +176,7 @@ pub fn check(build: &mut Build) { // If this is a native target (host is also musl) and no musl-root is given, // fall back to the system toolchain in /usr before giving up if build.musl_root(*target).is_none() && build.config.build == *target { - let target = build.config.target_config.entry(target.clone()).or_default(); + let target = build.config.target_config.entry(*target).or_default(); target.musl_root = Some("/usr".into()); } match build.musl_libdir(*target) { From b7795e135a642df024fc9bfee72abf7981c89ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 11 Dec 2020 18:08:05 +0100 Subject: [PATCH 237/719] fix clippy::{needless_bool, manual_unwrap_or} --- .../src/transform/early_otherwise_branch.rs | 7 ++++--- compiler/rustc_session/src/session.rs | 5 +---- compiler/rustc_typeck/src/check/upvar.rs | 21 +++++++++---------- compiler/rustc_typeck/src/collect.rs | 7 +------ src/bootstrap/sanity.rs | 6 +----- 5 files changed, 17 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 0460ebe0c0d5..6fbcc140978a 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -216,9 +216,10 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { let discr = self.find_switch_discriminant_info(bb, switch)?; // go through each target, finding a discriminant read, and a switch - let results = discr.targets_with_values.iter().map(|(value, target)| { - self.find_discriminant_switch_pairing(&discr, *target, *value) - }); + let results = discr + .targets_with_values + .iter() + .map(|(value, target)| self.find_discriminant_switch_pairing(&discr, *target, *value)); // if the optimization did not apply for one of the targets, then abort if results.clone().any(|x| x.is_none()) || results.len() == 0 { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 4e269f3172c2..75faab12e3e1 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1109,10 +1109,7 @@ impl Session { } pub fn link_dead_code(&self) -> bool { - match self.opts.cg.link_dead_code { - Some(explicitly_set) => explicitly_set, - None => false, - } + self.opts.cg.link_dead_code.unwrap_or(false) } pub fn mark_attr_known(&self, attr: &Attribute) { diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 373f23070192..1b04351018a0 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -297,17 +297,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_captures.insert(*var_hir_id, upvar_id); - let new_capture_kind = if let Some(capture_kind) = - upvar_capture_map.get(&upvar_id) - { - // upvar_capture_map only stores the UpvarCapture (CaptureKind), - // so we create a fake capture info with no expression. - let fake_capture_info = - ty::CaptureInfo { expr_id: None, capture_kind: *capture_kind }; - determine_capture_info(fake_capture_info, capture_info).capture_kind - } else { - capture_info.capture_kind - }; + let new_capture_kind = + if let Some(capture_kind) = upvar_capture_map.get(&upvar_id) { + // upvar_capture_map only stores the UpvarCapture (CaptureKind), + // so we create a fake capture info with no expression. + let fake_capture_info = + ty::CaptureInfo { expr_id: None, capture_kind: *capture_kind }; + determine_capture_info(fake_capture_info, capture_info).capture_kind + } else { + capture_info.capture_kind + }; upvar_capture_map.insert(upvar_id, new_capture_kind); } } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 38da1e5ea039..c70554cc6272 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2141,13 +2141,8 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // * It must be an associated type for this trait (*not* a // supertrait). if let ty::Projection(projection) = ty.kind() { - if projection.substs == trait_identity_substs + projection.substs == trait_identity_substs && tcx.associated_item(projection.item_def_id).container.id() == def_id - { - true - } else { - false - } } else { false } diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index aafb71629ad7..85b4a73439d9 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -159,11 +159,7 @@ pub fn check(build: &mut Build) { panic!("the iOS target is only supported on macOS"); } - build - .config - .target_config - .entry(*target) - .or_insert(Target::from_triple(&target.triple)); + build.config.target_config.entry(*target).or_insert(Target::from_triple(&target.triple)); if target.contains("-none-") || target.contains("nvptx") { if build.no_std(*target) == Some(false) { From 5833f74a9cd2316dae030155a36c16bcc7805da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 11 Dec 2020 18:19:51 +0100 Subject: [PATCH 238/719] use if let Some(x) = .. instead of ...map(|x|) to conditionally run fns that return () (clippy::option_map_unit_fn) --- compiler/rustc_mir_build/src/build/scope.rs | 5 ++- .../src/traits/error_reporting/suggestions.rs | 41 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index e137f77ffbb0..0edd44d4bf1e 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -616,8 +616,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("stmt_expr Break val block_context.push(SubExpr)"); self.block_context.push(BlockFrame::SubExpr); unpack!(block = self.into(destination, dest_scope, block, value)); - dest_scope - .map(|scope| self.unschedule_drop(scope, destination.as_local().unwrap())); + if let Some(scope) = dest_scope { + self.unschedule_drop(scope, destination.as_local().unwrap()) + }; self.block_context.pop(); } else { self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx()) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 095483aa5a25..5c185dc4a9f1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1448,31 +1448,30 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); }; - typeck_results + if let Some(cause) = typeck_results .generator_interior_types .iter() .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty_matches(ty)) - .map(|cause| { - // Check to see if any awaited expressions have the target type. - let from_awaited_ty = visitor - .awaits - .into_iter() - .map(|id| hir.expect_expr(id)) - .find(|await_expr| { - let ty = typeck_results.expr_ty_adjusted(&await_expr); - debug!( - "maybe_note_obligation_cause_for_async_await: await_expr={:?}", - await_expr - ); - ty_matches(ty) - }) - .map(|expr| expr.span); - let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = - cause; + { + // Check to see if any awaited expressions have the target type. + let from_awaited_ty = visitor + .awaits + .into_iter() + .map(|id| hir.expect_expr(id)) + .find(|await_expr| { + let ty = typeck_results.expr_ty_adjusted(&await_expr); + debug!( + "maybe_note_obligation_cause_for_async_await: await_expr={:?}", + await_expr + ); + ty_matches(ty) + }) + .map(|expr| expr.span); + let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause; - interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span)); - interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty)); - }); + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span)); + interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty)); + }; debug!( "maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \ From cf10a0abf23850018b32ed9a15b1bce6a1e71c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 11 Dec 2020 19:13:16 +0100 Subject: [PATCH 239/719] fix clippy::unnecessary_filter_map --- compiler/rustc_builtin_macros/src/deriving/generic/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index a767de53dae1..68c11868af88 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -597,10 +597,7 @@ impl<'a> TraitDef<'a> { let mut ty_params = params .iter() - .filter_map(|param| match param.kind { - ast::GenericParamKind::Type { .. } => Some(param), - _ => None, - }) + .filter(|param| matches!(param.kind, ast::GenericParamKind::Type{..})) .peekable(); if ty_params.peek().is_some() { From 0b145d688b293a92cd855000f249d83acae53f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 12 Dec 2020 01:09:30 +0100 Subject: [PATCH 240/719] clone_double_ref: print reference type in lint message changelog: clone_double_ref: print the type of the reference in lint message --- clippy_lints/src/methods/mod.rs | 7 +++++-- tests/ui/unnecessary_clone.stderr | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5133f31e0e7b..ce234e01a1bb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2100,8 +2100,11 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp cx, CLONE_DOUBLE_REF, expr.span, - "using `clone` on a double-reference; \ - this will copy the reference instead of cloning the inner type", + &format!( + "using `clone` on a double-reference; \ + this will copy the reference of type `{}` instead of cloning the inner type", + ty + ), |diag| { if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { let mut ty = innermost; diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 5ffa6c4fd061..b908d0ce9c16 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -44,7 +44,7 @@ error: using `clone` on a `Copy` type LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` -error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type +error: using `clone` on a double-reference; this will copy the reference of type `&std::vec::Vec` instead of cloning the inner type --> $DIR/unnecessary_clone.rs:48:22 | LL | let z: &Vec<_> = y.clone(); @@ -66,7 +66,7 @@ error: using `clone` on a `Copy` type LL | let _: E = a.clone(); | ^^^^^^^^^ help: try dereferencing it: `*****a` -error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type +error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type --> $DIR/unnecessary_clone.rs:89:22 | LL | let _ = &mut encoded.clone(); @@ -81,7 +81,7 @@ help: or try being explicit if you are sure, that you want to clone a reference LL | let _ = &mut <&[u8]>::clone(encoded); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type +error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type --> $DIR/unnecessary_clone.rs:90:18 | LL | let _ = &encoded.clone(); From b2cb6ffbe3735ef8f137c9a6c1290c4a078793ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 12 Dec 2020 01:23:28 +0100 Subject: [PATCH 241/719] clone_on_copy: show the type in the lint message changelog: clone_on_copy: show the type in the lint message --- clippy_lints/src/methods/mod.rs | 16 +++++++++++----- tests/ui/clone_on_copy.stderr | 10 +++++----- tests/ui/unnecessary_clone.stderr | 6 +++--- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5133f31e0e7b..03eaee35fc4f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2174,11 +2174,17 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp } else { snip = None; } - span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| { - if let Some((text, snip)) = snip { - diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable); - } - }); + span_lint_and_then( + cx, + CLONE_ON_COPY, + expr.span, + &format!("using `clone` on type `{}` which implements the `Copy` trait", ty), + |diag| { + if let Some((text, snip)) = snip { + diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable); + } + }, + ); } } diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index ec2faf4ab40d..14a700886a7b 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -1,4 +1,4 @@ -error: using `clone` on a `Copy` type +error: using `clone` on type `i32` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:22:5 | LL | 42.clone(); @@ -6,25 +6,25 @@ LL | 42.clone(); | = note: `-D clippy::clone-on-copy` implied by `-D warnings` -error: using `clone` on a `Copy` type +error: using `clone` on type `i32` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:26:5 | LL | (&42).clone(); | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` -error: using `clone` on a `Copy` type +error: using `clone` on type `i32` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:29:5 | LL | rc.borrow().clone(); | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` -error: using `clone` on a `Copy` type +error: using `clone` on type `char` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:35:14 | LL | is_ascii('z'.clone()); | ^^^^^^^^^^^ help: try removing the `clone` call: `'z'` -error: using `clone` on a `Copy` type +error: using `clone` on type `i32` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:39:14 | LL | vec.push(42.clone()); diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 5ffa6c4fd061..bb2dd998f271 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -30,7 +30,7 @@ error: using `.clone()` on a ref-counted pointer LL | let _: Arc = x.clone(); | ^^^^^^^^^ help: try this: `Arc::::clone(&x)` -error: using `clone` on a `Copy` type +error: using `clone` on type `T` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:40:5 | LL | t.clone(); @@ -38,7 +38,7 @@ LL | t.clone(); | = note: `-D clippy::clone-on-copy` implied by `-D warnings` -error: using `clone` on a `Copy` type +error: using `clone` on type `std::option::Option` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:42:5 | LL | Some(t).clone(); @@ -60,7 +60,7 @@ help: or try being explicit if you are sure, that you want to clone a reference LL | let z: &Vec<_> = <&std::vec::Vec>::clone(y); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: using `clone` on a `Copy` type +error: using `clone` on type `many_derefs::E` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:84:20 | LL | let _: E = a.clone(); From af6aa9f4313983deddd64543c5ad6c15e2160163 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Dec 2020 22:36:51 -0500 Subject: [PATCH 242/719] Pass Session into renderer --- src/librustdoc/formats/renderer.rs | 6 +++++- src/librustdoc/html/render/mod.rs | 5 +++++ src/librustdoc/json/mod.rs | 3 +++ src/librustdoc/lib.rs | 11 ++++++++--- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index d0fdc69cc193..6334524eb1ca 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use rustc_data_structures::sync::Lrc; +use rustc_session::Session; use rustc_span::edition::Edition; use crate::clean; @@ -19,6 +21,7 @@ crate trait FormatRenderer: Clone { render_info: RenderInfo, edition: Edition, cache: &mut Cache, + sess: Lrc, ) -> Result<(Self, clean::Crate), Error>; /// Renders a single non-module item. This means no recursive sub-item rendering is required. @@ -49,6 +52,7 @@ crate fn run_format( render_info: RenderInfo, diag: &rustc_errors::Handler, edition: Edition, + sess: Lrc, ) -> Result<(), Error> { let (krate, mut cache) = Cache::from_krate( render_info.clone(), @@ -59,7 +63,7 @@ crate fn run_format( ); let (mut format_renderer, mut krate) = - T::init(krate, options, render_info, edition, &mut cache)?; + T::init(krate, options, render_info, edition, &mut cache, sess)?; let cache = Arc::new(cache); // Freeze the cache now that the index has been built. Put an Arc into TLS for future diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 901f00b21da9..ff8fd208eea4 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -52,10 +52,12 @@ use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::Mutability; use rustc_middle::middle::stability; +use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::FileName; @@ -101,6 +103,7 @@ crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { /// rustdoc tree). #[derive(Clone)] crate struct Context { + crate sess: Lrc, /// Current hierarchy of components leading down to what's currently being /// rendered crate current: Vec, @@ -383,6 +386,7 @@ impl FormatRenderer for Context { _render_info: RenderInfo, edition: Edition, cache: &mut Cache, + sess: Lrc, ) -> Result<(Context, clean::Crate), Error> { // need to save a copy of the options for rendering the index page let md_opts = options.clone(); @@ -494,6 +498,7 @@ impl FormatRenderer for Context { let cache = Arc::new(cache); let mut cx = Context { + sess, current: Vec::new(), dst, render_redirect_pages: false, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 5f640bfddf10..884c4c725330 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -13,6 +13,8 @@ use std::path::PathBuf; use std::rc::Rc; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lrc; +use rustc_session::Session; use rustc_span::edition::Edition; use crate::clean; @@ -124,6 +126,7 @@ impl FormatRenderer for JsonRenderer { _render_info: RenderInfo, _edition: Edition, _cache: &mut Cache, + _sess: Lrc, ) -> Result<(Self, clean::Crate), Error> { debug!("Initializing json renderer"); Ok(( diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 26bf4b569ff4..fbab5735ee7a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -61,9 +61,11 @@ use std::default::Default; use std::env; use std::process; +use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; use rustc_session::getopts; +use rustc_session::Session; use rustc_session::{early_error, early_warn}; #[macro_use] @@ -483,8 +485,9 @@ fn run_renderer( render_info: config::RenderInfo, diag: &rustc_errors::Handler, edition: rustc_span::edition::Edition, + sess: Lrc, ) -> MainResult { - match formats::run_format::(krate, renderopts, render_info, &diag, edition) { + match formats::run_format::(krate, renderopts, render_info, &diag, edition, sess) { Ok(_) => Ok(()), Err(e) => { let mut msg = diag.struct_err(&format!("couldn't generate documentation: {}", e.error)); @@ -554,10 +557,12 @@ fn main_options(options: config::Options) -> MainResult { let diag = core::new_handler(error_format, None, &debugging_options); match output_format { None | Some(config::OutputFormat::Html) => sess.time("render_html", || { - run_renderer::(krate, renderopts, renderinfo, &diag, edition) + run_renderer::( + krate, renderopts, renderinfo, &diag, edition, sess, + ) }), Some(config::OutputFormat::Json) => sess.time("render_json", || { - run_renderer::(krate, renderopts, renderinfo, &diag, edition) + run_renderer::(krate, renderopts, renderinfo, &diag, edition, sess) }), } } From 4fa95b3a078f261267293f3308dd62889167c0bd Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Dec 2020 23:01:26 -0500 Subject: [PATCH 243/719] Calculate span info on-demand instead of ahead of time This should *vastly* reduce memory usage. --- src/librustdoc/clean/mod.rs | 24 ++--------- src/librustdoc/clean/types.rs | 41 +++++++++++-------- src/librustdoc/html/render/mod.rs | 25 ++++++----- src/librustdoc/html/sources.rs | 17 ++++++-- src/librustdoc/json/conversions.rs | 11 +++-- src/librustdoc/lib.rs | 5 ++- .../passes/calculate_doc_coverage.rs | 15 +++---- 7 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 16274430902e..a21e9d9820cb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -25,7 +25,7 @@ use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{self, ExpnKind, Pos}; +use rustc_span::{self, ExpnKind}; use rustc_typeck::hir_ty_to_ty; use std::collections::hash_map::Entry; @@ -1881,29 +1881,11 @@ impl Clean for hir::VariantData<'_> { } impl Clean for rustc_span::Span { - fn clean(&self, cx: &DocContext<'_>) -> Span { - if self.is_dummy() { - return Span::empty(); - } - + fn clean(&self, _cx: &DocContext<'_>) -> Span { // Get the macro invocation instead of the definition, // in case the span is result of a macro expansion. // (See rust-lang/rust#39726) - let span = self.source_callsite(); - - let sm = cx.sess().source_map(); - let filename = sm.span_to_filename(span); - let lo = sm.lookup_char_pos(span.lo()); - let hi = sm.lookup_char_pos(span.hi()); - Span { - filename, - cnum: lo.file.cnum, - loline: lo.line, - locol: lo.col.to_usize(), - hiline: hi.line, - hicol: hi.col.to_usize(), - original: span, - } + Span { original: self.source_callsite() } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index d4796b7ed66c..a8626af8832f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -17,15 +17,16 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::Mutability; use rustc_index::vec::IndexVec; use rustc_middle::ty::{AssocKind, TyCtxt}; +use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, sym, Ident, Symbol, SymbolStr}; -use rustc_span::{self, FileName}; +use rustc_span::{self, FileName, Loc}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use smallvec::{smallvec, SmallVec}; @@ -1609,33 +1610,37 @@ crate enum VariantKind { Struct(VariantStruct), } +/// Small wrapper around `rustc_span::Span` that adds helper methods. #[derive(Clone, Debug)] crate struct Span { - crate filename: FileName, - crate cnum: CrateNum, - crate loline: usize, - crate locol: usize, - crate hiline: usize, - crate hicol: usize, crate original: rustc_span::Span, } impl Span { - crate fn empty() -> Span { - Span { - filename: FileName::Anon(0), - cnum: LOCAL_CRATE, - loline: 0, - locol: 0, - hiline: 0, - hicol: 0, - original: rustc_span::DUMMY_SP, - } + crate fn empty() -> Self { + Self { original: rustc_span::DUMMY_SP } } crate fn span(&self) -> rustc_span::Span { self.original } + + crate fn filename(&self, sess: &Session) -> FileName { + sess.source_map().span_to_filename(self.original) + } + + crate fn lo(&self, sess: &Session) -> Loc { + sess.source_map().lookup_char_pos(self.original.lo()) + } + + crate fn hi(&self, sess: &Session) -> Loc { + sess.source_map().lookup_char_pos(self.original.hi()) + } + + crate fn cnum(&self, sess: &Session) -> CrateNum { + // FIXME: is there a time when the lo and hi crate would be different? + self.lo(sess).file.cnum + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index ff8fd208eea4..b91f1a6c0e3a 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -103,7 +103,6 @@ crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { /// rustdoc tree). #[derive(Clone)] crate struct Context { - crate sess: Lrc, /// Current hierarchy of components leading down to what's currently being /// rendered crate current: Vec, @@ -124,6 +123,7 @@ crate struct Context { } crate struct SharedContext { + crate sess: Lrc, /// The path to the crate root source minus the file name. /// Used for simplifying paths to the highlighted source code files. crate src_root: PathBuf, @@ -176,6 +176,10 @@ impl Context { let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext,); self.dst.join(&filename) } + + fn sess(&self) -> &Session { + &self.shared.sess + } } impl SharedContext { @@ -459,6 +463,7 @@ impl FormatRenderer for Context { } let (sender, receiver) = channel(); let mut scx = SharedContext { + sess, collapsed: krate.collapsed, src_root, include_sources, @@ -498,7 +503,6 @@ impl FormatRenderer for Context { let cache = Arc::new(cache); let mut cx = Context { - sess, current: Vec::new(), dst, render_redirect_pages: false, @@ -1636,24 +1640,24 @@ impl Context { /// of their crate documentation isn't known. fn src_href(&self, item: &clean::Item, cache: &Cache) -> Option { let mut root = self.root_path(); - let mut path = String::new(); + let cnum = item.source.cnum(self.sess()); // We can safely ignore synthetic `SourceFile`s. - let file = match item.source.filename { + let file = match item.source.filename(self.sess()) { FileName::Real(ref path) => path.local_path().to_path_buf(), _ => return None, }; let file = &file; - let (krate, path) = if item.source.cnum == LOCAL_CRATE { + let (krate, path) = if cnum == LOCAL_CRATE { if let Some(path) = self.shared.local_sources.get(file) { (&self.shared.layout.krate, path) } else { return None; } } else { - let (krate, src_root) = match *cache.extern_locations.get(&item.source.cnum)? { + let (krate, src_root) = match *cache.extern_locations.get(&cnum)? { (ref name, ref src, ExternalLocation::Local) => (name, src), (ref name, ref src, ExternalLocation::Remote(ref s)) => { root = s.to_string(); @@ -1672,11 +1676,10 @@ impl Context { (krate, &path) }; - let lines = if item.source.loline == item.source.hiline { - item.source.loline.to_string() - } else { - format!("{}-{}", item.source.loline, item.source.hiline) - }; + let loline = item.source.lo(self.sess()).line; + let hiline = item.source.hi(self.sess()).line; + let lines = + if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) }; Some(format!( "{root}src/{krate}/{path}#{lines}", root = Escape(&root), diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index e7b5a90d84df..ef9e9f350fb8 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -7,6 +7,7 @@ use crate::html::highlight; use crate::html::layout; use crate::html::render::{SharedContext, BASIC_KEYWORDS}; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_session::Session; use rustc_span::source_map::FileName; use std::ffi::OsStr; use std::fs; @@ -34,37 +35,45 @@ struct SourceCollector<'a> { impl<'a> DocFolder for SourceCollector<'a> { fn fold_item(&mut self, item: clean::Item) -> Option { + // If we're not rendering sources, there's nothing to do. // If we're including source files, and we haven't seen this file yet, // then we need to render it out to the filesystem. if self.scx.include_sources // skip all synthetic "files" - && item.source.filename.is_real() + && item.source.filename(self.sess()).is_real() // skip non-local files - && item.source.cnum == LOCAL_CRATE + && item.source.cnum(self.sess()) == LOCAL_CRATE { + let filename = item.source.filename(self.sess()); // If it turns out that we couldn't read this file, then we probably // can't read any of the files (generating html output from json or // something like that), so just don't include sources for the // entire crate. The other option is maintaining this mapping on a // per-file basis, but that's probably not worth it... - self.scx.include_sources = match self.emit_source(&item.source.filename) { + self.scx.include_sources = match self.emit_source(&filename) { Ok(()) => true, Err(e) => { println!( "warning: source code was requested to be rendered, \ but processing `{}` had an error: {}", - item.source.filename, e + filename, e ); println!(" skipping rendering of source code"); false } }; } + // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value, + // we could return None here without having to walk the rest of the crate. Some(self.fold_item_recur(item)) } } impl<'a> SourceCollector<'a> { + fn sess(&self) -> &Session { + &self.scx.sess + } + /// Renders the given filename into its corresponding HTML source file. fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> { let p = match *filename { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index afb8dfa67665..9ae0a16ac35c 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -56,9 +56,12 @@ impl From for Option { } impl From for Option { + #[allow(unreachable_code)] fn from(span: clean::Span) -> Self { - let clean::Span { loline, locol, hiline, hicol, .. } = span; - match span.filename { + // TODO: this should actually work + // Unfortunately this requires rethinking the whole framework, + // since this now needs a context and not just .into(). + match span.filename(todo!()) { rustc_span::FileName::Real(name) => Some(Span { filename: match name { rustc_span::RealFileName::Named(path) => path, @@ -66,8 +69,8 @@ impl From for Option { local_path } }, - begin: (loline, locol), - end: (hiline, hicol), + begin: todo!(), + end: todo!(), }), _ => None, } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index fbab5735ee7a..e094ead12bd0 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -555,13 +555,14 @@ fn main_options(options: config::Options) -> MainResult { info!("going to format"); let (error_format, edition, debugging_options) = diag_opts; let diag = core::new_handler(error_format, None, &debugging_options); + let sess_time = sess.clone(); match output_format { - None | Some(config::OutputFormat::Html) => sess.time("render_html", || { + None | Some(config::OutputFormat::Html) => sess_time.time("render_html", || { run_renderer::( krate, renderopts, renderinfo, &diag, edition, sess, ) }), - Some(config::OutputFormat::Json) => sess.time("render_json", || { + Some(config::OutputFormat::Json) => sess_time.time("render_json", || { run_renderer::(krate, renderopts, renderinfo, &diag, edition, sess) }), } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 3f9978c8fca8..52f6a97089bd 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -216,13 +216,9 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { return Some(i); } clean::ImplItem(ref impl_) => { + let filename = i.source.filename(self.ctx.sess()); if let Some(ref tr) = impl_.trait_ { - debug!( - "impl {:#} for {:#} in {}", - tr.print(), - impl_.for_.print(), - i.source.filename - ); + debug!("impl {:#} for {:#} in {}", tr.print(), impl_.for_.print(), filename,); // don't count trait impls, the missing-docs lint doesn't so we shouldn't // either @@ -231,7 +227,7 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { // inherent impls *can* be documented, and those docs show up, but in most // cases it doesn't make sense, as all methods on a type are in one single // impl block - debug!("impl {:#} in {}", impl_.for_.print(), i.source.filename); + debug!("impl {:#} in {}", impl_.for_.print(), filename); } } _ => { @@ -251,6 +247,7 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { None, ); + let filename = i.source.filename(self.ctx.sess()); let has_doc_example = tests.found_tests != 0; let hir_id = self.ctx.tcx.hir().local_def_id_to_hir_id(i.def_id.expect_local()); let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id); @@ -258,8 +255,8 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { // unless the user had an explicit `allow` let should_have_docs = level != lint::Level::Allow || matches!(source, LintSource::Default); - debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename); - self.items.entry(i.source.filename.clone()).or_default().count_item( + debug!("counting {:?} {:?} in {}", i.type_(), i.name, filename); + self.items.entry(filename).or_default().count_item( has_docs, has_doc_example, should_have_doc_example(self.ctx, &i), From 0e574fb39ad99a7ffbfd7f2d52603d890dfa2084 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Dec 2020 23:57:18 -0500 Subject: [PATCH 244/719] Fix the JSON backend This was simpler than expected. --- src/librustdoc/json/conversions.rs | 42 +++++++++++++++--------------- src/librustdoc/json/mod.rs | 6 +++-- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 9ae0a16ac35c..c463481db86d 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -6,14 +6,16 @@ use std::convert::From; use rustc_ast::ast; use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_span::Pos; use crate::clean; use crate::doctree; use crate::formats::item_type::ItemType; use crate::json::types::*; +use crate::json::JsonRenderer; -impl From for Option { - fn from(item: clean::Item) -> Self { +impl JsonRenderer { + pub(super) fn convert_item(&self, item: clean::Item) -> Option { let item_type = ItemType::from(&item); let clean::Item { source, @@ -32,7 +34,7 @@ impl From for Option { id: def_id.into(), crate_id: def_id.krate.as_u32(), name, - source: source.into(), + source: self.convert_span(source), visibility: visibility.into(), docs: attrs.collapsed_doc_value().unwrap_or_default(), links: attrs @@ -53,25 +55,23 @@ impl From for Option { }), } } -} -impl From for Option { - #[allow(unreachable_code)] - fn from(span: clean::Span) -> Self { - // TODO: this should actually work - // Unfortunately this requires rethinking the whole framework, - // since this now needs a context and not just .into(). - match span.filename(todo!()) { - rustc_span::FileName::Real(name) => Some(Span { - filename: match name { - rustc_span::RealFileName::Named(path) => path, - rustc_span::RealFileName::Devirtualized { local_path, virtual_name: _ } => { - local_path - } - }, - begin: todo!(), - end: todo!(), - }), + fn convert_span(&self, span: clean::Span) -> Option { + match span.filename(&self.sess) { + rustc_span::FileName::Real(name) => { + let hi = span.hi(&self.sess); + let lo = span.lo(&self.sess); + Some(Span { + filename: match name { + rustc_span::RealFileName::Named(path) => path, + rustc_span::RealFileName::Devirtualized { local_path, virtual_name: _ } => { + local_path + } + }, + begin: (lo.line, lo.col.to_usize()), + end: (hi.line, hi.col.to_usize()), + }) + } _ => None, } } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 884c4c725330..5c5239d1b6a2 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -26,6 +26,7 @@ use crate::html::render::cache::ExternalLocation; #[derive(Clone)] crate struct JsonRenderer { + sess: Lrc, /// A mapping of IDs that contains all local items for this crate which gets output as a top /// level field of the JSON blob. index: Rc>>, @@ -126,11 +127,12 @@ impl FormatRenderer for JsonRenderer { _render_info: RenderInfo, _edition: Edition, _cache: &mut Cache, - _sess: Lrc, + sess: Lrc, ) -> Result<(Self, clean::Crate), Error> { debug!("Initializing json renderer"); Ok(( JsonRenderer { + sess, index: Rc::new(RefCell::new(FxHashMap::default())), out_path: options.output, }, @@ -146,7 +148,7 @@ impl FormatRenderer for JsonRenderer { item.kind.inner_items().for_each(|i| self.item(i.clone(), cache).unwrap()); let id = item.def_id; - if let Some(mut new_item) = item.into(): Option { + if let Some(mut new_item) = self.convert_item(item) { if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner { t.implementors = self.get_trait_implementors(id, cache) } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner { From eb963ffe451bfbc001ea86712a94619903bfbaf8 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Fri, 11 Dec 2020 18:28:37 -0800 Subject: [PATCH 245/719] Fixes reported bugs in Rust Coverage Fixes: #79569 Fixes: #79566 Fixes: #79565 For the first issue (#79569), I got hit a `debug_assert!()` before encountering the reported error message (because I have `debug = true` enabled in my config.toml). The assertion showed me that some `SwitchInt`s can have more than one target pointing to the same `BasicBlock`. I had thought that was invalid, but since it seems to be possible, I'm allowing this now. I added a new test for this. ---- In the last two cases above, both tests (intentionally) fail to compile, but the `InstrumentCoverage` pass is invoked anyway. The MIR starts with an `Unreachable` `BasicBlock`, which I hadn't encountered before. (I had assumed the `InstrumentCoverage` pass would only be invoked with MIRs from successful compilations.) I don't have test infrastructure set up to test coverage on files that fail to compile, so I didn't add a new test. --- .../rustc_mir/src/transform/coverage/graph.rs | 28 +- .../rustc_mir/src/transform/coverage/mod.rs | 8 + ...cted_export_coverage.match_or_pattern.json | 59 ++++ ...xpected_show_coverage.match_or_pattern.txt | 50 ++++ .../expected_show_coverage_counters.async.txt | 12 +- ...how_coverage_counters.match_or_pattern.txt | 98 +++++++ ...ern.main.-------.InstrumentCoverage.0.html | 271 ++++++++++++++++++ .../coverage/match_or_pattern.rs | 45 +++ 8 files changed, 553 insertions(+), 18 deletions(-) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage/match_or_pattern.rs diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs index 2408a999c05a..b1a1bb957e79 100644 --- a/compiler/rustc_mir/src/transform/coverage/graph.rs +++ b/compiler/rustc_mir/src/transform/coverage/graph.rs @@ -32,24 +32,28 @@ impl CoverageGraph { // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock // equivalents. Note that since the BasicCoverageBlock graph has been fully simplified, the - // each predecessor of a BCB leader_bb should be in a unique BCB, and each successor of a - // BCB last_bb should be in its own unique BCB. Therefore, collecting the BCBs using - // `bb_to_bcb` should work without requiring a deduplication step. + // each predecessor of a BCB leader_bb should be in a unique BCB. It is possible for a + // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so + // de-duplication is required. This is done without reordering the successors. + let bcbs_len = bcbs.len(); + let mut seen = IndexVec::from_elem_n(false, bcbs_len); let successors = IndexVec::from_fn_n( |bcb| { + for b in seen.iter_mut() { + *b = false; + } let bcb_data = &bcbs[bcb]; - let bcb_successors = + let mut bcb_successors = Vec::new(); + for successor in bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind) .filter_map(|&successor_bb| bb_to_bcb[successor_bb]) - .collect::>(); - debug_assert!({ - let mut sorted = bcb_successors.clone(); - sorted.sort_unstable(); - let initial_len = sorted.len(); - sorted.dedup(); - sorted.len() == initial_len - }); + { + if !seen[successor] { + seen[successor] = true; + bcb_successors.push(successor); + } + } bcb_successors }, bcbs.len(), diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index f69748db238c..53f7c28ee35b 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -78,6 +78,14 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { return; } + match mir_body.basic_blocks()[mir::START_BLOCK].terminator().kind { + TerminatorKind::Unreachable => { + trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`"); + return; + } + _ => {} + } + trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); Instrumentor::new(&self.name(), tcx, mir_body).inject_counters(); trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json new file mode 100644 index 000000000000..8559fc84aa93 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/match_or_pattern.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 37, + "covered": 33, + "percent": 89.1891891891892 + }, + "regions": { + "count": 25, + "covered": 17, + "notcovered": 8, + "percent": 68 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 37, + "covered": 33, + "percent": 89.1891891891892 + }, + "regions": { + "count": 25, + "covered": 17, + "notcovered": 8, + "percent": 68 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt new file mode 100644 index 000000000000..a0fccb24f998 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt @@ -0,0 +1,50 @@ + 1| |#![feature(or_patterns)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut a: u8 = 0; + 10| 1| let mut b: u8 = 0; + 11| 1| if is_true { + 12| 1| a = 2; + 13| 1| b = 0; + 14| 1| } + ^0 + 15| 1| match (a, b) { + 16| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + 17| | // This test confirms a fix for Issue #79569. + 18| 0| (0 | 1, 2 | 3) => {} + 19| 1| _ => {} + 20| | } + 21| 1| if is_true { + 22| 1| a = 0; + 23| 1| b = 0; + 24| 1| } + ^0 + 25| 1| match (a, b) { + 26| 0| (0 | 1, 2 | 3) => {} + 27| 1| _ => {} + 28| | } + 29| 1| if is_true { + 30| 1| a = 2; + 31| 1| b = 2; + 32| 1| } + ^0 + 33| 1| match (a, b) { + 34| 0| (0 | 1, 2 | 3) => {} + 35| 1| _ => {} + 36| | } + 37| 1| if is_true { + 38| 1| a = 0; + 39| 1| b = 2; + 40| 1| } + ^0 + 41| 1| match (a, b) { + 42| 1| (0 | 1, 2 | 3) => {} + 43| 0| _ => {} + 44| | } + 45| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt index ed91e8898ee9..4df0bac8c866 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt @@ -28,11 +28,8 @@ Counter in file 0 79:14 -> 79:16, 0 Counter in file 0 81:1 -> 81:2, 0 Counter in file 0 91:25 -> 91:34, 0 Counter in file 0 5:1 -> 5:25, #1 -Counter in file 0 5:25 -> 6:14, #1 -Counter in file 0 7:9 -> 7:10, #2 -Counter in file 0 9:9 -> 9:10, (#1 - #2) -Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) Counter in file 0 21:1 -> 21:23, #1 +Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 67:5 -> 67:23, #1 Counter in file 0 38:1 -> 38:19, #1 Counter in file 0 38:19 -> 42:12, #1 @@ -46,14 +43,18 @@ Counter in file 0 44:27 -> 44:32, #8 Counter in file 0 44:36 -> 44:38, (#6 + 0) Counter in file 0 45:14 -> 45:16, #7 Counter in file 0 47:1 -> 47:2, (#5 + (#6 + #7)) +Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 29:1 -> 29:22, #1 Counter in file 0 93:1 -> 101:2, #1 Counter in file 0 91:1 -> 91:25, #1 +Counter in file 0 5:25 -> 6:14, #1 +Counter in file 0 7:9 -> 7:10, #2 +Counter in file 0 9:9 -> 9:10, (#1 - #2) +Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) Counter in file 0 51:5 -> 52:18, #1 Counter in file 0 53:13 -> 53:14, #2 Counter in file 0 63:13 -> 63:14, (#1 - #2) Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2)) -Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 49:1 -> 68:12, #1 Counter in file 0 69:9 -> 69:10, #2 Counter in file 0 69:14 -> 69:27, (#1 + 0) @@ -70,7 +71,6 @@ Counter in file 0 87:14 -> 87:16, #3 Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2)))) Counter in file 0 17:1 -> 17:20, #1 Counter in file 0 66:5 -> 66:23, #1 -Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 117:17 -> 117:19, #1 diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt new file mode 100644 index 000000000000..fc12612ce7d7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt @@ -0,0 +1,98 @@ +Counter in file 0 3:1 -> 11:15, #1 +Counter in file 0 11:16 -> 14:6, #2 +Counter in file 0 14:6 -> 14:7, (#1 - #2) +Counter in file 0 15:11 -> 15:17, (#2 + (#1 - #2)) +Counter in file 0 18:27 -> 18:29, #5 +Counter in file 0 19:14 -> 19:16, (#3 + #4) +Counter in file 0 21:8 -> 21:15, ((#3 + #4) + #5) +Counter in file 0 21:16 -> 24:6, #6 +Counter in file 0 24:6 -> 24:7, (((#3 + #4) + #5) - #6) +Counter in file 0 25:11 -> 25:17, (#6 + (((#3 + #4) + #5) - #6)) +Counter in file 0 26:27 -> 26:29, #9 +Counter in file 0 27:14 -> 27:16, (#7 + #8) +Counter in file 0 29:8 -> 29:15, ((#7 + #8) + #9) +Counter in file 0 29:16 -> 32:6, #10 +Counter in file 0 32:6 -> 32:7, (((#7 + #8) + #9) - #10) +Counter in file 0 33:11 -> 33:17, (#10 + (((#7 + #8) + #9) - #10)) +Counter in file 0 34:27 -> 34:29, #13 +Counter in file 0 35:14 -> 35:16, (#11 + #12) +Counter in file 0 37:8 -> 37:15, ((#11 + #12) + #13) +Counter in file 0 37:16 -> 40:6, #14 +Counter in file 0 40:6 -> 40:7, (((#11 + #12) + #13) - #14) +Counter in file 0 41:11 -> 41:17, (#14 + (((#11 + #12) + #13) - #14)) +Counter in file 0 42:27 -> 42:29, #17 +Counter in file 0 43:14 -> 43:16, (#15 + #16) +Counter in file 0 45:1 -> 45:2, ((#15 + #16) + #17) +Emitting segments for file: ../coverage/match_or_pattern.rs +Combined regions: + 3:1 -> 11:15 (count=1) + 11:16 -> 14:6 (count=1) + 14:6 -> 14:7 (count=0) + 15:11 -> 15:17 (count=1) + 18:27 -> 18:29 (count=0) + 19:14 -> 19:16 (count=1) + 21:8 -> 21:15 (count=1) + 21:16 -> 24:6 (count=1) + 24:6 -> 24:7 (count=0) + 25:11 -> 25:17 (count=1) + 26:27 -> 26:29 (count=0) + 27:14 -> 27:16 (count=1) + 29:8 -> 29:15 (count=1) + 29:16 -> 32:6 (count=1) + 32:6 -> 32:7 (count=0) + 33:11 -> 33:17 (count=1) + 34:27 -> 34:29 (count=0) + 35:14 -> 35:16 (count=1) + 37:8 -> 37:15 (count=1) + 37:16 -> 40:6 (count=1) + 40:6 -> 40:7 (count=0) + 41:11 -> 41:17 (count=1) + 42:27 -> 42:29 (count=1) + 43:14 -> 43:16 (count=0) + 45:1 -> 45:2 (count=1) +Segment at 3:1 (count = 1), RegionEntry +Segment at 11:15 (count = 0), Skipped +Segment at 11:16 (count = 1), RegionEntry +Segment at 14:6 (count = 0), RegionEntry +Segment at 14:7 (count = 0), Skipped +Segment at 15:11 (count = 1), RegionEntry +Segment at 15:17 (count = 0), Skipped +Segment at 18:27 (count = 0), RegionEntry +Segment at 18:29 (count = 0), Skipped +Segment at 19:14 (count = 1), RegionEntry +Segment at 19:16 (count = 0), Skipped +Segment at 21:8 (count = 1), RegionEntry +Segment at 21:15 (count = 0), Skipped +Segment at 21:16 (count = 1), RegionEntry +Segment at 24:6 (count = 0), RegionEntry +Segment at 24:7 (count = 0), Skipped +Segment at 25:11 (count = 1), RegionEntry +Segment at 25:17 (count = 0), Skipped +Segment at 26:27 (count = 0), RegionEntry +Segment at 26:29 (count = 0), Skipped +Segment at 27:14 (count = 1), RegionEntry +Segment at 27:16 (count = 0), Skipped +Segment at 29:8 (count = 1), RegionEntry +Segment at 29:15 (count = 0), Skipped +Segment at 29:16 (count = 1), RegionEntry +Segment at 32:6 (count = 0), RegionEntry +Segment at 32:7 (count = 0), Skipped +Segment at 33:11 (count = 1), RegionEntry +Segment at 33:17 (count = 0), Skipped +Segment at 34:27 (count = 0), RegionEntry +Segment at 34:29 (count = 0), Skipped +Segment at 35:14 (count = 1), RegionEntry +Segment at 35:16 (count = 0), Skipped +Segment at 37:8 (count = 1), RegionEntry +Segment at 37:15 (count = 0), Skipped +Segment at 37:16 (count = 1), RegionEntry +Segment at 40:6 (count = 0), RegionEntry +Segment at 40:7 (count = 0), Skipped +Segment at 41:11 (count = 1), RegionEntry +Segment at 41:17 (count = 0), Skipped +Segment at 42:27 (count = 1), RegionEntry +Segment at 42:29 (count = 0), Skipped +Segment at 43:14 (count = 0), RegionEntry +Segment at 43:16 (count = 0), Skipped +Segment at 45:1 (count = 1), RegionEntry +Segment at 45:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..133a85c83945 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,271 @@ + + + + +match_or_pattern.main - Coverage Spans + + + +
@0,1,2,3⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut a: u8 = 0; + let mut b: u8 = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + a = 2; + b = 0; + }⦉@4,6@5⦊⦉@5 + match @7⦊(a, b)⦉@7 { + // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + // This test confirms a fix for Issue #79569. + (0 | 1, 2 | 3) => @10,11⦊{}⦉@10,11 + _ => @8⦊{}⦉@8 + } + if @12⦊is_true⦉@12 @13,15⦊{ + a = 0; + b = 0; + }⦉@13,15@14⦊⦉@14 + match @16⦊(a, b)⦉@16 { + (0 | 1, 2 | 3) => @19,20⦊{}⦉@19,20 + _ => @17⦊{}⦉@17 + } + if @21⦊is_true⦉@21 @22,24⦊{ + a = 2; + b = 2; + }⦉@22,24@23⦊⦉@23 + match @25⦊(a, b)⦉@25 { + (0 | 1, 2 | 3) => @28,29⦊{}⦉@28,29 + _ => @26⦊{}⦉@26 + } + if @30⦊is_true⦉@30 @31,33⦊{ + a = 0; + b = 2; + }⦉@31,33@32⦊⦉@32 + match @34⦊(a, b)⦉@34 { + (0 | 1, 2 | 3) => @37,38⦊{}⦉@37,38 + _ => @35⦊{}⦉@35 + } +}@39⦊⦉@39
+ + diff --git a/src/test/run-make-fulldeps/coverage/match_or_pattern.rs b/src/test/run-make-fulldeps/coverage/match_or_pattern.rs new file mode 100644 index 000000000000..4c6a8a9b7037 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/match_or_pattern.rs @@ -0,0 +1,45 @@ +#![feature(or_patterns)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut a: u8 = 0; + let mut b: u8 = 0; + if is_true { + a = 2; + b = 0; + } + match (a, b) { + // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + // This test confirms a fix for Issue #79569. + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 0; + b = 0; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 2; + b = 2; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 0; + b = 2; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } +} From f8e22bfb1bff658466cf97e99026b91c2213df5d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 12 Dec 2020 10:37:10 +0100 Subject: [PATCH 246/719] Update Cranelift --- Cargo.lock | 88 ++++++++++++++++++++--------------------- Cargo.toml | 6 +-- src/debuginfo/emit.rs | 2 +- src/debuginfo/unwind.rs | 2 +- src/driver/jit.rs | 6 +-- 5 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b19a7b827ee..0382835269d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,7 +50,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" dependencies = [ "cranelift-entity", ] @@ -58,7 +58,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" dependencies = [ "byteorder", "cranelift-bforest", @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -85,17 +85,17 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" [[package]] name = "cranelift-entity" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" [[package]] name = "cranelift-frontend" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" dependencies = [ "cranelift-codegen", "log", @@ -104,44 +104,9 @@ dependencies = [ ] [[package]] -name = "cranelift-module" +name = "cranelift-jit" version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" -dependencies = [ - "anyhow", - "cranelift-codegen", - "cranelift-entity", - "log", - "thiserror", -] - -[[package]] -name = "cranelift-native" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" -dependencies = [ - "cranelift-codegen", - "raw-cpuid", - "target-lexicon", -] - -[[package]] -name = "cranelift-object" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" -dependencies = [ - "anyhow", - "cranelift-codegen", - "cranelift-module", - "log", - "object", - "target-lexicon", -] - -[[package]] -name = "cranelift-simplejit" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#bfd10512c10ef08d1969ab961e88dbbb41a3b201" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" dependencies = [ "anyhow", "cranelift-codegen", @@ -156,6 +121,41 @@ dependencies = [ "winapi", ] +[[package]] +name = "cranelift-module" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-entity", + "log", + "thiserror", +] + +[[package]] +name = "cranelift-native" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +dependencies = [ + "cranelift-codegen", + "raw-cpuid", + "target-lexicon", +] + +[[package]] +name = "cranelift-object" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-module", + "log", + "object", + "target-lexicon", +] + [[package]] name = "crc32fast" version = "1.2.1" @@ -326,9 +326,9 @@ dependencies = [ "ar", "cranelift-codegen", "cranelift-frontend", + "cranelift-jit", "cranelift-module", "cranelift-object", - "cranelift-simplejit", "gimli", "indexmap", "libloading", diff --git a/Cargo.toml b/Cargo.toml index cbff06749d3e..8e1933bb14e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["dylib"] cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] } cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } -cranelift-simplejit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true } +cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true } cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } target-lexicon = "0.11.0" gimli = { version = "0.23.0", default-features = false, features = ["write"]} @@ -27,7 +27,7 @@ libloading = { version = "0.6.0", optional = true } #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" } #cranelift-module = { path = "../wasmtime/cranelift/module" } -#cranelift-simplejit = { path = "../wasmtime/cranelift/simplejit" } +#cranelift-jit = { path = "../wasmtime/cranelift/jit" } #cranelift-object = { path = "../wasmtime/cranelift/object" } #[patch.crates-io] @@ -35,7 +35,7 @@ libloading = { version = "0.6.0", optional = true } [features] default = ["jit", "inline_asm"] -jit = ["cranelift-simplejit", "libloading"] +jit = ["cranelift-jit", "libloading"] inline_asm = [] [profile.dev] diff --git a/src/debuginfo/emit.rs b/src/debuginfo/emit.rs index c21835b1fc3a..7a0d8907c500 100644 --- a/src/debuginfo/emit.rs +++ b/src/debuginfo/emit.rs @@ -76,7 +76,7 @@ impl WriterRelocate { #[cfg(feature = "jit")] pub(super) fn relocate_for_jit( mut self, - jit_module: &cranelift_simplejit::SimpleJITModule, + jit_module: &cranelift_jit::JITModule, ) -> Vec { use std::convert::TryInto; diff --git a/src/debuginfo/unwind.rs b/src/debuginfo/unwind.rs index e0f62b64e6bb..dc630fa5fd42 100644 --- a/src/debuginfo/unwind.rs +++ b/src/debuginfo/unwind.rs @@ -80,7 +80,7 @@ impl<'tcx> UnwindContext<'tcx> { #[cfg(feature = "jit")] pub(crate) unsafe fn register_jit( self, - jit_module: &cranelift_simplejit::SimpleJITModule, + jit_module: &cranelift_jit::JITModule, ) -> Option { let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(super::target_endian( self.tcx, diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 4d40debc956d..05bcade35356 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -7,7 +7,7 @@ use std::os::raw::{c_char, c_int}; use rustc_codegen_ssa::CrateInfo; use rustc_middle::mir::mono::MonoItem; -use cranelift_simplejit::{SimpleJITBuilder, SimpleJITModule}; +use cranelift_jit::{JITBuilder, JITModule}; use crate::prelude::*; @@ -36,12 +36,12 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! { let imported_symbols = load_imported_symbols_for_jit(tcx); - let mut jit_builder = SimpleJITBuilder::with_isa( + let mut jit_builder = JITBuilder::with_isa( crate::build_isa(tcx.sess, false), cranelift_module::default_libcall_names(), ); jit_builder.symbols(imported_symbols); - let mut jit_module = SimpleJITModule::new(jit_builder); + let mut jit_module = JITModule::new(jit_builder); assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type()); let sig = Signature { From 3f47f938ba5303be9b6fe8c13aee6dce4aaa4b0b Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 12 Dec 2020 10:38:46 +0100 Subject: [PATCH 247/719] Enable Cranelift optimizations when optimizing LICM in Cranelift has been fixed recently --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ba9ee0d450ee..7b751102f8b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -283,8 +283,6 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box { @@ -297,7 +295,7 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box { sess.warn("Optimizing for size is not supported. Just ignoring the request"); } - }*/ + } let flags = settings::Flags::new(flags_builder); From 409382dd3cd9113757c11d3af2c509dac2edf8f2 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 23 Nov 2020 20:50:02 -0500 Subject: [PATCH 248/719] Don't abort rustdoc tests if `tidy` isn't installed Before: ``` Check compiletest suite=rustdoc mode=rustdoc (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) running 396 tests ..................................................2020-11-23T12:12:37.735649Z ERROR compiletest::runtest: fatal error, panic: "failed to run tidy - is it installed? - No such file or directory (os error 2)" F................................................. 100/396 .................................................................................................... 200/396 .................................................................................................... 300/396 ...............................i...............2020-11-23T12:15:00.271271Z ERROR compiletest::runtest: fatal error, panic: "failed to run tidy - is it installed? - No such file or directory (os error 2)" F................................................ ``` After: ``` Check compiletest suite=rustdoc mode=rustdoc (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) running 4 tests .FFF failures: ---- [rustdoc] rustdoc/fn-pointer-arg-name.rs stdout ---- error: htmldocck failed! status: exit code: 1 command: "/usr/bin/python" "/home/joshua/rustc/src/etc/htmldocck.py" "/home/joshua/rustc/build/x86_64-unknown-linux-gnu/test/rustdoc/fn-pointer-arg-name" "/home/joshua/rustc/src/test/rustdoc/fn-pointer-arg-name.rs" stdout: ------------------------------------------ ------------------------------------------ stderr: ------------------------------------------ 4: @has check failed `XPATH PATTERN` did not match // @has - '//*[@class="rust fn"]' 'pub fn f(callback: fn(len: usize, foo: u32))' Encountered 1 errors ------------------------------------------ info: generating a diff against nightly rustdoc failed to run tidy - is it installed? - Permission denied (os error 13) failed to run tidy - is it installed? - Permission denied (os error 13) # a diff without running `tidy` ``` --- src/tools/compiletest/src/runtest.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ccef005173d9..398f3e31c6ad 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2394,7 +2394,8 @@ impl<'test> TestCx<'test> { let proc_res = new_rustdoc.document(&compare_dir); if !proc_res.status.success() { - proc_res.fatal(Some("failed to run nightly rustdoc"), || ()); + eprintln!("failed to run nightly rustdoc"); + return; } #[rustfmt::skip] @@ -2409,22 +2410,26 @@ impl<'test> TestCx<'test> { ]; let tidy_dir = |dir| { let tidy = |file: &_| { - Command::new("tidy") - .args(&tidy_args) - .arg(file) - .spawn() - .unwrap_or_else(|err| { - self.fatal(&format!("failed to run tidy - is it installed? - {}", err)) - }) - .wait() - .unwrap() + let tidy_proc = Command::new("tidy").args(&tidy_args).arg(file).spawn(); + match tidy_proc { + Ok(mut proc) => { + proc.wait().unwrap(); + true + } + Err(err) => { + eprintln!("failed to run tidy - is it installed? - {}", err); + false + } + } }; for entry in walkdir::WalkDir::new(dir) { let entry = entry.expect("failed to read file"); if entry.file_type().is_file() && entry.path().extension().and_then(|p| p.to_str()) == Some("html".into()) { - tidy(entry.path()); + if !tidy(entry.path()) { + return; + } } } }; From 804b72af4a478a406e3b73fa690a307c420daf0b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 26 Nov 2020 14:05:54 -0500 Subject: [PATCH 249/719] If tidy isn't installed, only give one error, not many --- src/tools/compiletest/src/common.rs | 3 +++ src/tools/compiletest/src/main.rs | 12 +++++++++++- src/tools/compiletest/src/runtest.rs | 26 ++++++++------------------ 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index eba02333c8cb..55d25fa7c52c 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -327,6 +327,9 @@ pub struct Config { /// created in `//rustfix_missing_coverage.txt` pub rustfix_coverage: bool, + /// whether to run `tidy` when a rustdoc test fails + pub has_tidy: bool, + // Configuration for various run-make tests frobbing things like C compilers // or querying about various LLVM component information. pub cc: String, diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 5177dae8a660..c63bbaf70d3c 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -14,7 +14,7 @@ use std::ffi::OsString; use std::fs; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use std::time::SystemTime; use test::ColorConfig; use tracing::*; @@ -43,6 +43,10 @@ fn main() { panic!("Can't find Valgrind to run Valgrind tests"); } + if !config.has_tidy && config.mode == Mode::Rustdoc { + eprintln!("warning: `tidy` is not installed; generated diffs will be harder to read"); + } + log_config(&config); run_tests(config); } @@ -189,6 +193,11 @@ pub fn parse_config(args: Vec) -> Config { let src_base = opt_path(matches, "src-base"); let run_ignored = matches.opt_present("ignored"); + let has_tidy = Command::new("tidy") + .arg("--version") + .stdout(Stdio::null()) + .status() + .map_or(false, |status| status.success()); Config { bless: matches.opt_present("bless"), compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), @@ -244,6 +253,7 @@ pub fn parse_config(args: Vec) -> Config { remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse), rustfix_coverage: matches.opt_present("rustfix-coverage"), + has_tidy, cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 398f3e31c6ad..d43e75248eb4 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2409,32 +2409,22 @@ impl<'test> TestCx<'test> { "-modify", ]; let tidy_dir = |dir| { - let tidy = |file: &_| { - let tidy_proc = Command::new("tidy").args(&tidy_args).arg(file).spawn(); - match tidy_proc { - Ok(mut proc) => { - proc.wait().unwrap(); - true - } - Err(err) => { - eprintln!("failed to run tidy - is it installed? - {}", err); - false - } - } - }; for entry in walkdir::WalkDir::new(dir) { let entry = entry.expect("failed to read file"); if entry.file_type().is_file() && entry.path().extension().and_then(|p| p.to_str()) == Some("html".into()) { - if !tidy(entry.path()) { - return; - } + let status = + Command::new("tidy").args(&tidy_args).arg(entry.path()).status().unwrap(); + // `tidy` returns 1 if it modified the file. + assert!(status.success() || status.code() == Some(1)); } } }; - tidy_dir(out_dir); - tidy_dir(&compare_dir); + if self.config.has_tidy { + tidy_dir(out_dir); + tidy_dir(&compare_dir); + } let pager = { let output = Command::new("git").args(&["config", "--get", "core.pager"]).output().ok(); From f9b97a8e458b73b7e670a940877f91f9ce0b9ce3 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 26 Nov 2020 15:48:21 -0500 Subject: [PATCH 250/719] Ignore .css files in the diff These are always static and never autogenerated, so the diffs aren't useful. --- src/tools/compiletest/src/runtest.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index d43e75248eb4..7af0d91271b0 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2437,7 +2437,8 @@ impl<'test> TestCx<'test> { }) }; let mut diff = Command::new("diff"); - diff.args(&["-u", "-r"]).args(&[&compare_dir, out_dir]); + // diff recursively, showing context, and excluding .css files + diff.args(&["-u", "-r", "-x", "*.css"]).args(&[&compare_dir, out_dir]); let output = if let Some(pager) = pager { let diff_pid = diff.stdout(Stdio::piped()).spawn().expect("failed to run `diff`"); From 4bd9ed9b88d47bba3dc91fde6c0a27b63f63fe4b Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Wed, 2 Dec 2020 18:20:02 +0100 Subject: [PATCH 251/719] Rewrite update-all-references bash scripts in Rust This replaces the `update-all-references` scripts with a single cargo dev bless command. cc #5394 --- clippy_dev/src/bless.rs | 71 +++++++++++++++++++++++++ clippy_dev/src/lib.rs | 1 + clippy_dev/src/main.rs | 6 ++- doc/adding_lints.md | 13 +++-- doc/basics.md | 2 +- tests/ui-cargo/update-all-references.sh | 17 +----- tests/ui-cargo/update-references.sh | 46 ---------------- tests/ui-toml/update-all-references.sh | 17 +----- tests/ui-toml/update-references.sh | 46 ---------------- tests/ui/update-all-references.sh | 20 +------ tests/ui/update-references.sh | 56 ------------------- 11 files changed, 87 insertions(+), 208 deletions(-) create mode 100644 clippy_dev/src/bless.rs delete mode 100755 tests/ui-cargo/update-references.sh delete mode 100755 tests/ui-toml/update-references.sh delete mode 100755 tests/ui/update-references.sh diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs new file mode 100644 index 000000000000..45e403fa74d3 --- /dev/null +++ b/clippy_dev/src/bless.rs @@ -0,0 +1,71 @@ +//! `bless` updates the 'expected output' files in the repo with changed output files +//! from the last test run. + +use std::env; +use std::ffi::OsStr; +use std::fs; +use std::lazy::SyncLazy; +use std::path::PathBuf; +use walkdir::WalkDir; + +use crate::clippy_project_root; + +// NOTE: this is duplicated with tests/cargo/mod.rs What to do? +pub static CARGO_TARGET_DIR: SyncLazy = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") { + Some(v) => v.into(), + None => env::current_dir().unwrap().join("target"), +}); + +pub fn bless() { + let test_dirs = [ + clippy_project_root().join("tests").join("ui"), + clippy_project_root().join("tests").join("ui-toml"), + clippy_project_root().join("tests").join("ui-cargo"), + ]; + for test_dir in &test_dirs { + WalkDir::new(test_dir) + .into_iter() + .filter_map(Result::ok) + .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) + .for_each(|f| { + update_test_file(f.path().with_extension("stdout")); + update_test_file(f.path().with_extension("stderr")); + update_test_file(f.path().with_extension("fixed")); + }); + } +} + +fn update_test_file(test_file_path: PathBuf) { + let build_output_path = build_dir().join(PathBuf::from(test_file_path.file_name().unwrap())); + let relative_test_file_path = test_file_path.strip_prefix(clippy_project_root()).unwrap(); + + // If compiletest did not write any changes during the test run, + // we don't have to update anything + if !build_output_path.exists() { + return; + } + + let build_output = fs::read(&build_output_path).expect("Unable to read build output file"); + let test_file = fs::read(&test_file_path).expect("Unable to read test file"); + + if build_output != test_file { + // If a test run caused an output file to change, update the test file + println!("updating {}", &relative_test_file_path.display()); + fs::copy(build_output_path, &test_file_path).expect("Could not update test file"); + + if test_file.is_empty() { + // If we copied over an empty output file, we remove it + println!("removing {}", &relative_test_file_path.display()); + fs::remove_file(test_file_path).expect("Could not remove test file"); + } + } +} + +fn build_dir() -> PathBuf { + let profile = format!("{}", env::var("PROFILE").unwrap_or("debug".to_string())); + let mut path = PathBuf::new(); + path.push(CARGO_TARGET_DIR.clone()); + path.push(profile); + path.push("test_build_base"); + path +} diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index f51c45e9eb59..17cc08ee10fe 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -10,6 +10,7 @@ use std::lazy::SyncLazy; use std::path::{Path, PathBuf}; use walkdir::WalkDir; +pub mod bless; pub mod fmt; pub mod new_lint; pub mod ra_setup; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 7a8cbd5251da..f66855620e73 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -1,10 +1,11 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] use clap::{App, Arg, SubCommand}; -use clippy_dev::{fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints}; +use clippy_dev::{bless, fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints}; fn main() { let matches = App::new("Clippy developer tooling") + .subcommand(SubCommand::with_name("bless").about("bless the test output changes")) .subcommand( SubCommand::with_name("fmt") .about("Run rustfmt on all projects and tests") @@ -116,6 +117,9 @@ fn main() { .get_matches(); match matches.subcommand() { + ("bless", Some(_)) => { + bless::bless(); + }, ("fmt", Some(matches)) => { fmt::run(matches.is_present("check"), matches.is_present("verbose")); }, diff --git a/doc/adding_lints.md b/doc/adding_lints.md index a723b0a4c20f..60dfdb76650a 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -98,12 +98,12 @@ While we are working on implementing our lint, we can keep running the UI test. That allows us to check if the output is turning into what we want. Once we are satisfied with the output, we need to run -`tests/ui/update-all-references.sh` to update the `.stderr` file for our lint. +`cargo dev bless` to update the `.stderr` file for our lint. Please note that, we should run `TESTNAME=foo_functions cargo uitest` -every time before running `tests/ui/update-all-references.sh`. +every time before running `cargo dev bless`. Running `TESTNAME=foo_functions cargo uitest` should pass then. When we commit our lint, we need to commit the generated `.stderr` files, too. In general, you -should only commit files changed by `tests/ui/update-all-references.sh` for the +should only commit files changed by `cargo dev bless` for the specific lint you are creating/editing. Note that if the generated files are empty, they should be removed. @@ -122,8 +122,7 @@ we will find by default two new crates, each with its manifest file: If you need more cases, you can copy one of those crates (under `foo_categories`) and rename it. The process of generating the `.stderr` file is the same, and prepending the `TESTNAME` -variable to `cargo uitest` works too, but the script to update the references -is in another path: `tests/ui-cargo/update-all-references.sh`. +variable to `cargo uitest` works too. ## Rustfix tests @@ -133,7 +132,7 @@ additionally run [rustfix] for that test. Rustfix will apply the suggestions from the lint to the code of the test file and compare that to the contents of a `.fixed` file. -Use `tests/ui/update-all-references.sh` to automatically generate the +Use `cargo dev bless` to automatically generate the `.fixed` file after running the tests. [rustfix]: https://github.com/rust-lang/rustfix @@ -368,7 +367,7 @@ fn is_foo_fn(fn_kind: FnKind<'_>) -> bool { Now we should also run the full test suite with `cargo test`. At this point running `cargo test` should produce the expected output. Remember to run -`tests/ui/update-all-references.sh` to update the `.stderr` file. +`cargo dev bless` to update the `.stderr` file. `cargo test` (as opposed to `cargo uitest`) will also ensure that our lint implementation is not violating any Clippy lints itself. diff --git a/doc/basics.md b/doc/basics.md index 8b2a8a238900..dc71f022773c 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -61,7 +61,7 @@ If the output of a [UI test] differs from the expected output, you can update th reference file with: ```bash -sh tests/ui/update-all-references.sh +cargo dev bless ``` For example, this is necessary, if you fix a typo in an error message of a lint diff --git a/tests/ui-cargo/update-all-references.sh b/tests/ui-cargo/update-all-references.sh index 7028b251ea03..4391499a1e1f 100755 --- a/tests/ui-cargo/update-all-references.sh +++ b/tests/ui-cargo/update-all-references.sh @@ -1,18 +1,3 @@ #!/bin/bash -# -# A script to update the references for all tests. The idea is that -# you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. You then -# run this script, which will copy those files over. If you find -# yourself manually editing a foo.stderr file, you're doing it wrong. -# -# See all `update-references.sh`, if you just want to update a single test. -if [[ "$1" == "--help" || "$1" == "-h" ]]; then - echo "usage: $0" -fi - -BUILD_DIR=$PWD/target/debug/test_build_base -MY_DIR=$(dirname "$0") -cd "$MY_DIR" || exit -find . -name '*.rs' -exec ./update-references.sh "$BUILD_DIR" {} + +echo "Please use 'cargo dev bless' instead." diff --git a/tests/ui-cargo/update-references.sh b/tests/ui-cargo/update-references.sh deleted file mode 100755 index 2ab51168bcaa..000000000000 --- a/tests/ui-cargo/update-references.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# A script to update the references for particular tests. The idea is -# that you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. This -# script will then copy that output and replace the "expected output" -# files. You can then commit the changes. -# -# If you find yourself manually editing a foo.stderr file, you're -# doing it wrong. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then - echo "usage: $0 " - echo "" - echo "For example:" - echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" -fi - -MYDIR=$(dirname "$0") - -BUILD_DIR="$1" -shift - -while [[ "$1" != "" ]]; do - STDERR_NAME="${1/%.rs/.stderr}" - STDOUT_NAME="${1/%.rs/.stdout}" - shift - if [[ -f "$BUILD_DIR"/"$STDOUT_NAME" ]] && \ - ! (cmp -s -- "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"); then - echo updating "$MYDIR"/"$STDOUT_NAME" - cp "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME" - if [[ ! -s "$MYDIR"/"$STDOUT_NAME" ]]; then - echo removing "$MYDIR"/"$STDOUT_NAME" - rm "$MYDIR"/"$STDOUT_NAME" - fi - fi - if [[ -f "$BUILD_DIR"/"$STDERR_NAME" ]] && \ - ! (cmp -s -- "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"); then - echo updating "$MYDIR"/"$STDERR_NAME" - cp "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME" - if [[ ! -s "$MYDIR"/"$STDERR_NAME" ]]; then - echo removing "$MYDIR"/"$STDERR_NAME" - rm "$MYDIR"/"$STDERR_NAME" - fi - fi -done diff --git a/tests/ui-toml/update-all-references.sh b/tests/ui-toml/update-all-references.sh index 7028b251ea03..4391499a1e1f 100755 --- a/tests/ui-toml/update-all-references.sh +++ b/tests/ui-toml/update-all-references.sh @@ -1,18 +1,3 @@ #!/bin/bash -# -# A script to update the references for all tests. The idea is that -# you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. You then -# run this script, which will copy those files over. If you find -# yourself manually editing a foo.stderr file, you're doing it wrong. -# -# See all `update-references.sh`, if you just want to update a single test. -if [[ "$1" == "--help" || "$1" == "-h" ]]; then - echo "usage: $0" -fi - -BUILD_DIR=$PWD/target/debug/test_build_base -MY_DIR=$(dirname "$0") -cd "$MY_DIR" || exit -find . -name '*.rs' -exec ./update-references.sh "$BUILD_DIR" {} + +echo "Please use 'cargo dev bless' instead." diff --git a/tests/ui-toml/update-references.sh b/tests/ui-toml/update-references.sh deleted file mode 100755 index 2ab51168bcaa..000000000000 --- a/tests/ui-toml/update-references.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# A script to update the references for particular tests. The idea is -# that you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. This -# script will then copy that output and replace the "expected output" -# files. You can then commit the changes. -# -# If you find yourself manually editing a foo.stderr file, you're -# doing it wrong. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then - echo "usage: $0 " - echo "" - echo "For example:" - echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" -fi - -MYDIR=$(dirname "$0") - -BUILD_DIR="$1" -shift - -while [[ "$1" != "" ]]; do - STDERR_NAME="${1/%.rs/.stderr}" - STDOUT_NAME="${1/%.rs/.stdout}" - shift - if [[ -f "$BUILD_DIR"/"$STDOUT_NAME" ]] && \ - ! (cmp -s -- "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"); then - echo updating "$MYDIR"/"$STDOUT_NAME" - cp "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME" - if [[ ! -s "$MYDIR"/"$STDOUT_NAME" ]]; then - echo removing "$MYDIR"/"$STDOUT_NAME" - rm "$MYDIR"/"$STDOUT_NAME" - fi - fi - if [[ -f "$BUILD_DIR"/"$STDERR_NAME" ]] && \ - ! (cmp -s -- "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"); then - echo updating "$MYDIR"/"$STDERR_NAME" - cp "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME" - if [[ ! -s "$MYDIR"/"$STDERR_NAME" ]]; then - echo removing "$MYDIR"/"$STDERR_NAME" - rm "$MYDIR"/"$STDERR_NAME" - fi - fi -done diff --git a/tests/ui/update-all-references.sh b/tests/ui/update-all-references.sh index 30ba9188db43..4391499a1e1f 100755 --- a/tests/ui/update-all-references.sh +++ b/tests/ui/update-all-references.sh @@ -1,21 +1,3 @@ #!/bin/bash -# A script to update the references for all tests. The idea is that -# you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. You then -# run this script, which will copy those files over. If you find -# yourself manually editing a foo.stderr file, you're doing it wrong. -# -# See all `update-references.sh`, if you just want to update a single test. - -if [[ "$1" == "--help" || "$1" == "-h" ]]; then - echo "usage: $0" -fi - -CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-$PWD/target} -PROFILE=${PROFILE:-debug} -BUILD_DIR=${CARGO_TARGET_DIR}/${PROFILE}/test_build_base - -MY_DIR=$(dirname "$0") -cd "$MY_DIR" || exit -find . -name '*.rs' -exec ./update-references.sh "$BUILD_DIR" {} + +echo "Please use 'cargo dev bless' instead." diff --git a/tests/ui/update-references.sh b/tests/ui/update-references.sh deleted file mode 100755 index e16ed600ef81..000000000000 --- a/tests/ui/update-references.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -# A script to update the references for particular tests. The idea is -# that you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. This -# script will then copy that output and replace the "expected output" -# files. You can then commit the changes. -# -# If you find yourself manually editing a `foo.stderr` file, you're -# doing it wrong. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then - echo "usage: $0 " - echo "" - echo "For example:" - echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" -fi - -MYDIR=$(dirname "$0") - -BUILD_DIR="$1" -shift - -while [[ "$1" != "" ]]; do - STDERR_NAME="${1/%.rs/.stderr}" - STDOUT_NAME="${1/%.rs/.stdout}" - FIXED_NAME="${1/%.rs/.fixed}" - shift - if [[ -f "$BUILD_DIR"/"$STDOUT_NAME" ]] && \ - ! (cmp -s -- "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"); then - echo updating "$MYDIR"/"$STDOUT_NAME" - cp "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME" - if [[ ! -s "$MYDIR"/"$STDOUT_NAME" ]]; then - echo removing "$MYDIR"/"$STDOUT_NAME" - rm "$MYDIR"/"$STDOUT_NAME" - fi - fi - if [[ -f "$BUILD_DIR"/"$STDERR_NAME" ]] && \ - ! (cmp -s -- "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"); then - echo updating "$MYDIR"/"$STDERR_NAME" - cp "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME" - if [[ ! -s "$MYDIR"/"$STDERR_NAME" ]]; then - echo removing "$MYDIR"/"$STDERR_NAME" - rm "$MYDIR"/"$STDERR_NAME" - fi - fi - if [[ -f "$BUILD_DIR"/"$FIXED_NAME" ]] && \ - ! (cmp -s -- "$BUILD_DIR"/"$FIXED_NAME" "$MYDIR"/"$FIXED_NAME"); then - echo updating "$MYDIR"/"$FIXED_NAME" - cp "$BUILD_DIR"/"$FIXED_NAME" "$MYDIR"/"$FIXED_NAME" - if [[ ! -s "$MYDIR"/"$FIXED_NAME" ]]; then - echo removing "$MYDIR"/"$FIXED_NAME" - rm "$MYDIR"/"$FIXED_NAME" - fi - fi -done From 41c562d4a578637306dca2d9a7889d8f5bb4a58e Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Thu, 10 Dec 2020 11:34:22 +0100 Subject: [PATCH 252/719] Improve variable naming --- clippy_dev/src/bless.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs index 45e403fa74d3..6a1fa61b12d6 100644 --- a/clippy_dev/src/bless.rs +++ b/clippy_dev/src/bless.rs @@ -1,4 +1,4 @@ -//! `bless` updates the 'expected output' files in the repo with changed output files +//! `bless` updates the reference files in the repo with changed output files //! from the last test run. use std::env; @@ -28,35 +28,35 @@ pub fn bless() { .filter_map(Result::ok) .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) .for_each(|f| { - update_test_file(f.path().with_extension("stdout")); - update_test_file(f.path().with_extension("stderr")); - update_test_file(f.path().with_extension("fixed")); + update_reference_file(f.path().with_extension("stdout")); + update_reference_file(f.path().with_extension("stderr")); + update_reference_file(f.path().with_extension("fixed")); }); } } -fn update_test_file(test_file_path: PathBuf) { - let build_output_path = build_dir().join(PathBuf::from(test_file_path.file_name().unwrap())); - let relative_test_file_path = test_file_path.strip_prefix(clippy_project_root()).unwrap(); +fn update_reference_file(reference_file_path: PathBuf) { + let test_output_path = build_dir().join(PathBuf::from(reference_file_path.file_name().unwrap())); + let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap(); // If compiletest did not write any changes during the test run, // we don't have to update anything - if !build_output_path.exists() { + if !test_output_path.exists() { return; } - let build_output = fs::read(&build_output_path).expect("Unable to read build output file"); - let test_file = fs::read(&test_file_path).expect("Unable to read test file"); + let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file"); + let reference_file = fs::read(&reference_file_path).expect("Unable to read reference file"); - if build_output != test_file { - // If a test run caused an output file to change, update the test file - println!("updating {}", &relative_test_file_path.display()); - fs::copy(build_output_path, &test_file_path).expect("Could not update test file"); + if test_output_file != reference_file { + // If a test run caused an output file to change, update the reference file + println!("updating {}", &relative_reference_file_path.display()); + fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file"); - if test_file.is_empty() { - // If we copied over an empty output file, we remove it - println!("removing {}", &relative_test_file_path.display()); - fs::remove_file(test_file_path).expect("Could not remove test file"); + if reference_file.is_empty() { + // If we copied over an empty output file, we remove the now empty reference file + println!("removing {}", &relative_reference_file_path.display()); + fs::remove_file(reference_file_path).expect("Could not remove reference file"); } } } From b8501e1be12594145bcd2bae2b47af2152785622 Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Sat, 12 Dec 2020 15:14:54 +0100 Subject: [PATCH 253/719] Feed the dog :dog2: --- clippy_dev/src/bless.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs index 6a1fa61b12d6..8d5c2e95055d 100644 --- a/clippy_dev/src/bless.rs +++ b/clippy_dev/src/bless.rs @@ -62,7 +62,7 @@ fn update_reference_file(reference_file_path: PathBuf) { } fn build_dir() -> PathBuf { - let profile = format!("{}", env::var("PROFILE").unwrap_or("debug".to_string())); + let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); let mut path = PathBuf::new(); path.push(CARGO_TARGET_DIR.clone()); path.push(profile); From 9684557c8f1b9fd55cb6fcc27533044022b0ed22 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 12 Dec 2020 09:38:35 -0500 Subject: [PATCH 254/719] Small cleanups - Use a tuple struct instead of a single field - Enforce calling `source_callsite()` by making the inner span private - Rename `empty` to `dummy` --- src/librustdoc/clean/auto_trait.rs | 2 +- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 5 +---- src/librustdoc/clean/types.rs | 25 +++++++++++++++---------- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 8feef9c259c1..7a61a169c2bd 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -118,7 +118,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { }; Some(Item { - source: Span::empty(), + source: Span::dummy(), name: None, attrs: Default::default(), visibility: Inherited, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f3067360f068..42778867bf80 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -479,7 +479,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet) items.push(clean::Item { name: None, attrs: clean::Attributes::default(), - source: clean::Span::empty(), + source: clean::Span::dummy(), def_id: DefId::local(CRATE_DEF_INDEX), visibility: clean::Public, stability: None, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a21e9d9820cb..1a63a5092ca0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1882,10 +1882,7 @@ impl Clean for hir::VariantData<'_> { impl Clean for rustc_span::Span { fn clean(&self, _cx: &DocContext<'_>) -> Span { - // Get the macro invocation instead of the definition, - // in case the span is result of a macro expansion. - // (See rust-lang/rust#39726) - Span { original: self.source_callsite() } + Span::from_rustc_span(*self) } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a8626af8832f..0228d63ac00e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1610,31 +1610,36 @@ crate enum VariantKind { Struct(VariantStruct), } -/// Small wrapper around `rustc_span::Span` that adds helper methods. +/// Small wrapper around `rustc_span::Span` that adds helper methods and enforces calling `source_callsite`. #[derive(Clone, Debug)] -crate struct Span { - crate original: rustc_span::Span, -} +crate struct Span(rustc_span::Span); impl Span { - crate fn empty() -> Self { - Self { original: rustc_span::DUMMY_SP } + crate fn from_rustc_span(sp: rustc_span::Span) -> Self { + // Get the macro invocation instead of the definition, + // in case the span is result of a macro expansion. + // (See rust-lang/rust#39726) + Self(sp.source_callsite()) + } + + crate fn dummy() -> Self { + Self(rustc_span::DUMMY_SP) } crate fn span(&self) -> rustc_span::Span { - self.original + self.0 } crate fn filename(&self, sess: &Session) -> FileName { - sess.source_map().span_to_filename(self.original) + sess.source_map().span_to_filename(self.0) } crate fn lo(&self, sess: &Session) -> Loc { - sess.source_map().lookup_char_pos(self.original.lo()) + sess.source_map().lookup_char_pos(self.0.lo()) } crate fn hi(&self, sess: &Session) -> Loc { - sess.source_map().lookup_char_pos(self.original.hi()) + sess.source_map().lookup_char_pos(self.0.hi()) } crate fn cnum(&self, sess: &Session) -> CrateNum { From 6a1f92b896d0afed3b26ac67871e9dc4e892dbfd Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 12 Dec 2020 16:13:06 +0100 Subject: [PATCH 255/719] Fix typo in `DebruijnIndex` documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rémy Rakic --- compiler/rustc_type_ir/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 1c9475f7a66e..37abb4496ac3 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -119,7 +119,7 @@ rustc_index::newtype_index! { /// Bruijn index of 0, meaning "the innermost binder" (in this case, a /// fn). The region `'a` that appears in the second argument type (`&'a /// isize`) would then be assigned a De Bruijn index of 1, meaning "the - /// second-innermost binder". (These indices are written on the arrays + /// second-innermost binder". (These indices are written on the arrows /// in the diagram). /// /// What is interesting is that De Bruijn index attached to a particular From ec09616078e89deab5f97e578b3400b045c09575 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 12 Dec 2020 19:18:44 +0300 Subject: [PATCH 256/719] tidy: Re-enable check for inline unit tests --- compiler/rustc_feature/src/lib.rs | 30 +++-------------------------- compiler/rustc_feature/src/tests.rs | 23 ++++++++++++++++++++++ src/tools/tidy/src/main.rs | 5 ++++- 3 files changed, 30 insertions(+), 28 deletions(-) create mode 100644 compiler/rustc_feature/src/tests.rs diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index f965f7fdefe4..2a7c2a02fbaf 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -18,6 +18,9 @@ mod active; mod builtin_attrs; mod removed; +#[cfg(test)] +mod tests; + use rustc_span::{edition::Edition, symbol::Symbol, Span}; use std::fmt; use std::num::NonZeroU32; @@ -149,30 +152,3 @@ pub use builtin_attrs::{ AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; - -#[cfg(test)] -mod test { - use super::UnstableFeatures; - - #[test] - fn rustc_bootstrap_parsing() { - let is_bootstrap = |env, krate| { - std::env::set_var("RUSTC_BOOTSTRAP", env); - matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Cheat) - }; - assert!(is_bootstrap("1", None)); - assert!(is_bootstrap("1", Some("x"))); - // RUSTC_BOOTSTRAP allows specifying a specific crate - assert!(is_bootstrap("x", Some("x"))); - // RUSTC_BOOTSTRAP allows multiple comma-delimited crates - assert!(is_bootstrap("x,y,z", Some("x"))); - assert!(is_bootstrap("x,y,z", Some("y"))); - // Crate that aren't specified do not get unstable features - assert!(!is_bootstrap("x", Some("a"))); - assert!(!is_bootstrap("x,y,z", Some("a"))); - assert!(!is_bootstrap("x,y,z", None)); - - // this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP - assert!(!is_bootstrap("0", None)); - } -} diff --git a/compiler/rustc_feature/src/tests.rs b/compiler/rustc_feature/src/tests.rs new file mode 100644 index 000000000000..50433e44b135 --- /dev/null +++ b/compiler/rustc_feature/src/tests.rs @@ -0,0 +1,23 @@ +use super::UnstableFeatures; + +#[test] +fn rustc_bootstrap_parsing() { + let is_bootstrap = |env, krate| { + std::env::set_var("RUSTC_BOOTSTRAP", env); + matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Cheat) + }; + assert!(is_bootstrap("1", None)); + assert!(is_bootstrap("1", Some("x"))); + // RUSTC_BOOTSTRAP allows specifying a specific crate + assert!(is_bootstrap("x", Some("x"))); + // RUSTC_BOOTSTRAP allows multiple comma-delimited crates + assert!(is_bootstrap("x,y,z", Some("x"))); + assert!(is_bootstrap("x,y,z", Some("y"))); + // Crate that aren't specified do not get unstable features + assert!(!is_bootstrap("x", Some("a"))); + assert!(!is_bootstrap("x,y,z", Some("a"))); + assert!(!is_bootstrap("x,y,z", None)); + + // this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP + assert!(!is_bootstrap("0", None)); +} diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index e1525f8e1bf2..080e16316242 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,9 +35,12 @@ fn main() { // Checks that only make sense for the std libs. pal::check(&library_path, &mut bad); - unit_tests::check(&library_path, &mut bad); // Checks that need to be done for both the compiler and std libraries. + unit_tests::check(&src_path, &mut bad); + unit_tests::check(&compiler_path, &mut bad); + unit_tests::check(&library_path, &mut bad); + bins::check(&src_path, &output_directory, &mut bad); bins::check(&compiler_path, &output_directory, &mut bad); bins::check(&library_path, &output_directory, &mut bad); From 05b557cfc981e4fc05fb47380e471f50cd23869d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 12 Dec 2020 19:20:37 +0300 Subject: [PATCH 257/719] Remove some no longer necessary `#[cfg(test)]`s With https://github.com/rust-lang/rust/pull/69838 inner modules are never touched in the outer module is unconfigured. --- compiler/rustc_expand/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 47247294f5dc..3b722c04cb15 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -36,16 +36,13 @@ crate mod mbe; mod tests; #[cfg(test)] mod parse { - #[cfg(test)] mod tests; } #[cfg(test)] mod tokenstream { - #[cfg(test)] mod tests; } #[cfg(test)] mod mut_visit { - #[cfg(test)] mod tests; } From 16f69b5430cd543d5767401d760cc644dc836906 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 12 Dec 2020 18:02:37 +0100 Subject: [PATCH 258/719] Don't checkout llvm-project when the LLVM backend isn't built --- src/bootstrap/bootstrap.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index a819e1b6e2f1..63975c6dedac 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -892,13 +892,17 @@ class RustBuild(object): filtered_submodules = [] submodules_names = [] llvm_checked_out = os.path.exists(os.path.join(self.rust_root, "src/llvm-project/.git")) + external_llvm_provided = self.get_toml('llvm-config') or self.downloading_llvm() + llvm_needed = not self.get_toml('codegen-backends', 'rust') \ + or "llvm" in self.get_toml('codegen-backends', 'rust') for module in submodules: if module.endswith("llvm-project"): - # Don't sync the llvm-project submodule either if an external LLVM - # was provided, or if we are downloading LLVM. Also, if the - # submodule has been initialized already, sync it anyways so that - # it doesn't mess up contributor pull requests. - if self.get_toml('llvm-config') or self.downloading_llvm(): + # Don't sync the llvm-project submodule if an external LLVM was + # provided, if we are downloading LLVM or if the LLVM backend is + # not being built. Also, if the submodule has been initialized + # already, sync it anyways so that it doesn't mess up contributor + # pull requests. + if external_llvm_provided or not llvm_needed: if self.get_toml('lld') != 'true' and not llvm_checked_out: continue check = self.check_submodule(module, slow_submodules) From d79e19f3320be33f280a2b2eeb2e1ffd7f8f9162 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 12 Dec 2020 18:13:04 +0100 Subject: [PATCH 259/719] Don't require cmake and ninja when the LLVM backend is not used --- src/bootstrap/sanity.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 4cfcf6ca407b..8d7ad345ab4d 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -17,6 +17,7 @@ use std::process::Command; use build_helper::{output, t}; +use crate::cache::INTERNER; use crate::config::Target; use crate::Build; @@ -79,18 +80,19 @@ pub fn check(build: &mut Build) { } // We need cmake, but only if we're actually building LLVM or sanitizers. - let building_llvm = build - .hosts - .iter() - .map(|host| { - build - .config - .target_config - .get(host) - .map(|config| config.llvm_config.is_none()) - .unwrap_or(true) - }) - .any(|build_llvm_ourselves| build_llvm_ourselves); + let building_llvm = build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) + && build + .hosts + .iter() + .map(|host| { + build + .config + .target_config + .get(host) + .map(|config| config.llvm_config.is_none()) + .unwrap_or(true) + }) + .any(|build_llvm_ourselves| build_llvm_ourselves); if building_llvm || build.config.any_sanitizers_enabled() { cmd_finder.must_have("cmake"); } @@ -147,10 +149,12 @@ pub fn check(build: &mut Build) { } } - // Externally configured LLVM requires FileCheck to exist - let filecheck = build.llvm_filecheck(build.build); - if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests { - panic!("FileCheck executable {:?} does not exist", filecheck); + if build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { + // Externally configured LLVM requires FileCheck to exist + let filecheck = build.llvm_filecheck(build.build); + if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests { + panic!("FileCheck executable {:?} does not exist", filecheck); + } } for target in &build.targets { From 50576420f559be3c681e6833327845d6cf3217b4 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 24 Nov 2020 12:27:38 +0100 Subject: [PATCH 260/719] BTreeMap: clarify comments and panics surrounding choose_parent_kv --- library/alloc/src/collections/btree/node.rs | 14 ++++++++------ library/alloc/src/collections/btree/remove.rs | 12 ++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 31809fde57b7..588066f9fec5 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -1282,10 +1282,12 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// Chooses a balancing context involving the node as a child, thus between /// the KV immediately to the left or to the right in the parent node. /// Returns an `Err` if there is no parent. + /// Panics if the parent is empty. /// - /// This method optimizes for a node that has fewer elements than its left - /// and right siblings, if they exist, by preferring the left parent KV. - /// Merging with the left sibling is faster, since we only need to move + /// Prefers the left side, to be optimal if the given node is somehow + /// underfull, meaning here only that it has fewer elements than its left + /// sibling and than its right sibling, if they exist. In that case, + /// merging with the left sibling is faster, since we only need to move /// the node's N elements, instead of shifting them to the right and moving /// more than N elements in front. Stealing from the left sibling is also /// typically faster, since we only need to shift the node's N elements to @@ -1293,19 +1295,19 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// the left. pub fn choose_parent_kv(self) -> Result>, Self> { match unsafe { ptr::read(&self) }.ascend() { - Ok(parent) => match parent.left_kv() { + Ok(parent_edge) => match parent_edge.left_kv() { Ok(left_parent_kv) => Ok(LeftOrRight::Left(BalancingContext { parent: unsafe { ptr::read(&left_parent_kv) }, left_child: left_parent_kv.left_edge().descend(), right_child: self, })), - Err(parent) => match parent.right_kv() { + Err(parent_edge) => match parent_edge.right_kv() { Ok(right_parent_kv) => Ok(LeftOrRight::Right(BalancingContext { parent: unsafe { ptr::read(&right_parent_kv) }, left_child: self, right_child: right_parent_kv.right_edge().descend(), })), - Err(_) => unreachable!("empty non-root node"), + Err(_) => unreachable!("empty internal node"), }, }, Err(root) => Err(root), diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs index 5ae1c1fcab80..d8a0d51f28a9 100644 --- a/library/alloc/src/collections/btree/remove.rs +++ b/library/alloc/src/collections/btree/remove.rs @@ -55,12 +55,12 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark pos = unsafe { new_pos.cast_to_leaf_unchecked() }; // Only if we merged, the parent (if any) has shrunk, but skipping - // the following step does not pay off in benchmarks. + // the following step otherwise does not pay off in benchmarks. // // SAFETY: We won't destroy or rearrange the leaf where `pos` is at // by handling its parent recursively; at worst we will destroy or // rearrange the parent through the grandparent, thus change the - // leaf's parent pointer. + // link to the parent inside the leaf. if let Ok(parent) = unsafe { pos.reborrow_mut() }.into_node().ascend() { parent.into_node().handle_shrunk_node_recursively(handle_emptied_internal_root); } @@ -92,8 +92,8 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { - /// Stocks up a possibly underfull internal node, recursively. - /// Climbs up until it reaches an ancestor that has elements to spare or the root. + /// Stocks up a possibly underfull internal node and its ancestors, + /// until it reaches an ancestor that has elements to spare or is the root. fn handle_shrunk_node_recursively(mut self, handle_emptied_internal_root: F) { loop { self = match self.len() { @@ -124,7 +124,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { ) -> Option, K, V, marker::Internal>> { match self.forget_type().choose_parent_kv() { Ok(Left(left_parent_kv)) => { - debug_assert!(left_parent_kv.right_child_len() == MIN_LEN - 1); + debug_assert_eq!(left_parent_kv.right_child_len(), MIN_LEN - 1); if left_parent_kv.can_merge() { let pos = left_parent_kv.merge(None); let parent_edge = unsafe { unwrap_unchecked(pos.into_node().ascend().ok()) }; @@ -136,7 +136,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { } } Ok(Right(right_parent_kv)) => { - debug_assert!(right_parent_kv.left_child_len() == MIN_LEN - 1); + debug_assert_eq!(right_parent_kv.left_child_len(), MIN_LEN - 1); if right_parent_kv.can_merge() { let pos = right_parent_kv.merge(None); let parent_edge = unsafe { unwrap_unchecked(pos.into_node().ascend().ok()) }; From 2b455aa7d805a2a88e231585c7e89cb1652d3d3c Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 12 Dec 2020 11:42:34 -0800 Subject: [PATCH 261/719] rustdoc light theme: Fix CSS for selected buttons The background was dark before, which made the text impossible to read. Now the background is white, which is how selected `div`s are rendered. As a result, the search results tabs now look identical to how they used to look (before #79896). --- src/librustdoc/html/static/themes/light.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 52cfdf6f7a38..997e1f00f859 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -349,8 +349,8 @@ pre.ignore:hover, .information:hover + pre.ignore { } #titles > button:hover, #titles > button.selected { + background-color: #ffffff; border-top-color: #0089ff; - background-color: #353535; } #titles > button > div.count { From 130dbe46427068bf642697f70f68938117e13625 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 12 Dec 2020 15:40:58 -0500 Subject: [PATCH 262/719] Remove incorrect assert --- src/librustdoc/passes/collect_intra_doc_links.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5ce64c4cd83c..e2fdf369087b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -436,8 +436,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); // NB: `split`'s first element is always defined, even if the delimiter was not present. + // NB: `item_str` could be empty when resolving in the root namespace (e.g. `::std`). let item_str = split.next().unwrap(); - assert!(!item_str.is_empty()); let item_name = Symbol::intern(item_str); let path_root = split .next() From 1e27b65d8e877fd33ff8de20c359282577b8956c Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Thu, 3 Dec 2020 12:37:19 -0600 Subject: [PATCH 263/719] Recover on `const impl<> X for Y` --- compiler/rustc_parse/src/parser/item.rs | 41 +++++++++++++++++-- .../const-impl-norecover.rs | 13 ++++++ .../const-impl-norecover.stderr | 8 ++++ .../const-impl-recovery.rs | 16 ++++++++ .../const-impl-recovery.stderr | 24 +++++++++++ 5 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5954b370e6d9..4c92c198679f 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -247,9 +247,14 @@ impl<'a> Parser<'a> { (ident, ItemKind::Static(ty, m, expr)) } else if let Const::Yes(const_span) = self.parse_constness() { // CONST ITEM - self.recover_const_mut(const_span); - let (ident, ty, expr) = self.parse_item_global(None)?; - (ident, ItemKind::Const(def(), ty, expr)) + if self.token.is_keyword(kw::Impl) { + // recover from `const impl`, suggest `impl const` + self.recover_const_impl(const_span, attrs, def())? + } else { + self.recover_const_mut(const_span); + let (ident, ty, expr) = self.parse_item_global(None)?; + (ident, ItemKind::Const(def(), ty, expr)) + } } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM self.parse_item_trait(attrs, lo)? @@ -988,6 +993,36 @@ impl<'a> Parser<'a> { } } + /// Recover on `const impl` with `const` already eaten. + fn recover_const_impl( + &mut self, + const_span: Span, + attrs: &mut Vec, + defaultness: Defaultness, + ) -> PResult<'a, ItemInfo> { + let impl_span = self.token.span; + let mut err = self.expected_ident_found(); + let mut impl_info = self.parse_item_impl(attrs, defaultness)?; + match impl_info.1 { + // only try to recover if this is implementing a trait for a type + ItemKind::Impl { of_trait: Some(ref trai), ref mut constness, .. } => { + *constness = Const::Yes(const_span); + + let before_trait = trai.path.span.shrink_to_lo(); + let const_up_to_impl = const_span.with_hi(impl_span.lo()); + err.multipart_suggestion( + "you might have meant to write a const trait impl", + vec![(const_up_to_impl, "".to_owned()), (before_trait, "const ".to_owned())], + Applicability::MaybeIncorrect, + ) + .emit(); + } + ItemKind::Impl { .. } => return Err(err), + _ => unreachable!(), + } + Ok(impl_info) + } + /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. /// diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs new file mode 100644 index 000000000000..936c90e88aae --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs @@ -0,0 +1,13 @@ +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +struct Foo; + +const impl Foo { //~ ERROR: expected identifier, found keyword + fn bar() {} +} + +fn main() { + // shouldn't error here because we shouldn't have been able to recover above + Foo::bar(); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr new file mode 100644 index 000000000000..612511a47995 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-norecover.rs:6:7 + | +LL | const impl Foo { + | ^^^^ expected identifier, found keyword + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs new file mode 100644 index 000000000000..fd3dd2cef9d1 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs @@ -0,0 +1,16 @@ +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +trait Foo {} + +const impl Foo for i32 {} //~ ERROR: expected identifier, found keyword + +trait Bar {} + +const impl Bar for T {} //~ ERROR: expected identifier, found keyword + +const fn still_implements() {} + +const _: () = still_implements::(); + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr new file mode 100644 index 000000000000..84fb619dc964 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr @@ -0,0 +1,24 @@ +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-recovery.rs:6:7 + | +LL | const impl Foo for i32 {} + | ^^^^ expected identifier, found keyword + | +help: you might have meant to write a const trait impl + | +LL | impl const Foo for i32 {} + |-- ^^^^^ + +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-recovery.rs:10:7 + | +LL | const impl Bar for T {} + | ^^^^ expected identifier, found keyword + | +help: you might have meant to write a const trait impl + | +LL | impl const Bar for T {} + |-- ^^^^^ + +error: aborting due to 2 previous errors + From bb6b6aeb786059ac0a84c090c8794a46108baaec Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Sat, 12 Dec 2020 21:00:47 +0000 Subject: [PATCH 264/719] Update RELEASES.md --- RELEASES.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 8f5d6db5db92..f9dadbec5772 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -25,7 +25,6 @@ Language let Person { name, ref age } = person; println!("{} {}", name, age); ``` -- [Macros that end with a semi-colon are now treated as statements even if they expand to nothing.][78376] Compiler ----------------------- @@ -73,10 +72,10 @@ Cargo Compatibility Notes ------------------- -- [Demoted `i686-unknown-freebsd` to tier 2 support.][78746] +- [Demoted `i686-unknown-freebsd` from host tier 2 to target tier 2 support.][78746] +- [Macros that end with a semi-colon are now treated as statements even if they expand to nothing.][78376] - [Rustc will now check for the validity of some built-in attributes on enum variants.][77015] Previously such invalid or unused attributes could be ignored. - Previously invalid or unused attributes were ignored. Internal Only ------------- From e6fa6334dd54f7c96514b520c5b9f261df3fc16b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 12 Dec 2020 15:20:22 -0500 Subject: [PATCH 265/719] Properly capture trailing 'unglued' token If we try to capture the `Vec` in `Option>`, we'll need to capture a `>` token which was 'unglued' from a `>>` token. The processing of unglueing a token for parsing purposes bypasses the usual capturing infrastructure, so we currently lose the trailing `>`. As a result, we fall back to the reparsed `TokenStream`, causing us to lose spans. This commit makes token capturing keep track of a trailing 'unglued' token. Note that we don't need to care about unglueing except at the end of the captured tokens - if we capture both the first and second unglued tokens, then we'll end up capturing the full 'glued' token, which already works correctly. --- compiler/rustc_parse/src/parser/mod.rs | 67 ++++++++++++++++--- .../ui/proc-macro/capture-unglued-token.rs | 20 ++++++ .../proc-macro/capture-unglued-token.stdout | 28 ++++++++ 3 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/proc-macro/capture-unglued-token.rs create mode 100644 src/test/ui/proc-macro/capture-unglued-token.stdout diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index df4695b18e71..d51a0fcbf09e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -17,7 +17,7 @@ pub use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, Spacing}; -use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit}; @@ -132,6 +132,28 @@ struct TokenCursor { // Counts the number of calls to `next` or `next_desugared`, // depending on whether `desugar_doc_comments` is set. num_next_calls: usize, + // During parsing, we may sometimes need to 'unglue' a + // glued token into two component tokens + // (e.g. '>>' into '>' and '>), so that the parser + // can consume them one at a time. This process + // bypasses the normal capturing mechanism + // (e.g. `num_next_calls` will not be incremented), + // since the 'unglued' tokens due not exist in + // the original `TokenStream`. + // + // If we end up consuming both unglued tokens, + // then this is not an issue - we'll end up + // capturing the single 'glued' token. + // + // However, in certain circumstances, we may + // want to capture just the first 'unglued' token. + // For example, capturing the `Vec` + // in `Option>` requires us to unglue + // the trailing `>>` token. The `append_unglued_token` + // field is used to track this token - it gets + // appended to the captured stream when + // we evaluate a `LazyTokenStream` + append_unglued_token: Option, } #[derive(Clone)] @@ -336,6 +358,7 @@ impl<'a> Parser<'a> { stack: Vec::new(), num_next_calls: 0, desugar_doc_comments, + append_unglued_token: None, }, desugar_doc_comments, unmatched_angle_bracket_count: 0, @@ -359,6 +382,10 @@ impl<'a> Parser<'a> { self.token_cursor.next() }; self.token_cursor.num_next_calls += 1; + // We've retrieved an token from the underlying + // cursor, so we no longer need to worry about + // an unglued token. See `break_and_eat` for more details + self.token_cursor.append_unglued_token = None; if next.span.is_dummy() { // Tweak the location for better diagnostics, but keep syntactic context intact. next.span = fallback_span.with_ctxt(next.span.ctxt()); @@ -555,6 +582,14 @@ impl<'a> Parser<'a> { let first_span = self.sess.source_map().start_point(self.token.span); let second_span = self.token.span.with_lo(first_span.hi()); self.token = Token::new(first, first_span); + // Keep track of this token - if we end token capturing now, + // we'll want to append this token to the captured stream. + // + // If we consume any additional tokens, then this token + // is not needed (we'll capture the entire 'glued' token), + // and `next_tok` will set this field to `None` + self.token_cursor.append_unglued_token = + Some((TokenTree::Token(self.token.clone()), Spacing::Alone)); // Use the spacing of the glued token as the spacing // of the unglued second token. self.bump_with((Token::new(second, second_span), self.token_spacing)); @@ -1230,6 +1265,7 @@ impl<'a> Parser<'a> { num_calls: usize, desugar_doc_comments: bool, trailing_semi: bool, + append_unglued_token: Option, } impl CreateTokenStream for LazyTokenStreamImpl { fn create_token_stream(&self) -> TokenStream { @@ -1253,12 +1289,18 @@ impl<'a> Parser<'a> { })) .take(num_calls); - make_token_stream(tokens) + make_token_stream(tokens, self.append_unglued_token.clone()) } fn add_trailing_semi(&self) -> Box { if self.trailing_semi { panic!("Called `add_trailing_semi` twice!"); } + if self.append_unglued_token.is_some() { + panic!( + "Cannot call `add_trailing_semi` when we have an unglued token {:?}", + self.append_unglued_token + ); + } let mut new = self.clone(); new.trailing_semi = true; Box::new(new) @@ -1271,6 +1313,7 @@ impl<'a> Parser<'a> { cursor_snapshot, desugar_doc_comments: self.desugar_doc_comments, trailing_semi: false, + append_unglued_token: self.token_cursor.append_unglued_token.clone(), }; Ok((ret, Some(LazyTokenStream::new(lazy_impl)))) } @@ -1325,7 +1368,10 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &Pa /// Converts a flattened iterator of tokens (including open and close delimiter tokens) /// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair /// of open and close delims. -fn make_token_stream(tokens: impl Iterator) -> TokenStream { +fn make_token_stream( + tokens: impl Iterator, + append_unglued_token: Option, +) -> TokenStream { #[derive(Debug)] struct FrameData { open: Span, @@ -1348,14 +1394,17 @@ fn make_token_stream(tokens: impl Iterator) -> TokenStr .inner .push((delimited, Spacing::Alone)); } - token => stack - .last_mut() - .expect("Bottom token frame is missing!") - .inner - .push((TokenTree::Token(token), spacing)), + token => { + stack + .last_mut() + .expect("Bottom token frame is missing!") + .inner + .push((TokenTree::Token(token), spacing)); + } } } - let final_buf = stack.pop().expect("Missing final buf!"); + let mut final_buf = stack.pop().expect("Missing final buf!"); + final_buf.inner.extend(append_unglued_token); assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack); TokenStream::new(final_buf.inner) } diff --git a/src/test/ui/proc-macro/capture-unglued-token.rs b/src/test/ui/proc-macro/capture-unglued-token.rs new file mode 100644 index 000000000000..727b779776b9 --- /dev/null +++ b/src/test/ui/proc-macro/capture-unglued-token.rs @@ -0,0 +1,20 @@ +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// check-pass + +// Tests that we properly handle parsing a nonterminal +// where we have two consecutive angle brackets (one inside +// the nonterminal, and one outside) + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; +extern crate test_macros; + +macro_rules! trailing_angle { + (Option<$field:ty>) => { + test_macros::print_bang_consume!($field); + } +} + +trailing_angle!(Option>); +fn main() {} diff --git a/src/test/ui/proc-macro/capture-unglued-token.stdout b/src/test/ui/proc-macro/capture-unglued-token.stdout new file mode 100644 index 000000000000..7e6b540332c7 --- /dev/null +++ b/src/test/ui/proc-macro/capture-unglued-token.stdout @@ -0,0 +1,28 @@ +PRINT-BANG INPUT (DISPLAY): Vec +PRINT-BANG RE-COLLECTED (DISPLAY): Vec < u8 > +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "Vec", + span: $DIR/capture-unglued-token.rs:19:24: 19:27 (#0), + }, + Punct { + ch: '<', + spacing: Alone, + span: $DIR/capture-unglued-token.rs:19:27: 19:28 (#0), + }, + Ident { + ident: "u8", + span: $DIR/capture-unglued-token.rs:19:28: 19:30 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/capture-unglued-token.rs:19:30: 19:31 (#0), + }, + ], + span: $DIR/capture-unglued-token.rs:15:42: 15:48 (#4), + }, +] From 5ce3f4c16636b261a8ce9ddfbbb30896338b9e37 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 11 Dec 2020 19:52:51 -0800 Subject: [PATCH 266/719] Resolve enum field visibility correctly Previously, this code treated enum fields' visibility as if they were struct fields. However, that's not correct because the visibility of a struct field with `ast::VisibilityKind::Inherited` is private to the module it's defined in, whereas the visibility of an *enum* field with `ast::VisibilityKind::Inherited` is the visibility of the enum it belongs to. --- .../rustc_resolve/src/build_reduced_graph.rs | 11 ++++++- compiler/rustc_resolve/src/lib.rs | 1 + compiler/rustc_typeck/src/check/expr.rs | 4 +-- src/test/ui/issues/issue-79593.rs | 29 ++++++++++++++++ src/test/ui/issues/issue-79593.stderr | 33 +++++++++++++++++++ 5 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/issues/issue-79593.rs create mode 100644 src/test/ui/issues/issue-79593.stderr diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 6d7e4ebc253b..06e9969697d0 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -258,7 +258,16 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))) } ast::VisibilityKind::Inherited => { - Ok(ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id)) + if matches!(self.parent_scope.module.kind, ModuleKind::Def(DefKind::Enum, _, _)) { + // Any inherited visibility resolved directly inside an enum + // (e.g. variants or fields) inherits from the visibility of the enum. + let parent_enum = self.parent_scope.module.def_id().unwrap().expect_local(); + Ok(self.r.visibilities[&parent_enum]) + } else { + // If it's not in an enum, its visibility is restricted to the `mod` item + // that it's defined in. + Ok(ty::Visibility::Restricted(self.parent_scope.module.normal_ancestor_id)) + } } ast::VisibilityKind::Restricted { ref path, id, .. } => { // For visibilities we are not ready to provide correct implementation of "uniform diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e8a06265adaf..f764fbc3f8da 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -403,6 +403,7 @@ enum PathResult<'a> { }, } +#[derive(Debug)] enum ModuleKind { /// An anonymous module; e.g., just a block. /// diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index b8a2a4779d98..ec0e039b5d29 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1248,7 +1248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if no_accessible_remaining_fields { self.report_no_accessible_fields(adt_ty, span); } else { - self.report_missing_field(adt_ty, span, remaining_fields); + self.report_missing_fields(adt_ty, span, remaining_fields); } } @@ -1279,7 +1279,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// error: aborting due to previous error /// ``` - fn report_missing_field( + fn report_missing_fields( &self, adt_ty: Ty<'tcx>, span: Span, diff --git a/src/test/ui/issues/issue-79593.rs b/src/test/ui/issues/issue-79593.rs new file mode 100644 index 000000000000..fb54b36940d5 --- /dev/null +++ b/src/test/ui/issues/issue-79593.rs @@ -0,0 +1,29 @@ +mod foo { + pub struct Pub { private: () } + + pub enum Enum { + Variant { x: (), y: () }, + Other + } + + fn correct() { + Pub {}; + //~^ ERROR missing field `private` in initializer of `Pub` + Enum::Variant { x: () }; + //~^ ERROR missing field `y` in initializer of `Enum` + } +} + +fn correct() { + foo::Pub {}; + //~^ ERROR cannot construct `Pub` with struct literal syntax due to inaccessible fields +} + +fn wrong() { + foo::Enum::Variant { x: () }; + //~^ ERROR missing field `y` in initializer of `Enum` + foo::Enum::Variant { }; + //~^ ERROR missing fields `x`, `y` in initializer of `Enum` +} + +fn main() {} diff --git a/src/test/ui/issues/issue-79593.stderr b/src/test/ui/issues/issue-79593.stderr new file mode 100644 index 000000000000..33dbd85032ea --- /dev/null +++ b/src/test/ui/issues/issue-79593.stderr @@ -0,0 +1,33 @@ +error[E0063]: missing field `private` in initializer of `Pub` + --> $DIR/issue-79593.rs:10:9 + | +LL | Pub {}; + | ^^^ missing `private` + +error[E0063]: missing field `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:12:9 + | +LL | Enum::Variant { x: () }; + | ^^^^^^^^^^^^^ missing `y` + +error: cannot construct `Pub` with struct literal syntax due to inaccessible fields + --> $DIR/issue-79593.rs:18:5 + | +LL | foo::Pub {}; + | ^^^^^^^^ + +error[E0063]: missing field `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:23:5 + | +LL | foo::Enum::Variant { x: () }; + | ^^^^^^^^^^^^^^^^^^ missing `y` + +error[E0063]: missing fields `x`, `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:25:5 + | +LL | foo::Enum::Variant { }; + | ^^^^^^^^^^^^^^^^^^ missing `x`, `y` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0063`. From 600efe7f1069029f57430c5e4994c58b2065178c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 12 Dec 2020 22:13:03 +0000 Subject: [PATCH 267/719] Remove an unused dependency that made `rustdoc` crash --- Cargo.lock | 3 --- .../rustc_mir/src/transform/coverage/test_macros/Cargo.toml | 3 --- 2 files changed, 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59525a29a805..12f9e19cf18b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -725,9 +725,6 @@ checksum = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6" [[package]] name = "coverage_test_macros" version = "0.0.0" -dependencies = [ - "proc-macro2", -] [[package]] name = "cpuid-bool" diff --git a/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml b/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml index a9d6f0c803d2..eda1ced001ca 100644 --- a/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml +++ b/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml @@ -7,6 +7,3 @@ edition = "2018" [lib] proc-macro = true doctest = false - -[dependencies] -proc-macro2 = "1" From 9df0348299df0a0ceeefd587700cabea6adc2d53 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Dec 2020 20:27:28 -0500 Subject: [PATCH 268/719] Fix building compiler docs with stage 0 --- src/bootstrap/builder.rs | 5 ++++- src/bootstrap/doc.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 6d97943548d5..9af79e20630d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -732,11 +732,14 @@ impl<'a> Builder<'a> { .env("CFG_RELEASE_CHANNEL", &self.config.channel) .env("RUSTDOC_REAL", self.rustdoc(compiler)) .env("RUSTC_BOOTSTRAP", "1") - .arg("-Znormalize_docs") .arg("-Winvalid_codeblock_attributes"); if self.config.deny_warnings { cmd.arg("-Dwarnings"); } + // cfg(not(bootstrap)), can be removed on the next beta bump + if compiler.stage != 0 { + cmd.arg("-Znormalize-docs"); + } // Remove make-related flags that can cause jobserver problems. cmd.env_remove("MAKEFLAGS"); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index a296a1fe3f4f..8cacc2512eff 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -527,7 +527,10 @@ impl Step for Rustc { cargo.rustdocflag("--document-private-items"); cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("-Zunstable-options"); - cargo.rustdocflag("-Znormalize-docs"); + // cfg(not(bootstrap)), can be removed on the next beta bump + if stage != 0 { + cargo.rustdocflag("-Znormalize-docs"); + } compile::rustc_cargo(builder, &mut cargo, target); // Only include compiler crates, no dependencies of those, such as `libc`. From 98118bbde42112f74d2707c0a167a0a27191438c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 Dec 2020 23:30:13 +0100 Subject: [PATCH 269/719] Fixes submit event of the search input In HTML, when a button follows an input, if the enter keep is pressed on the input, instead of sending the submit event to the input, it'll create a click event on the button following it, which in this case made the help popup show up whenever "enter" was pressed. --- src/librustdoc/html/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index f2c74c46d7db..b5169b059977 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -98,7 +98,7 @@ crate fn render( placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \ type=\"search\">\ \ - +
\ Date: Fri, 11 Dec 2020 11:32:48 -0800 Subject: [PATCH 270/719] Improve error handling in `symbols` proc-macro This improves how the `symbols` proc-macro handles errors. If it finds an error in its input, the macro does not panic. Instead, it still produces an output token stream. That token stream will contain `compile_error!(...)` macro invocations. This will still cause compilation to fail (which is what we want), but it will prevent meaningless errors caused by the output not containing symbols that the macro normally generates. This solves a small (but annoying) problem. When you're editing rustc_span/src/symbol.rs, and you get something wrong (dup symbol name, misordered symbol), you want to get only the errors that are relevant, not a burst of errors that are irrelevant. This change also uses the correct Span when reporting errors, so you get errors that point to the correct place in rustc_span/src/symbol.rs where something is wrong. This also adds several unit tests which test the `symbols` proc-macro. This commit also makes it easy to run the `symbols` proc-macro as an ordinary Cargo test. Just run `cargo test`. This makes it easier to do development on the macro itself, such as running it under a debugger. This commit also uses the `Punctuated` type in `syn` for parsing comma-separated lists, rather than doing it manually. The output of the macro is not changed at all by this commit, so rustc should be completely unchanged. This just improves quality of life during development. --- compiler/rustc_macros/src/lib.rs | 2 +- compiler/rustc_macros/src/symbols.rs | 152 ++++++++++++++------- compiler/rustc_macros/src/symbols/tests.rs | 111 +++++++++++++++ 3 files changed, 212 insertions(+), 53 deletions(-) create mode 100644 compiler/rustc_macros/src/symbols/tests.rs diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 5c28839c9b7e..152ae159aed4 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -21,7 +21,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { #[proc_macro] pub fn symbols(input: TokenStream) -> TokenStream { - symbols::symbols(input) + symbols::symbols(input.into()).into() } decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 94d4ad78e8d9..f449900d5c24 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -1,8 +1,35 @@ -use proc_macro::TokenStream; +//! Proc macro which builds the Symbol table +//! +//! # Debugging +//! +//! Since this proc-macro does some non-trivial work, debugging it is important. +//! This proc-macro can be invoked as an ordinary unit test, like so: +//! +//! ```bash +//! cd compiler/rustc_macros +//! cargo test symbols::test_symbols -- --nocapture +//! ``` +//! +//! This unit test finds the `symbols!` invocation in `compiler/rustc_span/src/symbol.rs` +//! and runs it. It verifies that the output token stream can be parsed as valid module +//! items and that no errors were produced. +//! +//! You can also view the generated code by using `cargo expand`: +//! +//! ```bash +//! cargo install cargo-expand # this is necessary only once +//! cd compiler/rustc_span +//! cargo expand > /tmp/rustc_span.rs # it's a big file +//! ``` + +use proc_macro2::{Span, TokenStream}; use quote::quote; -use std::collections::HashSet; +use std::collections::HashMap; use syn::parse::{Parse, ParseStream, Result}; -use syn::{braced, parse_macro_input, Ident, LitStr, Token}; +use syn::{braced, punctuated::Punctuated, Ident, LitStr, Token}; + +#[cfg(test)] +mod tests; mod kw { syn::custom_keyword!(Keywords); @@ -19,7 +46,6 @@ impl Parse for Keyword { let name = input.parse()?; input.parse::()?; let value = input.parse()?; - input.parse::()?; Ok(Keyword { name, value }) } @@ -37,28 +63,14 @@ impl Parse for Symbol { Ok(_) => Some(input.parse()?), Err(_) => None, }; - input.parse::()?; Ok(Symbol { name, value }) } } -/// A type used to greedily parse another type until the input is empty. -struct List(Vec); - -impl Parse for List { - fn parse(input: ParseStream<'_>) -> Result { - let mut list = Vec::new(); - while !input.is_empty() { - list.push(input.parse()?); - } - Ok(List(list)) - } -} - struct Input { - keywords: List, - symbols: List, + keywords: Punctuated, + symbols: Punctuated, } impl Parse for Input { @@ -66,49 +78,86 @@ impl Parse for Input { input.parse::()?; let content; braced!(content in input); - let keywords = content.parse()?; + let keywords = Punctuated::parse_terminated(&content)?; input.parse::()?; let content; braced!(content in input); - let symbols = content.parse()?; + let symbols = Punctuated::parse_terminated(&content)?; Ok(Input { keywords, symbols }) } } +#[derive(Default)] +struct Errors { + list: Vec, +} + +impl Errors { + fn error(&mut self, span: Span, message: String) { + self.list.push(syn::Error::new(span, message)); + } +} + pub fn symbols(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as Input); + let (mut output, errors) = symbols_with_errors(input); + + // If we generated any errors, then report them as compiler_error!() macro calls. + // This lets the errors point back to the most relevant span. It also allows us + // to report as many errors as we can during a single run. + output.extend(errors.into_iter().map(|e| e.to_compile_error())); + + output +} + +fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { + let mut errors = Errors::default(); + + let input: Input = match syn::parse2(input) { + Ok(input) => input, + Err(e) => { + // This allows us to display errors at the proper span, while minimizing + // unrelated errors caused by bailing out (and not generating code). + errors.list.push(e); + Input { keywords: Default::default(), symbols: Default::default() } + } + }; let mut keyword_stream = quote! {}; let mut symbols_stream = quote! {}; let mut digits_stream = quote! {}; let mut prefill_stream = quote! {}; let mut counter = 0u32; - let mut keys = HashSet::::new(); - let mut prev_key: Option = None; - let mut errors = Vec::::new(); + let mut keys = + HashMap::::with_capacity(input.keywords.len() + input.symbols.len() + 10); + let mut prev_key: Option<(Span, String)> = None; - let mut check_dup = |str: &str, errors: &mut Vec| { - if !keys.insert(str.to_string()) { - errors.push(format!("Symbol `{}` is duplicated", str)); + let mut check_dup = |span: Span, str: &str, errors: &mut Errors| { + if let Some(prev_span) = keys.get(str) { + errors.error(span, format!("Symbol `{}` is duplicated", str)); + errors.error(*prev_span, format!("location of previous definition")); + } else { + keys.insert(str.to_string(), span); } }; - let mut check_order = |str: &str, errors: &mut Vec| { - if let Some(ref prev_str) = prev_key { + let mut check_order = |span: Span, str: &str, errors: &mut Errors| { + if let Some((prev_span, ref prev_str)) = prev_key { if str < prev_str { - errors.push(format!("Symbol `{}` must precede `{}`", str, prev_str)); + errors.error(span, format!("Symbol `{}` must precede `{}`", str, prev_str)); + errors.error(prev_span, format!("location of previous symbol `{}`", prev_str)); } } - prev_key = Some(str.to_string()); + prev_key = Some((span, str.to_string())); }; // Generate the listed keywords. - for keyword in &input.keywords.0 { + for keyword in input.keywords.iter() { let name = &keyword.name; let value = &keyword.value; - check_dup(&value.value(), &mut errors); + let value_string = value.value(); + check_dup(keyword.name.span(), &value_string, &mut errors); prefill_stream.extend(quote! { #value, }); @@ -120,14 +169,15 @@ pub fn symbols(input: TokenStream) -> TokenStream { } // Generate the listed symbols. - for symbol in &input.symbols.0 { + for symbol in input.symbols.iter() { let name = &symbol.name; let value = match &symbol.value { Some(value) => value.value(), None => name.to_string(), }; - check_dup(&value, &mut errors); - check_order(&name.to_string(), &mut errors); + check_dup(symbol.name.span(), &value, &mut errors); + check_order(symbol.name.span(), &name.to_string(), &mut errors); + prefill_stream.extend(quote! { #value, }); @@ -142,7 +192,7 @@ pub fn symbols(input: TokenStream) -> TokenStream { // Generate symbols for the strings "0", "1", ..., "9". for n in 0..10 { let n = n.to_string(); - check_dup(&n, &mut errors); + check_dup(Span::call_site(), &n, &mut errors); prefill_stream.extend(quote! { #n, }); @@ -152,14 +202,7 @@ pub fn symbols(input: TokenStream) -> TokenStream { counter += 1; } - if !errors.is_empty() { - for error in errors.into_iter() { - eprintln!("error: {}", error) - } - panic!("errors in `Keywords` and/or `Symbols`"); - } - - let tt = TokenStream::from(quote! { + let output = quote! { macro_rules! keywords { () => { #keyword_stream @@ -184,11 +227,16 @@ pub fn symbols(input: TokenStream) -> TokenStream { ]) } } - }); + }; - // To see the generated code generated, uncomment this line, recompile, and - // run the resulting output through `rustfmt`. - //eprintln!("{}", tt); + (output, errors.list) - tt + // To see the generated code, use the "cargo expand" command. + // Do this once to install: + // cargo install cargo-expand + // + // Then, cd to rustc_span and run: + // cargo expand > /tmp/rustc_span_expanded.rs + // + // and read that file. } diff --git a/compiler/rustc_macros/src/symbols/tests.rs b/compiler/rustc_macros/src/symbols/tests.rs new file mode 100644 index 000000000000..90a28b518020 --- /dev/null +++ b/compiler/rustc_macros/src/symbols/tests.rs @@ -0,0 +1,111 @@ +use super::*; + +// This test is mainly here for interactive development. Use this test while +// you're working on the proc-macro defined in this file. +#[test] +fn test_symbols() { + // We textually include the symbol.rs file, which contains the list of all + // symbols, keywords, and common words. Then we search for the + // `symbols! { ... }` call. + + static SYMBOL_RS_FILE: &str = include_str!("../../../rustc_span/src/symbol.rs"); + + let file = syn::parse_file(SYMBOL_RS_FILE).unwrap(); + let symbols_path: syn::Path = syn::parse_quote!(symbols); + + let m: &syn::ItemMacro = file + .items + .iter() + .filter_map(|i| { + if let syn::Item::Macro(m) = i { + if m.mac.path == symbols_path { Some(m) } else { None } + } else { + None + } + }) + .next() + .expect("did not find `symbols!` macro invocation."); + + let body_tokens = m.mac.tokens.clone(); + + test_symbols_macro(body_tokens, &[]); +} + +fn test_symbols_macro(input: TokenStream, expected_errors: &[&str]) { + let (output, found_errors) = symbols_with_errors(input); + + // It should always parse. + let _parsed_file = syn::parse2::(output).unwrap(); + + assert_eq!( + found_errors.len(), + expected_errors.len(), + "Macro generated a different number of errors than expected" + ); + + for (found_error, &expected_error) in found_errors.iter().zip(expected_errors.iter()) { + let found_error_str = format!("{}", found_error); + assert_eq!(found_error_str, expected_error); + } +} + +#[test] +fn check_dup_keywords() { + let input = quote! { + Keywords { + Crate: "crate", + Crate: "crate", + } + Symbols {} + }; + test_symbols_macro( + input, + &["Symbol `crate` is duplicated", "location of previous definition"], + ); +} + +#[test] +fn check_dup_symbol() { + let input = quote! { + Keywords {} + Symbols { + splat, + splat, + } + }; + test_symbols_macro( + input, + &["Symbol `splat` is duplicated", "location of previous definition"], + ); +} + +#[test] +fn check_dup_symbol_and_keyword() { + let input = quote! { + Keywords { + Splat: "splat", + } + Symbols { + splat, + } + }; + test_symbols_macro( + input, + &["Symbol `splat` is duplicated", "location of previous definition"], + ); +} + +#[test] +fn check_symbol_order() { + let input = quote! { + Keywords {} + Symbols { + zebra, + aardvark, + } + }; + test_symbols_macro( + input, + &["Symbol `aardvark` must precede `zebra`", "location of previous symbol `zebra`"], + ); +} From ad75a96b34c0c52036c7e903cc97816cdba150f8 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 23 Nov 2020 14:41:53 +0100 Subject: [PATCH 271/719] BTreeMap: detect bulk_steal's count-1 underflow in release builds too --- library/alloc/src/collections/btree/node.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 31809fde57b7..ffa18201431a 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -1469,6 +1469,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// This does stealing similar to `steal_left` but steals multiple elements at once. pub fn bulk_steal_left(&mut self, count: usize) { + assert!(count > 0); unsafe { let left_node = &mut self.left_child; let old_left_len = left_node.len(); @@ -1526,6 +1527,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// The symmetric clone of `bulk_steal_left`. pub fn bulk_steal_right(&mut self, count: usize) { + assert!(count > 0); unsafe { let left_node = &mut self.left_child; let old_left_len = left_node.len(); From 0ae4c95effa98e30d980264892860e7a0f727b4f Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 23 Nov 2020 14:41:53 +0100 Subject: [PATCH 272/719] BTreeMap: capture a recurring use pattern as replace_kv --- library/alloc/src/collections/btree/node.rs | 12 ++++++++---- library/alloc/src/collections/btree/remove.rs | 6 ++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 31809fde57b7..ae5831d51406 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -1159,6 +1159,12 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> (key, val) } } + + /// Replace the key and value that the KV handle refers to. + pub fn replace_kv(&mut self, k: K, v: V) -> (K, V) { + let (key, val) = self.kv_mut(); + (mem::replace(key, k), mem::replace(val, v)) + } } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { @@ -1432,8 +1438,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { unsafe { let (k, v, edge) = self.left_child.pop(); - let k = mem::replace(self.parent.kv_mut().0, k); - let v = mem::replace(self.parent.kv_mut().1, v); + let (k, v) = self.parent.replace_kv(k, v); match self.right_child.reborrow_mut().force() { ForceResult::Leaf(mut leaf) => leaf.push_front(k, v), @@ -1455,8 +1460,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { unsafe { let (k, v, edge) = self.right_child.pop_front(); - let k = mem::replace(self.parent.kv_mut().0, k); - let v = mem::replace(self.parent.kv_mut().1, v); + let (k, v) = self.parent.replace_kv(k, v); match self.left_child.reborrow_mut().force() { ForceResult::Leaf(mut leaf) => leaf.push(k, v), diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs index 5ae1c1fcab80..1da0a0608064 100644 --- a/library/alloc/src/collections/btree/remove.rs +++ b/library/alloc/src/collections/btree/remove.rs @@ -1,7 +1,6 @@ use super::map::MIN_LEN; use super::node::{marker, ForceResult::*, Handle, LeftOrRight::*, NodeRef}; use super::unwrap_unchecked; -use core::mem; impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInternal>, marker::KV> { /// Removes a key-value pair from the tree, and returns that pair, as well as @@ -84,10 +83,9 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, // The internal node may have been stolen from or merged. Go back right // to find where the original KV ended up. let mut internal = unsafe { unwrap_unchecked(left_hole.next_kv().ok()) }; - let old_key = mem::replace(internal.kv_mut().0, left_kv.0); - let old_val = mem::replace(internal.kv_mut().1, left_kv.1); + let old_kv = internal.replace_kv(left_kv.0, left_kv.1); let pos = internal.next_leaf_edge(); - ((old_key, old_val), pos) + (old_kv, pos) } } From 3af09b8cf1229fb05a549a13b144aca6b60784c7 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sun, 13 Dec 2020 06:32:41 +0200 Subject: [PATCH 273/719] New internal lint: interning_defined_symbol --- clippy_lints/src/lib.rs | 4 + clippy_lints/src/utils/internal_lints.rs | 80 +++++++++++++++++++ clippy_lints/src/utils/paths.rs | 6 ++ .../interning_defined_symbol.fixed | 33 ++++++++ tests/ui-internal/interning_defined_symbol.rs | 33 ++++++++ .../interning_defined_symbol.stderr | 27 +++++++ 6 files changed, 183 insertions(+) create mode 100644 tests/ui-internal/interning_defined_symbol.fixed create mode 100644 tests/ui-internal/interning_defined_symbol.rs create mode 100644 tests/ui-internal/interning_defined_symbol.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f06926fa91d3..97018599b05a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -513,6 +513,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: #[cfg(feature = "internal-lints")] &utils::internal_lints::INVALID_PATHS, #[cfg(feature = "internal-lints")] + &utils::internal_lints::INTERNING_DEFINED_SYMBOL, + #[cfg(feature = "internal-lints")] &utils::internal_lints::LINT_WITHOUT_LINT_PASS, #[cfg(feature = "internal-lints")] &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, @@ -958,6 +960,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); store.register_late_pass(|| box utils::internal_lints::InvalidPaths); + store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default()); store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass); @@ -1350,6 +1353,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS), LintId::of(&utils::internal_lints::DEFAULT_LINT), LintId::of(&utils::internal_lints::INVALID_PATHS), + LintId::of(&utils::internal_lints::INTERNING_DEFINED_SYMBOL), LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS), LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA), diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 8b59a9541a73..0de87fab528a 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -15,6 +15,7 @@ use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Node, Path, StmtKind, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_middle::hir::map::Map; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; @@ -247,6 +248,30 @@ declare_clippy_lint! { "invalid path" } +declare_clippy_lint! { + /// **What it does:** + /// Checks for interning symbols that have already been pre-interned and defined as constants. + /// + /// **Why is this bad?** + /// It's faster and easier to use the symbol constant. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// Bad: + /// ```rust,ignore + /// let _ = sym!(f32); + /// ``` + /// + /// Good: + /// ```rust,ignore + /// let _ = sym::f32; + /// ``` + pub INTERNING_DEFINED_SYMBOL, + internal, + "interning a symbol that is pre-interned and defined as a constant" +} + declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]); impl EarlyLintPass for ClippyLintsInternal { @@ -840,3 +865,58 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths { } } } + +#[derive(Default)] +pub struct InterningDefinedSymbol { + // Maps the symbol to the constant name. + symbol_map: FxHashMap, +} + +impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL]); + +impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { + fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { + if !self.symbol_map.is_empty() { + return; + } + + if let Some(Res::Def(_, def_id)) = path_to_res(cx, &paths::SYM_MODULE) { + for item in cx.tcx.item_children(def_id).iter() { + if_chain! { + if let Res::Def(DefKind::Const, item_def_id) = item.res; + let ty = cx.tcx.type_of(item_def_id); + if match_type(cx, ty, &paths::SYMBOL); + if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id); + if let Ok(value) = value.to_u32(); + then { + // SAFETY: We're converting the raw bytes of the symbol value back + // into a Symbol instance. + let symbol = unsafe { std::mem::transmute::(value) }; + self.symbol_map.insert(symbol.to_string(), item.ident.to_string()); + } + } + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + if let ExprKind::Call(func, [arg]) = &expr.kind; + if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind(); + if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN); + if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg); + if let Some(symbol_const) = self.symbol_map.get(&arg); + then { + span_lint_and_sugg( + cx, + INTERNING_DEFINED_SYMBOL, + is_expn_of(expr.span, "sym").unwrap_or(expr.span), + "interning a defined symbol", + "try", + format!("rustc_span::symbol::sym::{}", symbol_const), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 6fdc7b4587f0..2080a49a11cd 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -146,6 +146,12 @@ pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "", "starts_with"]; #[cfg(feature = "internal-lints")] +pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"]; +#[cfg(feature = "internal-lints")] +pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"]; +#[cfg(feature = "internal-lints")] +pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; +#[cfg(feature = "internal-lints")] pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"]; pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"]; diff --git a/tests/ui-internal/interning_defined_symbol.fixed b/tests/ui-internal/interning_defined_symbol.fixed new file mode 100644 index 000000000000..c6b84d2ef650 --- /dev/null +++ b/tests/ui-internal/interning_defined_symbol.fixed @@ -0,0 +1,33 @@ +// run-rustfix +#![deny(clippy::internal)] +#![feature(rustc_private)] + +extern crate rustc_span; + +use rustc_span::symbol::Symbol; + +macro_rules! sym { + ($tt:tt) => { + rustc_span::symbol::Symbol::intern(stringify!($tt)) + }; +} + +fn main() { + // Direct use of Symbol::intern + let _ = rustc_span::symbol::sym::f32; + + // Using a sym macro + let _ = rustc_span::symbol::sym::f32; + + // Correct suggestion when symbol isn't stringified constant name + let _ = rustc_span::symbol::sym::proc_dash_macro; + + // Interning a symbol that is not defined + let _ = Symbol::intern("xyz123"); + let _ = sym!(xyz123); + + // Using a different `intern` function + let _ = intern("f32"); +} + +fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_defined_symbol.rs b/tests/ui-internal/interning_defined_symbol.rs new file mode 100644 index 000000000000..9ec82d4ad0ba --- /dev/null +++ b/tests/ui-internal/interning_defined_symbol.rs @@ -0,0 +1,33 @@ +// run-rustfix +#![deny(clippy::internal)] +#![feature(rustc_private)] + +extern crate rustc_span; + +use rustc_span::symbol::Symbol; + +macro_rules! sym { + ($tt:tt) => { + rustc_span::symbol::Symbol::intern(stringify!($tt)) + }; +} + +fn main() { + // Direct use of Symbol::intern + let _ = Symbol::intern("f32"); + + // Using a sym macro + let _ = sym!(f32); + + // Correct suggestion when symbol isn't stringified constant name + let _ = Symbol::intern("proc-macro"); + + // Interning a symbol that is not defined + let _ = Symbol::intern("xyz123"); + let _ = sym!(xyz123); + + // Using a different `intern` function + let _ = intern("f32"); +} + +fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_defined_symbol.stderr b/tests/ui-internal/interning_defined_symbol.stderr new file mode 100644 index 000000000000..74b906c8a579 --- /dev/null +++ b/tests/ui-internal/interning_defined_symbol.stderr @@ -0,0 +1,27 @@ +error: interning a defined symbol + --> $DIR/interning_defined_symbol.rs:17:13 + | +LL | let _ = Symbol::intern("f32"); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::sym::f32` + | +note: the lint level is defined here + --> $DIR/interning_defined_symbol.rs:2:9 + | +LL | #![deny(clippy::internal)] + | ^^^^^^^^^^^^^^^^ + = note: `#[deny(clippy::interning_defined_symbol)]` implied by `#[deny(clippy::internal)]` + +error: interning a defined symbol + --> $DIR/interning_defined_symbol.rs:20:13 + | +LL | let _ = sym!(f32); + | ^^^^^^^^^ help: try: `rustc_span::symbol::sym::f32` + +error: interning a defined symbol + --> $DIR/interning_defined_symbol.rs:23:13 + | +LL | let _ = Symbol::intern("proc-macro"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::sym::proc_dash_macro` + +error: aborting due to 3 previous errors + From a6aa0acbeaeb74a50e08bfa2b18df4e22dbd9894 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sun, 13 Dec 2020 06:32:41 +0200 Subject: [PATCH 274/719] Fix dogfood errors --- clippy_lints/src/manual_ok_or.rs | 3 ++- clippy_lints/src/methods/mod.rs | 10 +++++----- clippy_lints/src/ref_option_ref.rs | 3 ++- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 5 +++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index c99d2e35b94a..b97d97ea1a5e 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -8,6 +8,7 @@ use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; declare_clippy_lint! { /// **What it does:** @@ -51,7 +52,7 @@ impl LateLintPass<'_> for ManualOkOr { if args.len() == 3; let method_receiver = &args[0]; let ty = cx.typeck_results().expr_ty(method_receiver); - if is_type_diagnostic_item(cx, ty, sym!(option_type)); + if is_type_diagnostic_item(cx, ty, sym::option_type); let or_expr = &args[1]; if is_ok_wrapping(cx, &args[2]); if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5133f31e0e7b..c5eab2a97fe0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1568,7 +1568,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); - if args.len() == 1 && method_call.ident.name == sym!(clone) { + if args.len() == 1 && method_call.ident.name == sym::clone { lint_clone_on_copy(cx, expr, &args[0], self_ty); lint_clone_on_ref_ptr(cx, expr, &args[0]); } @@ -1592,7 +1592,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } }, - ty::Ref(..) if method_call.ident.name == sym!(into_iter) => { + ty::Ref(..) if method_call.ident.name == sym::into_iter => { lint_into_iter(cx, expr, self_ty, *method_span); }, _ => (), @@ -2638,9 +2638,9 @@ fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::E fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { Some((EXPECT_USED, "an Option", "None")) - } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) { + } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { Some((EXPECT_USED, "a Result", "Err")) } else { None @@ -3133,7 +3133,7 @@ fn lint_search_is_some<'tcx>( else if search_method == "find" { let is_string_or_str_slice = |e| { let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); - if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, self_ty, sym::string_type) { true } else { *self_ty.kind() == ty::Str diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index a914a77d48b4..803ebada54b7 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -2,6 +2,7 @@ use crate::utils::{last_path_segment, snippet, span_lint_and_sugg}; use rustc_hir::{GenericArg, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; use if_chain::if_chain; use rustc_errors::Applicability; @@ -41,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { if let Some(res) = last.res; if let Some(def_id) = res.opt_def_id(); - if cx.tcx.is_diagnostic_item(sym!(option_type), def_id); + if cx.tcx.is_diagnostic_item(sym::option_type, def_id); if let Some(ref params) = last_path_segment(qpath).args ; if !params.parenthesized; if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 77e790733789..31dd5965473d 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -372,7 +372,7 @@ impl LateLintPass<'_> for StringToString { if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; if path.ident.name == sym!(to_string); let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym!(string_type)); + if is_type_diagnostic_item(cx, ty, sym::string_type); then { span_lint_and_help( cx, diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index e763da593d49..5b9a80f92db6 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -9,6 +9,7 @@ use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; use rustc_span::Span; declare_clippy_lint! { @@ -82,9 +83,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } } - let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { + let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::option_type) { ("Option", &paths::OPTION_SOME) - } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { + } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) { ("Result", &paths::RESULT_OK) } else { return; From 64e630c28018972479394a2fbdcc9f7d8856bb91 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sun, 13 Dec 2020 06:46:08 +0200 Subject: [PATCH 275/719] Run 'cargo dev update_lints' --- clippy_lints/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 97018599b05a..0498d469c00b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -511,10 +511,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: #[cfg(feature = "internal-lints")] &utils::internal_lints::DEFAULT_LINT, #[cfg(feature = "internal-lints")] - &utils::internal_lints::INVALID_PATHS, - #[cfg(feature = "internal-lints")] &utils::internal_lints::INTERNING_DEFINED_SYMBOL, #[cfg(feature = "internal-lints")] + &utils::internal_lints::INVALID_PATHS, + #[cfg(feature = "internal-lints")] &utils::internal_lints::LINT_WITHOUT_LINT_PASS, #[cfg(feature = "internal-lints")] &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, @@ -1352,8 +1352,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS), LintId::of(&utils::internal_lints::DEFAULT_LINT), - LintId::of(&utils::internal_lints::INVALID_PATHS), LintId::of(&utils::internal_lints::INTERNING_DEFINED_SYMBOL), + LintId::of(&utils::internal_lints::INVALID_PATHS), LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS), LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA), From b66eb696af9ef1952f2582b2b8ec07156868b2f6 Mon Sep 17 00:00:00 2001 From: Yenlin Chen <3822365+hencrice@users.noreply.github.com> Date: Sun, 13 Dec 2020 04:14:08 +0000 Subject: [PATCH 276/719] Refactored verbose print into a function Also handle Tuple and Array separately, which was not explicitly checked. Fixes #79799. --- compiler/rustc_mir/src/util/pretty.rs | 44 ++++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index cd60602b088f..9b81629400a6 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -17,7 +17,8 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; use rustc_target::abi::Size; use std::ops::ControlFlow; @@ -408,6 +409,33 @@ impl ExtraComments<'tcx> { } } +fn use_verbose(ty: &&TyS<'tcx>) -> bool { + match ty.kind() { + ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, + // Unit type + ty::Tuple(g_args) if g_args.is_empty() => false, + ty::Tuple(g_args) => { + // could have used `try_fold` here but it seems a bit silly that + // the accumulator is useless + let mut should_be_verbose = false; + for g_arg in g_args.iter() { + if match g_arg.unpack() { + GenericArgKind::Type(ty) => use_verbose(&ty), + GenericArgKind::Const(ty::Const { ty, val: _ }) => use_verbose(ty), + _ => false, + } { + should_be_verbose = true; + break; + } + } + should_be_verbose + } + ty::Array(ty, _) => use_verbose(ty), + ty::FnDef(..) => false, + _ => true, + } +} + impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); @@ -430,16 +458,10 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); let ty::Const { ty, val, .. } = constant; - match ty.kind() { - ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => {} - // Unit type - ty::Tuple(tys) if tys.is_empty() => {} - ty::FnDef(..) => {} - _ => { - self.push("ty::Const"); - self.push(&format!("+ ty: {:?}", ty)); - self.push(&format!("+ val: {:?}", val)); - } + if use_verbose(ty) { + self.push("ty::Const"); + self.push(&format!("+ ty: {:?}", ty)); + self.push(&format!("+ val: {:?}", val)); } } From 0f30b7dd87b8555698ca7e7de360b037230e1f23 Mon Sep 17 00:00:00 2001 From: Justus K Date: Sun, 13 Dec 2020 10:02:36 +0100 Subject: [PATCH 277/719] fix panic if converting ZST Vec to VecDeque --- library/alloc/src/collections/vec_deque/mod.rs | 8 ++++++-- library/alloc/tests/vec_deque.rs | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 57807bc54539..1303b58e31c9 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2793,8 +2793,12 @@ impl From> for VecDeque { let len = other.len(); // 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.capacity().is_power_of_two() + // or doesn't have at least one free space. + // We check if `T` is a ZST in the first condition, + // because `usize::MAX` (the capacity returned by `capacity()` for ZST) + // is not a power of zero and thus it'll always try + // to reserve more memory which will panic for ZST (rust-lang/rust#78532) + if (!buf.capacity().is_power_of_two() && mem::size_of::() != 0) || (buf.capacity() < (MINIMUM_CAPACITY + 1)) || (buf.capacity() == len) { diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 705f0d62fbb7..a962a5494a9a 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1728,3 +1728,10 @@ fn test_zero_sized_push() { } } } + +#[test] +fn test_from_zero_sized_vec() { + let v = vec![(); 100]; + let queue = VecDeque::from(v); + assert!(queue.len(), 100); +} From d75618e7a2517d4b39c4e50ff1644f595a86e92b Mon Sep 17 00:00:00 2001 From: Justus K Date: Sun, 13 Dec 2020 10:21:24 +0100 Subject: [PATCH 278/719] replace assert! with assert_eq! --- library/alloc/tests/vec_deque.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index a962a5494a9a..0919b1325bce 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1733,5 +1733,5 @@ fn test_zero_sized_push() { fn test_from_zero_sized_vec() { let v = vec![(); 100]; let queue = VecDeque::from(v); - assert!(queue.len(), 100); + assert_eq!(queue.len(), 100); } From cd21269ae0b3c9f516b0322b522255da03afcc76 Mon Sep 17 00:00:00 2001 From: Jesse Date: Sun, 13 Dec 2020 10:58:47 +0100 Subject: [PATCH 279/719] Fix Cranelift link in readme (#1118) --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index de54bf67f4a1..b0ea95692f3f 100644 --- a/Readme.md +++ b/Readme.md @@ -2,7 +2,7 @@ > ⚠⚠⚠ Certain kinds of FFI don't work yet. ⚠⚠⚠ -The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/master/cranelift). +The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/main/cranelift). This has the potential to improve compilation times in debug mode. If your project doesn't use any of the things listed under "Not yet supported", it should work fine. If not please open an issue. From bdc6adfb3bf3723268ac05540cc88bcca1b31227 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 23 Nov 2020 14:41:53 +0100 Subject: [PATCH 280/719] BTreeMap: declare clear_parent_link directly on the root it needs --- library/alloc/src/collections/btree/node.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index ae5831d51406..968e197f1706 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -150,7 +150,7 @@ impl NodeRef { /// Mutably borrows the owned node. Unlike `reborrow_mut`, this is safe, /// because the return value cannot be used to destroy the node itself, /// and there cannot be other references to the tree (except during the - /// process of `into_iter` or `drop`, but that is a horrific already). + /// process of `into_iter` or `drop`, but that is horrific already). pub fn borrow_mut(&mut self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } @@ -192,7 +192,7 @@ impl NodeRef { let internal_node = NodeRef { height: self.height, node: top, _marker: PhantomData }; *self = internal_node.first_edge().descend(); - self.borrow_mut().clear_parent_link(); + self.clear_parent_link(); unsafe { Global.deallocate(top.cast(), Layout::new::>()); @@ -611,18 +611,19 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { - /// Set or clear the node's link to its parent edge, + /// Sets the node's link to its parent edge, /// without invalidating other references to the node. fn set_parent_link(&mut self, parent: NonNull>, parent_idx: usize) { let leaf = Self::as_leaf_ptr(self); unsafe { (*leaf).parent = Some(parent) }; unsafe { (*leaf).parent_idx.write(parent_idx as u16) }; } +} - /// Clear the node's link to its parent edge. - /// This only makes sense when there are no other references to the node. +impl NodeRef { + /// Clears the root's link to its parent edge. fn clear_parent_link(&mut self) { - let leaf = Self::as_leaf_mut(self); + let leaf = NodeRef::as_leaf_mut(&mut self.borrow_mut()); leaf.parent = None; } } @@ -720,9 +721,9 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { ForceResult::Internal(internal) => { let node = ptr::read(internal.reborrow().edge_at(idx + 1)); let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; - // In practice, clearing the parent is a waste of time, because we will + // Currently, clearing the parent link is superfluous, because we will // insert the node elsewhere and set its parent link again. - edge.borrow_mut().clear_parent_link(); + edge.clear_parent_link(); Some(edge) } }; @@ -748,9 +749,9 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { ForceResult::Internal(mut internal) => { let node = slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0); let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; - // In practice, clearing the parent is a waste of time, because we will + // Currently, clearing the parent link is superfluous, because we will // insert the node elsewhere and set its parent link again. - edge.borrow_mut().clear_parent_link(); + edge.clear_parent_link(); internal.correct_childrens_parent_links(0..old_len); From 94fd1d325c2f36b12b8d62d8a7b06a431375e55e Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 23 Nov 2020 14:41:53 +0100 Subject: [PATCH 281/719] BTreeMap: more expressive local variables in merge --- library/alloc/src/collections/btree/node.rs | 55 ++++++++++----------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index ae5831d51406..a8fffb389efa 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -1352,66 +1352,65 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// /// Panics unless we `.can_merge()`. pub fn merge( - mut self, + self, track_edge_idx: Option>, ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { + let Handle { node: mut parent_node, idx: parent_idx, _marker } = self.parent; + let old_parent_len = parent_node.len(); let mut left_node = self.left_child; - let left_len = left_node.len(); + let old_left_len = left_node.len(); let right_node = self.right_child; let right_len = right_node.len(); + let new_left_len = old_left_len + 1 + right_len; - assert!(left_len + right_len < CAPACITY); + assert!(new_left_len <= CAPACITY); assert!(match track_edge_idx { None => true, - Some(LeftOrRight::Left(idx)) => idx <= left_len, + Some(LeftOrRight::Left(idx)) => idx <= old_left_len, Some(LeftOrRight::Right(idx)) => idx <= right_len, }); unsafe { - *left_node.reborrow_mut().into_len_mut() += right_len as u16 + 1; + *left_node.reborrow_mut().into_len_mut() = new_left_len as u16; - let parent_key = slice_remove( - self.parent.node.reborrow_mut().into_key_area_slice(), - self.parent.idx, - ); - left_node.reborrow_mut().into_key_area_mut_at(left_len).write(parent_key); + let parent_key = + slice_remove(parent_node.reborrow_mut().into_key_area_slice(), parent_idx); + left_node.reborrow_mut().into_key_area_mut_at(old_left_len).write(parent_key); ptr::copy_nonoverlapping( right_node.reborrow().key_area().as_ptr(), - left_node.reborrow_mut().into_key_area_slice().as_mut_ptr().add(left_len + 1), + left_node.reborrow_mut().into_key_area_slice().as_mut_ptr().add(old_left_len + 1), right_len, ); - let parent_val = slice_remove( - self.parent.node.reborrow_mut().into_val_area_slice(), - self.parent.idx, - ); - left_node.reborrow_mut().into_val_area_mut_at(left_len).write(parent_val); + let parent_val = + slice_remove(parent_node.reborrow_mut().into_val_area_slice(), parent_idx); + left_node.reborrow_mut().into_val_area_mut_at(old_left_len).write(parent_val); ptr::copy_nonoverlapping( right_node.reborrow().val_area().as_ptr(), - left_node.reborrow_mut().into_val_area_slice().as_mut_ptr().add(left_len + 1), + left_node.reborrow_mut().into_val_area_slice().as_mut_ptr().add(old_left_len + 1), right_len, ); - slice_remove( - &mut self.parent.node.reborrow_mut().into_edge_area_slice(), - self.parent.idx + 1, - ); - let parent_old_len = self.parent.node.len(); - self.parent.node.correct_childrens_parent_links(self.parent.idx + 1..parent_old_len); - *self.parent.node.reborrow_mut().into_len_mut() -= 1; + slice_remove(&mut parent_node.reborrow_mut().into_edge_area_slice(), parent_idx + 1); + parent_node.correct_childrens_parent_links(parent_idx + 1..old_parent_len); + *parent_node.reborrow_mut().into_len_mut() -= 1; - if self.parent.node.height > 1 { + if parent_node.height > 1 { // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. let mut left_node = left_node.reborrow_mut().cast_to_internal_unchecked(); let right_node = right_node.cast_to_internal_unchecked(); ptr::copy_nonoverlapping( right_node.reborrow().edge_area().as_ptr(), - left_node.reborrow_mut().into_edge_area_slice().as_mut_ptr().add(left_len + 1), + left_node + .reborrow_mut() + .into_edge_area_slice() + .as_mut_ptr() + .add(old_left_len + 1), right_len + 1, ); - left_node.correct_childrens_parent_links(left_len + 1..=left_len + 1 + right_len); + left_node.correct_childrens_parent_links(old_left_len + 1..new_left_len + 1); Global.deallocate(right_node.node.cast(), Layout::new::>()); } else { @@ -1421,7 +1420,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { let new_idx = match track_edge_idx { None => 0, Some(LeftOrRight::Left(idx)) => idx, - Some(LeftOrRight::Right(idx)) => left_len + 1 + idx, + Some(LeftOrRight::Right(idx)) => old_left_len + 1 + idx, }; Handle::new_edge(left_node, new_idx) } From 7662626f7734b40b8e422c5406d99c55d782f94e Mon Sep 17 00:00:00 2001 From: EFanZh Date: Sun, 13 Dec 2020 19:23:16 +0800 Subject: [PATCH 282/719] Fix `cargo-binutils` link --- .../src/compiler-flags/source-based-code-coverage.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md index 6ca5ae40707c..98bcadd12ee2 100644 --- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md @@ -118,7 +118,7 @@ LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process covera * If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`. * You can install compatible versions of these tools via `rustup`. -The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-bintools`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands! +The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-binutils`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands! ```shell $ rustup component add llvm-tools-preview @@ -320,8 +320,8 @@ Rust's implementation and workflow for source-based code coverage is based on th [rustc-dev-guide-how-to-build-and-run]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html [`rustfilt`]: https://crates.io/crates/rustfilt [`json5format`]: https://crates.io/crates/json5format -[`cargo-bintools`]: https://crates.io/crates/cargo-bintools +[`cargo-binutils`]: https://crates.io/crates/cargo-binutils [`llvm-profdata merge`]: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge [`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report [`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show -[source-based code coverage in Clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html \ No newline at end of file +[source-based code coverage in Clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html From 09d528ec155f77349001fa7eb6c3ae3363f41412 Mon Sep 17 00:00:00 2001 From: Justus K Date: Sun, 13 Dec 2020 15:18:38 +0100 Subject: [PATCH 283/719] fix typo --- library/alloc/src/collections/vec_deque/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 1303b58e31c9..9e54c15ea6a0 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2796,7 +2796,7 @@ impl From> for VecDeque { // or doesn't have at least one free space. // We check if `T` is a ZST in the first condition, // because `usize::MAX` (the capacity returned by `capacity()` for ZST) - // is not a power of zero and thus it'll always try + // is not a power of two and thus it'll always try // to reserve more memory which will panic for ZST (rust-lang/rust#78532) if (!buf.capacity().is_power_of_two() && mem::size_of::() != 0) || (buf.capacity() < (MINIMUM_CAPACITY + 1)) From cd2a62cb0cf89f5b4105c1c40651cf0eeaa85b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 13 Dec 2020 15:17:47 +0100 Subject: [PATCH 284/719] needless_borrow: print the type in the lint message changelog: needless_borrow: print type in lint message --- clippy_lints/src/needless_borrow.rs | 7 +++++-- tests/ui/eta.stderr | 2 +- tests/ui/needless_borrow.stderr | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 405c21d608d9..bff53eb8ccad 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { return; } if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind { - if let ty::Ref(..) = cx.typeck_results().expr_ty(inner).kind() { + if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() { for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) { if let [Adjustment { kind: Adjust::Deref(_), .. @@ -62,8 +62,11 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { cx, NEEDLESS_BORROW, e.span, - "this expression borrows a reference that is immediately dereferenced \ + &format!( + "this expression borrows a reference (`&{}`) that is immediately dereferenced \ by the compiler", + ty + ), |diag| { if let Some(snippet) = snippet_opt(cx, inner.span) { diag.span_suggestion( diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index c4713ca8083d..16aa1b07733d 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -12,7 +12,7 @@ error: redundant closure found LL | meta(|a| foo(a)); | ^^^^^^^^^^ help: remove closure as shown: `foo` -error: this expression borrows a reference that is immediately dereferenced by the compiler +error: this expression borrows a reference (`&u8`) that is immediately dereferenced by the compiler --> $DIR/eta.rs:24:21 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index 0bfeda7914db..bea4b41b803d 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -1,4 +1,4 @@ -error: this expression borrows a reference that is immediately dereferenced by the compiler +error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:14:15 | LL | let c = x(&&a); @@ -12,7 +12,7 @@ error: this pattern creates a reference to a reference LL | if let Some(ref cake) = Some(&5) {} | ^^^^^^^^ help: change this to: `cake` -error: this expression borrows a reference that is immediately dereferenced by the compiler +error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:28:15 | LL | 46 => &&a, From cc9695543ea8f3973a2be2936df0efc724de1c16 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Fri, 11 Dec 2020 23:54:47 +0100 Subject: [PATCH 285/719] Pass Clippy args also trough RUSTFLAGS --- README.md | 1 - src/driver.rs | 116 +++++++++++++++++++++++++++++++++++------------ src/main.rs | 98 ++++++++++++++++++++++++++++++--------- tests/dogfood.rs | 2 +- 4 files changed, 165 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index aaa55e11c7db..dc931963726b 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,6 @@ the lint(s) you are interested in: ```terminal cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... ``` -Note that if you've run clippy before, this may only take effect after you've modified a file or ran `cargo clean`. ### Specifying the minimum supported Rust version diff --git a/src/driver.rs b/src/driver.rs index e490ee54c0be..40f1b802e60e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,5 +1,6 @@ #![feature(rustc_private)] #![feature(once_cell)] +#![feature(bool_to_option)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] @@ -19,6 +20,7 @@ use rustc_tools_util::VersionInfo; use std::borrow::Cow; use std::env; +use std::iter; use std::lazy::SyncLazy; use std::ops::Deref; use std::panic; @@ -47,20 +49,6 @@ fn arg_value<'a, T: Deref>( None } -#[test] -fn test_arg_value() { - let args = &["--bar=bar", "--foobar", "123", "--foo"]; - - assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None); - assert_eq!(arg_value(args, "--bar", |_| false), None); - assert_eq!(arg_value(args, "--bar", |_| true), Some("bar")); - assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar")); - assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None); - assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None); - assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123")); - assert_eq!(arg_value(args, "--foo", |_| true), None); -} - struct DefaultCallbacks; impl rustc_driver::Callbacks for DefaultCallbacks {} @@ -182,6 +170,28 @@ fn toolchain_path(home: Option, toolchain: Option) -> Option(args: &mut Vec, clippy_args: I) +where + T: AsRef, + U: AsRef + ?Sized + 'a, + I: Iterator + Clone, +{ + let args_iter = clippy_args.map(AsRef::as_ref); + let args_count = args_iter.clone().count(); + + if args_count > 0 { + if let Some(start) = args.windows(args_count).enumerate().find_map(|(current, window)| { + window + .iter() + .map(AsRef::as_ref) + .eq(args_iter.clone()) + .then_some(current) + }) { + args.drain(start..start + args_count); + } + } +} + #[allow(clippy::too_many_lines)] pub fn main() { rustc_driver::init_rustc_env_logger(); @@ -278,20 +288,9 @@ pub fn main() { args.extend(vec!["--sysroot".into(), sys_root]); }; - let mut no_deps = false; - let clippy_args = env::var("CLIPPY_ARGS") - .unwrap_or_default() - .split("__CLIPPY_HACKERY__") - .filter_map(|s| match s { - "" => None, - "--no-deps" => { - no_deps = true; - None - }, - _ => Some(s.to_string()), - }) - .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]) - .collect::>(); + let clippy_args = env::var("CLIPPY_ARGS").unwrap_or_default(); + let clippy_args = clippy_args.split_whitespace(); + let no_deps = clippy_args.clone().any(|flag| flag == "--no-deps"); // We enable Clippy if one of the following conditions is met // - IF Clippy is run on its test suite OR @@ -304,7 +303,11 @@ pub fn main() { let clippy_enabled = clippy_tests_set || (!cap_lints_allow && (!no_deps || in_primary_package)); if clippy_enabled { - args.extend(clippy_args); + remove_clippy_args(&mut args, iter::once("--no-deps")); + args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]); + } else { + // Remove all flags passed through RUSTFLAGS if Clippy is not enabled. + remove_clippy_args(&mut args, clippy_args); } let mut clippy = ClippyCallbacks; @@ -315,3 +318,58 @@ pub fn main() { rustc_driver::RunCompiler::new(&args, callbacks).run() })) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_arg_value() { + let args = &["--bar=bar", "--foobar", "123", "--foo"]; + + assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None); + assert_eq!(arg_value(args, "--bar", |_| false), None); + assert_eq!(arg_value(args, "--bar", |_| true), Some("bar")); + assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar")); + assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None); + assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None); + assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123")); + assert_eq!(arg_value(args, "--foo", |_| true), None); + } + + #[test] + fn removes_clippy_args_from_start() { + let mut args = vec!["-D", "clippy::await_holding_lock", "--cfg", r#"feature="some_feat""#]; + let clippy_args = ["-D", "clippy::await_holding_lock"].iter(); + + remove_clippy_args(&mut args, clippy_args); + assert_eq!(args, &["--cfg", r#"feature="some_feat""#]); + } + + #[test] + fn removes_clippy_args_from_end() { + let mut args = vec!["-Zui-testing", "-A", "clippy::empty_loop", "--no-deps"]; + let clippy_args = ["-A", "clippy::empty_loop", "--no-deps"].iter(); + + remove_clippy_args(&mut args, clippy_args); + assert_eq!(args, &["-Zui-testing"]); + } + + #[test] + fn removes_clippy_args_from_middle() { + let mut args = vec!["-Zui-testing", "-W", "clippy::filter_map", "-L", "serde"]; + let clippy_args = ["-W", "clippy::filter_map"].iter(); + + remove_clippy_args(&mut args, clippy_args); + assert_eq!(args, &["-Zui-testing", "-L", "serde"]); + } + + #[test] + fn no_clippy_args_to_remove() { + let mut args = vec!["-Zui-testing", "-L", "serde"]; + let clippy_args: [&str; 0] = []; + + remove_clippy_args(&mut args, clippy_args.iter()); + assert_eq!(args, &["-Zui-testing", "-L", "serde"]); + } +} diff --git a/src/main.rs b/src/main.rs index ea06743394d1..7594ea2c7b1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +#![feature(bool_to_option)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] @@ -62,11 +63,12 @@ struct ClippyCmd { unstable_options: bool, cargo_subcommand: &'static str, args: Vec, - clippy_args: Vec, + rustflags: Option, + clippy_args: Option, } impl ClippyCmd { - fn new(mut old_args: I) -> Self + fn new(mut old_args: I, rustflags: Option) -> Self where I: Iterator, { @@ -99,16 +101,19 @@ impl ClippyCmd { args.insert(0, "+nightly".to_string()); } - let mut clippy_args: Vec = old_args.collect(); - if cargo_subcommand == "fix" && !clippy_args.iter().any(|arg| arg == "--no-deps") { - clippy_args.push("--no-deps".into()); + let mut clippy_args = old_args.collect::>().join(" "); + if cargo_subcommand == "fix" && !clippy_args.contains("--no-deps") { + clippy_args = format!("{} --no-deps", clippy_args); } + let has_args = !clippy_args.is_empty(); ClippyCmd { unstable_options, cargo_subcommand, args, - clippy_args, + rustflags: has_args + .then(|| rustflags.map_or_else(|| clippy_args.clone(), |flags| format!("{} {}", clippy_args, flags))), + clippy_args: has_args.then_some(clippy_args), } } @@ -150,18 +155,19 @@ impl ClippyCmd { fn into_std_cmd(self) -> Command { let mut cmd = Command::new("cargo"); - let clippy_args: String = self - .clippy_args - .iter() - .map(|arg| format!("{}__CLIPPY_HACKERY__", arg)) - .collect(); cmd.env(self.path_env(), Self::path()) .envs(ClippyCmd::target_dir()) - .env("CLIPPY_ARGS", clippy_args) .arg(self.cargo_subcommand) .args(&self.args); + // HACK: pass Clippy args to the driver *also* through RUSTFLAGS. + // This guarantees that new builds will be triggered when Clippy flags change. + if let (Some(clippy_args), Some(rustflags)) = (self.clippy_args, self.rustflags) { + cmd.env("CLIPPY_ARGS", clippy_args); + cmd.env("RUSTFLAGS", rustflags); + } + cmd } } @@ -170,7 +176,7 @@ fn process(old_args: I) -> Result<(), i32> where I: Iterator, { - let cmd = ClippyCmd::new(old_args); + let cmd = ClippyCmd::new(old_args, env::var("RUSTFLAGS").ok()); let mut cmd = cmd.into_std_cmd(); @@ -195,7 +201,7 @@ mod tests { #[should_panic] fn fix_without_unstable() { let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string); - let _ = ClippyCmd::new(args); + let _ = ClippyCmd::new(args, None); } #[test] @@ -203,7 +209,8 @@ mod tests { let args = "cargo clippy --fix -Zunstable-options" .split_whitespace() .map(ToString::to_string); - let cmd = ClippyCmd::new(args); + let cmd = ClippyCmd::new(args, None); + assert_eq!("fix", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); assert!(cmd.args.iter().any(|arg| arg.ends_with("unstable-options"))); @@ -214,8 +221,9 @@ mod tests { let args = "cargo clippy --fix -Zunstable-options" .split_whitespace() .map(ToString::to_string); - let cmd = ClippyCmd::new(args); - assert!(cmd.clippy_args.iter().any(|arg| arg == "--no-deps")); + let cmd = ClippyCmd::new(args, None); + + assert!(cmd.clippy_args.unwrap().contains("--no-deps")); } #[test] @@ -223,14 +231,16 @@ mod tests { let args = "cargo clippy --fix -Zunstable-options -- --no-deps" .split_whitespace() .map(ToString::to_string); - let cmd = ClippyCmd::new(args); - assert_eq!(cmd.clippy_args.iter().filter(|arg| *arg == "--no-deps").count(), 1); + let cmd = ClippyCmd::new(args, None); + + assert_eq!(1, cmd.clippy_args.unwrap().matches("--no-deps").count()); } #[test] fn check() { let args = "cargo clippy".split_whitespace().map(ToString::to_string); - let cmd = ClippyCmd::new(args); + let cmd = ClippyCmd::new(args, None); + assert_eq!("check", cmd.cargo_subcommand); assert_eq!("RUSTC_WRAPPER", cmd.path_env()); } @@ -240,8 +250,54 @@ mod tests { let args = "cargo clippy -Zunstable-options" .split_whitespace() .map(ToString::to_string); - let cmd = ClippyCmd::new(args); + let cmd = ClippyCmd::new(args, None); + assert_eq!("check", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); } + + #[test] + fn clippy_args_into_rustflags() { + let args = "cargo clippy -- -W clippy::as_conversions" + .split_whitespace() + .map(ToString::to_string); + let rustflags = None; + let cmd = ClippyCmd::new(args, rustflags); + + assert_eq!("-W clippy::as_conversions", cmd.rustflags.unwrap()); + } + + #[test] + fn clippy_args_respect_existing_rustflags() { + let args = "cargo clippy -- -D clippy::await_holding_lock" + .split_whitespace() + .map(ToString::to_string); + let rustflags = Some(r#"--cfg feature="some_feat""#.into()); + let cmd = ClippyCmd::new(args, rustflags); + + assert_eq!( + r#"-D clippy::await_holding_lock --cfg feature="some_feat""#, + cmd.rustflags.unwrap() + ); + } + + #[test] + fn no_env_change_if_no_clippy_args() { + let args = "cargo clippy".split_whitespace().map(ToString::to_string); + let rustflags = Some(r#"--cfg feature="some_feat""#.into()); + let cmd = ClippyCmd::new(args, rustflags); + + assert!(cmd.clippy_args.is_none()); + assert!(cmd.rustflags.is_none()); + } + + #[test] + fn no_env_change_if_no_clippy_args_nor_rustflags() { + let args = "cargo clippy".split_whitespace().map(ToString::to_string); + let rustflags = None; + let cmd = ClippyCmd::new(args, rustflags); + + assert!(cmd.clippy_args.is_none()); + assert!(cmd.rustflags.is_none()); + } } diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 052223d6d6ff..fda1413868e8 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -23,7 +23,7 @@ fn dogfood_clippy() { .current_dir(root_dir) .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") - .arg("clippy-preview") + .arg("clippy") .arg("--all-targets") .arg("--all-features") .arg("--") From f93d9654d2ce012e146b8dfa615ad724f4bb23fd Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sun, 13 Dec 2020 17:21:53 +0100 Subject: [PATCH 286/719] Address comments from PR review Also: enable tests for cargo-clippy --- Cargo.toml | 1 - src/main.rs | 76 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a765390c6032..7f9d22e594b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ publish = false [[bin]] name = "cargo-clippy" -test = false path = "src/main.rs" [[bin]] diff --git a/src/main.rs b/src/main.rs index 7594ea2c7b1d..1c0e04689a9f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![feature(bool_to_option)] +#![feature(command_access)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] @@ -63,12 +64,11 @@ struct ClippyCmd { unstable_options: bool, cargo_subcommand: &'static str, args: Vec, - rustflags: Option, clippy_args: Option, } impl ClippyCmd { - fn new(mut old_args: I, rustflags: Option) -> Self + fn new(mut old_args: I) -> Self where I: Iterator, { @@ -111,8 +111,6 @@ impl ClippyCmd { unstable_options, cargo_subcommand, args, - rustflags: has_args - .then(|| rustflags.map_or_else(|| clippy_args.clone(), |flags| format!("{} {}", clippy_args, flags))), clippy_args: has_args.then_some(clippy_args), } } @@ -153,7 +151,7 @@ impl ClippyCmd { .map(|p| ("CARGO_TARGET_DIR", p)) } - fn into_std_cmd(self) -> Command { + fn into_std_cmd(self, rustflags: Option) -> Command { let mut cmd = Command::new("cargo"); cmd.env(self.path_env(), Self::path()) @@ -163,9 +161,12 @@ impl ClippyCmd { // HACK: pass Clippy args to the driver *also* through RUSTFLAGS. // This guarantees that new builds will be triggered when Clippy flags change. - if let (Some(clippy_args), Some(rustflags)) = (self.clippy_args, self.rustflags) { + if let Some(clippy_args) = self.clippy_args { + cmd.env( + "RUSTFLAGS", + rustflags.map_or(clippy_args.clone(), |flags| format!("{} {}", clippy_args, flags)), + ); cmd.env("CLIPPY_ARGS", clippy_args); - cmd.env("RUSTFLAGS", rustflags); } cmd @@ -176,9 +177,9 @@ fn process(old_args: I) -> Result<(), i32> where I: Iterator, { - let cmd = ClippyCmd::new(old_args, env::var("RUSTFLAGS").ok()); + let cmd = ClippyCmd::new(old_args); - let mut cmd = cmd.into_std_cmd(); + let mut cmd = cmd.into_std_cmd(env::var("RUSTFLAGS").ok()); let exit_status = cmd .spawn() @@ -196,12 +197,13 @@ where #[cfg(test)] mod tests { use super::ClippyCmd; + use std::ffi::OsStr; #[test] #[should_panic] fn fix_without_unstable() { let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string); - let _ = ClippyCmd::new(args, None); + let _ = ClippyCmd::new(args); } #[test] @@ -209,7 +211,7 @@ mod tests { let args = "cargo clippy --fix -Zunstable-options" .split_whitespace() .map(ToString::to_string); - let cmd = ClippyCmd::new(args, None); + let cmd = ClippyCmd::new(args); assert_eq!("fix", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); @@ -221,7 +223,7 @@ mod tests { let args = "cargo clippy --fix -Zunstable-options" .split_whitespace() .map(ToString::to_string); - let cmd = ClippyCmd::new(args, None); + let cmd = ClippyCmd::new(args); assert!(cmd.clippy_args.unwrap().contains("--no-deps")); } @@ -231,7 +233,7 @@ mod tests { let args = "cargo clippy --fix -Zunstable-options -- --no-deps" .split_whitespace() .map(ToString::to_string); - let cmd = ClippyCmd::new(args, None); + let cmd = ClippyCmd::new(args); assert_eq!(1, cmd.clippy_args.unwrap().matches("--no-deps").count()); } @@ -239,7 +241,7 @@ mod tests { #[test] fn check() { let args = "cargo clippy".split_whitespace().map(ToString::to_string); - let cmd = ClippyCmd::new(args, None); + let cmd = ClippyCmd::new(args); assert_eq!("check", cmd.cargo_subcommand); assert_eq!("RUSTC_WRAPPER", cmd.path_env()); @@ -250,7 +252,7 @@ mod tests { let args = "cargo clippy -Zunstable-options" .split_whitespace() .map(ToString::to_string); - let cmd = ClippyCmd::new(args, None); + let cmd = ClippyCmd::new(args); assert_eq!("check", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); @@ -261,10 +263,14 @@ mod tests { let args = "cargo clippy -- -W clippy::as_conversions" .split_whitespace() .map(ToString::to_string); - let rustflags = None; - let cmd = ClippyCmd::new(args, rustflags); + let cmd = ClippyCmd::new(args); - assert_eq!("-W clippy::as_conversions", cmd.rustflags.unwrap()); + let rustflags = None; + let cmd = cmd.into_std_cmd(rustflags); + + assert!(cmd + .get_envs() + .any(|(key, val)| key == "RUSTFLAGS" && val == Some(OsStr::new("-W clippy::as_conversions")))); } #[test] @@ -272,32 +278,38 @@ mod tests { let args = "cargo clippy -- -D clippy::await_holding_lock" .split_whitespace() .map(ToString::to_string); - let rustflags = Some(r#"--cfg feature="some_feat""#.into()); - let cmd = ClippyCmd::new(args, rustflags); + let cmd = ClippyCmd::new(args); - assert_eq!( - r#"-D clippy::await_holding_lock --cfg feature="some_feat""#, - cmd.rustflags.unwrap() - ); + let rustflags = Some(r#"--cfg feature="some_feat""#.into()); + let cmd = cmd.into_std_cmd(rustflags); + + assert!(cmd.get_envs().any(|(key, val)| key == "RUSTFLAGS" + && val == Some(OsStr::new(r#"-D clippy::await_holding_lock --cfg feature="some_feat""#)))); } #[test] fn no_env_change_if_no_clippy_args() { let args = "cargo clippy".split_whitespace().map(ToString::to_string); - let rustflags = Some(r#"--cfg feature="some_feat""#.into()); - let cmd = ClippyCmd::new(args, rustflags); + let cmd = ClippyCmd::new(args); - assert!(cmd.clippy_args.is_none()); - assert!(cmd.rustflags.is_none()); + let rustflags = Some(r#"--cfg feature="some_feat""#.into()); + let cmd = cmd.into_std_cmd(rustflags); + + assert!(!cmd + .get_envs() + .any(|(key, _)| key == "RUSTFLAGS" || key == "CLIPPY_ARGS")); } #[test] fn no_env_change_if_no_clippy_args_nor_rustflags() { let args = "cargo clippy".split_whitespace().map(ToString::to_string); - let rustflags = None; - let cmd = ClippyCmd::new(args, rustflags); + let cmd = ClippyCmd::new(args); - assert!(cmd.clippy_args.is_none()); - assert!(cmd.rustflags.is_none()); + let rustflags = None; + let cmd = cmd.into_std_cmd(rustflags); + + assert!(!cmd + .get_envs() + .any(|(key, _)| key == "RUSTFLAGS" || key == "CLIPPY_ARGS")) } } From ec0f1d70c955643a77e89d67eb2469ff5d7d6eba Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 13 Dec 2020 17:47:46 +0100 Subject: [PATCH 287/719] Refactor test_lang_string_parse to make it clearer --- src/librustdoc/html/markdown/tests.rs | 143 +++++++++++++------------- 1 file changed, 69 insertions(+), 74 deletions(-) diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 9807d8632c75..75ff3c5af2fd 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -51,82 +51,77 @@ fn test_unique_id() { #[test] fn test_lang_string_parse() { - fn t( - s: &str, - should_panic: bool, - no_run: bool, - ignore: Ignore, - rust: bool, - test_harness: bool, - compile_fail: bool, - allow_fail: bool, - error_codes: Vec, - edition: Option, - ) { - assert_eq!( - LangString::parse(s, ErrorCodes::Yes, true, None), - LangString { - should_panic, - no_run, - ignore, - rust, - test_harness, - compile_fail, - error_codes, - original: s.to_owned(), - allow_fail, - edition, - } - ) - } - let ignore_foo = Ignore::Some(vec!["foo".to_string()]); - - fn v() -> Vec { - Vec::new() + fn t(lg: LangString) { + let s = &lg.original; + assert_eq!(LangString::parse(s, ErrorCodes::Yes, true, None), lg) } - // marker | should_panic | no_run | ignore | rust | test_harness - // | compile_fail | allow_fail | error_codes | edition - t("", false, false, Ignore::None, true, false, false, false, v(), None); - t("rust", false, false, Ignore::None, true, false, false, false, v(), None); - t("sh", false, false, Ignore::None, false, false, false, false, v(), None); - t("ignore", false, false, Ignore::All, true, false, false, false, v(), None); - t("ignore-foo", false, false, ignore_foo, true, false, false, false, v(), None); - t("should_panic", true, false, Ignore::None, true, false, false, false, v(), None); - t("no_run", false, true, Ignore::None, true, false, false, false, v(), None); - t("test_harness", false, false, Ignore::None, true, true, false, false, v(), None); - t("compile_fail", false, true, Ignore::None, true, false, true, false, v(), None); - t("allow_fail", false, false, Ignore::None, true, false, false, true, v(), None); - t("{.no_run .example}", false, true, Ignore::None, true, false, false, false, v(), None); - t("{.sh .should_panic}", true, false, Ignore::None, false, false, false, false, v(), None); - t("{.example .rust}", false, false, Ignore::None, true, false, false, false, v(), None); - t("{.test_harness .rust}", false, false, Ignore::None, true, true, false, false, v(), None); - t("text, no_run", false, true, Ignore::None, false, false, false, false, v(), None); - t("text,no_run", false, true, Ignore::None, false, false, false, false, v(), None); - t( - "edition2015", - false, - false, - Ignore::None, - true, - false, - false, - false, - v(), - Some(Edition::Edition2015), - ); - t( - "edition2018", - false, - false, - Ignore::None, - true, - false, - false, - false, - v(), - Some(Edition::Edition2018), - ); + t(LangString::all_false()); + t(LangString { original: "rust".into(), ..LangString::all_false() }); + t(LangString { original: "sh".into(), rust: false, ..LangString::all_false() }); + t(LangString { original: "ignore".into(), ignore: Ignore::All, ..LangString::all_false() }); + t(LangString { + original: "ignore-foo".into(), + ignore: Ignore::Some(vec!["foo".to_string()]), + ..LangString::all_false() + }); + t(LangString { + original: "should_panic".into(), + should_panic: true, + ..LangString::all_false() + }); + t(LangString { original: "no_run".into(), no_run: true, ..LangString::all_false() }); + t(LangString { + original: "test_harness".into(), + test_harness: true, + ..LangString::all_false() + }); + t(LangString { + original: "compile_fail".into(), + no_run: true, + compile_fail: true, + ..LangString::all_false() + }); + t(LangString { original: "allow_fail".into(), allow_fail: true, ..LangString::all_false() }); + t(LangString { + original: "{.no_run .example}".into(), + no_run: true, + ..LangString::all_false() + }); + t(LangString { + original: "{.sh .should_panic}".into(), + should_panic: true, + rust: false, + ..LangString::all_false() + }); + t(LangString { original: "{.example .rust}".into(), ..LangString::all_false() }); + t(LangString { + original: "{.test_harness .rust}".into(), + test_harness: true, + ..LangString::all_false() + }); + t(LangString { + original: "text, no_run".into(), + no_run: true, + rust: false, + ..LangString::all_false() + }); + t(LangString { + original: "text,no_run".into(), + no_run: true, + rust: false, + ..LangString::all_false() + }); + t(LangString { + original: "edition2015".into(), + edition: Some(Edition::Edition2015), + ..LangString::all_false() + }); + t(LangString { + original: "edition2018".into(), + edition: Some(Edition::Edition2018), + ..LangString::all_false() + }); } #[test] From 404c50f56200c28ebbee64113c9dfc0120c33e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 13 Dec 2020 15:22:45 +0100 Subject: [PATCH 288/719] NFC: clippy cargo dev: move generation of clap config into a function --- clippy_dev/src/main.rs | 100 +++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index f66855620e73..5938b7881013 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -1,10 +1,52 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] -use clap::{App, Arg, SubCommand}; +use clap::{App, Arg, ArgMatches, SubCommand}; use clippy_dev::{bless, fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints}; fn main() { - let matches = App::new("Clippy developer tooling") + let matches = get_clap_config(); + + match matches.subcommand() { + ("bless", Some(_)) => { + bless::bless(); + }, + ("fmt", Some(matches)) => { + fmt::run(matches.is_present("check"), matches.is_present("verbose")); + }, + ("update_lints", Some(matches)) => { + if matches.is_present("print-only") { + update_lints::print_lints(); + } else if matches.is_present("check") { + update_lints::run(update_lints::UpdateMode::Check); + } else { + update_lints::run(update_lints::UpdateMode::Change); + } + }, + ("new_lint", Some(matches)) => { + match new_lint::create( + matches.value_of("pass"), + matches.value_of("name"), + matches.value_of("category"), + ) { + Ok(_) => update_lints::run(update_lints::UpdateMode::Change), + Err(e) => eprintln!("Unable to create lint: {}", e), + } + }, + ("limit_stderr_length", _) => { + stderr_length_check::check(); + }, + ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")), + ("serve", Some(matches)) => { + let port = matches.value_of("port").unwrap().parse().unwrap(); + let lint = matches.value_of("lint"); + serve::run(port, lint); + }, + _ => {}, + } +} + +fn get_clap_config<'a>() -> ArgMatches<'a> { + App::new("Clippy developer tooling") .subcommand(SubCommand::with_name("bless").about("bless the test output changes")) .subcommand( SubCommand::with_name("fmt") @@ -26,16 +68,16 @@ fn main() { .about("Updates lint registration and information from the source code") .long_about( "Makes sure that:\n \ - * the lint count in README.md is correct\n \ - * the changelog contains markdown link references at the bottom\n \ - * all lint groups include the correct lints\n \ - * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \ - * all lints are registered in the lint store", + * the lint count in README.md is correct\n \ + * the changelog contains markdown link references at the bottom\n \ + * all lint groups include the correct lints\n \ + * lint modules in `clippy_lints/*` are visible in `src/lifb.rs` via `pub mod`\n \ + * all lints are registered in the lint store", ) .arg(Arg::with_name("print-only").long("print-only").help( "Print a table of lints to STDOUT. \ - This does not include deprecated and internal lints. \ - (Does not modify any files)", + This does not include deprecated and internal lints. \ + (Does not modify any files)", )) .arg( Arg::with_name("check") @@ -114,43 +156,5 @@ fn main() { ) .arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")), ) - .get_matches(); - - match matches.subcommand() { - ("bless", Some(_)) => { - bless::bless(); - }, - ("fmt", Some(matches)) => { - fmt::run(matches.is_present("check"), matches.is_present("verbose")); - }, - ("update_lints", Some(matches)) => { - if matches.is_present("print-only") { - update_lints::print_lints(); - } else if matches.is_present("check") { - update_lints::run(update_lints::UpdateMode::Check); - } else { - update_lints::run(update_lints::UpdateMode::Change); - } - }, - ("new_lint", Some(matches)) => { - match new_lint::create( - matches.value_of("pass"), - matches.value_of("name"), - matches.value_of("category"), - ) { - Ok(_) => update_lints::run(update_lints::UpdateMode::Change), - Err(e) => eprintln!("Unable to create lint: {}", e), - } - }, - ("limit_stderr_length", _) => { - stderr_length_check::check(); - }, - ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")), - ("serve", Some(matches)) => { - let port = matches.value_of("port").unwrap().parse().unwrap(); - let lint = matches.value_of("lint"); - serve::run(port, lint); - }, - _ => {}, - } + .get_matches() } From 91fa25c9de9b8abb410273fe233fd71c39a434e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 13 Dec 2020 15:49:48 +0100 Subject: [PATCH 289/719] clippy dev fmt: don't format if we have a local rustc repo enabled as path dependency via cargo dev ra-setup. rustfmt would try to format the entire rustc repo, probably because it sees it as a local dependency. --- clippy_dev/src/fmt.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 6ae3f58c1f2a..6f13af8aa473 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,9 +1,9 @@ use crate::clippy_project_root; use shell_escape::escape; use std::ffi::OsStr; -use std::io; use std::path::Path; use std::process::{self, Command}; +use std::{fs, io}; use walkdir::WalkDir; #[derive(Debug)] @@ -12,6 +12,7 @@ pub enum CliError { IoError(io::Error), RustfmtNotInstalled, WalkDirError(walkdir::Error), + RaSetupActive, } impl From for CliError { @@ -31,12 +32,23 @@ struct FmtContext { verbose: bool, } +// the "main" function of cargo dev fmt pub fn run(check: bool, verbose: bool) { fn try_run(context: &FmtContext) -> Result { let mut success = true; let project_root = clippy_project_root(); + // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to + // format because rustfmt would also format the entire rustc repo as it is a local + // dependency + if fs::read_to_string(project_root.join("Cargo.toml")) + .expect("Failed to read clippy Cargo.toml") + .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]") + { + return Err(CliError::RaSetupActive); + } + rustfmt_test(context)?; success &= cargo_fmt(context, project_root.as_path())?; @@ -75,6 +87,13 @@ pub fn run(check: bool, verbose: bool) { CliError::WalkDirError(err) => { eprintln!("error: {}", err); }, + CliError::RaSetupActive => { + eprintln!( + "error: a local rustc repo is enabled as path dependency via `cargo dev ra-setup`. +Not formatting because that would format the local repo as well! +Please revert the changes to Cargo.tomls first." + ); + }, } } From 27dc565d28444fa488972e09a8117474cee1e752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 13 Dec 2020 17:01:44 +0100 Subject: [PATCH 290/719] cargo dev: rename ra-setup to ra_setup to be in line with the other commands --- CONTRIBUTING.md | 8 ++++---- clippy_dev/src/fmt.rs | 2 +- clippy_dev/src/main.rs | 4 ++-- clippy_dev/src/ra_setup.rs | 2 +- doc/basics.md | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a3c602b9e26..49b64da1fb6b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,10 +19,10 @@ All contributors are expected to follow the [Rust Code of Conduct]. - [Writing code](#writing-code) - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work) - [How Clippy works](#how-clippy-works) - - [Fixing build failures caused by Rust](#fixing-build-failures-caused-by-rust) + - [Syncing changes between Clippy and [`rust-lang/rust`]](#syncing-changes-between-clippy-and-rust-langrust) - [Patching git-subtree to work with big repos](#patching-git-subtree-to-work-with-big-repos) - - [Performing the sync](#performing-the-sync) - - [Syncing back changes in Clippy to [`rust-lang/rust`]](#syncing-back-changes-in-clippy-to-rust-langrust) + - [Performing the sync from [`rust-lang/rust`] to Clippy](#performing-the-sync-from-rust-langrust-to-clippy) + - [Performing the sync from Clippy to [`rust-lang/rust`]](#performing-the-sync-from-clippy-to-rust-langrust) - [Defining remotes](#defining-remotes) - [Issue and PR triage](#issue-and-pr-triage) - [Bors and Homu](#bors-and-homu) @@ -111,7 +111,7 @@ To work around this, you need to have a copy of the [rustc-repo][rustc_repo] ava `git clone https://github.com/rust-lang/rust/`. Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies which rust-analyzer will be able to understand. -Run `cargo dev ra-setup --repo-path ` where `` is an absolute path to the rustc repo +Run `cargo dev ra_setup --repo-path ` where `` is an absolute path to the rustc repo you just cloned. The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to Clippys `Cargo.toml`s and should allow rust-analyzer to understand most of the types that Clippy uses. diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 6f13af8aa473..6b528d219df2 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -89,7 +89,7 @@ pub fn run(check: bool, verbose: bool) { }, CliError::RaSetupActive => { eprintln!( - "error: a local rustc repo is enabled as path dependency via `cargo dev ra-setup`. + "error: a local rustc repo is enabled as path dependency via `cargo dev ra_setup`. Not formatting because that would format the local repo as well! Please revert the changes to Cargo.tomls first." ); diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 5938b7881013..4fdae38e3ab7 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -35,7 +35,7 @@ fn main() { ("limit_stderr_length", _) => { stderr_length_check::check(); }, - ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")), + ("ra_setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")), ("serve", Some(matches)) => { let port = matches.value_of("port").unwrap().parse().unwrap(); let lint = matches.value_of("lint"); @@ -131,7 +131,7 @@ fn get_clap_config<'a>() -> ArgMatches<'a> { .about("Ensures that stderr files do not grow longer than a certain amount of lines."), ) .subcommand( - SubCommand::with_name("ra-setup") + SubCommand::with_name("ra_setup") .about("Alter dependencies so rust-analyzer can find rustc internals") .arg( Arg::with_name("rustc-repo-path") diff --git a/clippy_dev/src/ra_setup.rs b/clippy_dev/src/ra_setup.rs index 9d9e836cc08a..40bf4a9505a8 100644 --- a/clippy_dev/src/ra_setup.rs +++ b/clippy_dev/src/ra_setup.rs @@ -52,7 +52,7 @@ fn inject_deps_into_manifest( // do not inject deps if we have aleady done so if cargo_toml.contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { eprintln!( - "cargo dev ra-setup: warning: deps already found inside {}, doing nothing.", + "cargo dev ra_setup: warning: deps already found inside {}, doing nothing.", manifest_path ); return Ok(()); diff --git a/doc/basics.md b/doc/basics.md index dc71f022773c..954474a17aa8 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -8,7 +8,7 @@ the codebase take a look at [Adding Lints] or [Common Tools]. [Common Tools]: https://github.com/rust-lang/rust-clippy/blob/master/doc/common_tools_writing_lints.md - [Basics for hacking on Clippy](#basics-for-hacking-on-clippy) - - [Get the code](#get-the-code) + - [Get the Code](#get-the-code) - [Building and Testing](#building-and-testing) - [`cargo dev`](#cargo-dev) - [PR](#pr) @@ -87,7 +87,7 @@ cargo dev update_lints # create a new lint and register it cargo dev new_lint # (experimental) Setup Clippy to work with rust-analyzer -cargo dev ra-setup +cargo dev ra_setup ``` ## PR From 4c1addfcb77b4699be409112075cf3e33e8b5ea7 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 13 Dec 2020 15:13:41 -0500 Subject: [PATCH 291/719] Use imports instead of rewriting the type signature of `stable` This was an adventure; see https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/'higher.20ranked.20subtype.20error' --- src/librustdoc/lib.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 286a29edd95e..94b6617a071a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -117,21 +117,9 @@ fn get_args() -> Option> { .collect() } -fn stable(name: &'static str, f: F) -> RustcOptGroup -where - F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, -{ - RustcOptGroup::stable(name, f) -} - -fn unstable(name: &'static str, f: F) -> RustcOptGroup -where - F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, -{ - RustcOptGroup::unstable(name, f) -} - fn opts() -> Vec { + let stable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::stable; + let unstable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::unstable; vec![ stable("h", |o| o.optflag("h", "help", "show this help message")), stable("V", |o| o.optflag("V", "version", "print rustdoc's version")), From a37af06fea574f3d9f4d3cca58a70cd545523486 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Wed, 9 Dec 2020 12:25:45 +0000 Subject: [PATCH 292/719] Removing false positive for the match_single_binding lint * Applying suggested changes from the PR --- clippy_lints/src/matches.rs | 22 +++++++++++++++++-- tests/ui/match_single_binding.fixed | 28 +++++++++++++++++++++++ tests/ui/match_single_binding.rs | 33 ++++++++++++++++++++++++++++ tests/ui/match_single_binding.stderr | 13 ++++++++++- 4 files changed, 93 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 2a1a73f98ee5..04b35835c6b8 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -4,8 +4,8 @@ use crate::utils::usage::is_unused; use crate::utils::{ expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, remove_blocks, - snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, + snippet, snippet_block, snippet_opt, snippet_with_applicability, span_lint_and_help, span_lint_and_note, + span_lint_and_sugg, span_lint_and_then, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; @@ -1237,6 +1237,24 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) { return; } + + // HACK: + // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here + // to prevent false positives as there is currently no better way to detect if code was excluded by + // a macro. See PR #6435 + if_chain! { + if let Some(match_snippet) = snippet_opt(cx, expr.span); + if let Some(arm_snippet) = snippet_opt(cx, arms[0].span); + if let Some(ex_snippet) = snippet_opt(cx, ex.span); + let rest_snippet = match_snippet.replace(&arm_snippet, "").replace(&ex_snippet, ""); + if rest_snippet.contains("=>"); + then { + // The code it self contains another thick arrow "=>" + // -> Either another arm or a comment + return; + } + } + let matched_vars = ex.span; let bind_names = arms[0].pat.span; let match_body = remove_blocks(&arms[0].body); diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index f3627902eec9..526e94b10bd0 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -87,4 +87,32 @@ fn main() { unwrapped }) .collect::>(); + // Ok + let x = 1; + match x { + #[cfg(disabled_feature)] + 0 => println!("Disabled branch"), + _ => println!("Enabled branch"), + } + // Lint + let x = 1; + let y = 1; + println!("Single branch"); + // Ok + let x = 1; + let y = 1; + match match y { + 0 => 1, + _ => 2, + } { + #[cfg(disabled_feature)] + 0 => println!("Array index start"), + _ => println!("Not an array index start"), + } + // False negative + let x = 1; + match x { + // => + _ => println!("Not an array index start"), + } } diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index 8c182148ae18..6a2ca7c5e934 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -99,4 +99,37 @@ fn main() { unwrapped => unwrapped, }) .collect::>(); + // Ok + let x = 1; + match x { + #[cfg(disabled_feature)] + 0 => println!("Disabled branch"), + _ => println!("Enabled branch"), + } + // Lint + let x = 1; + let y = 1; + match match y { + 0 => 1, + _ => 2, + } { + _ => println!("Single branch"), + } + // Ok + let x = 1; + let y = 1; + match match y { + 0 => 1, + _ => 2, + } { + #[cfg(disabled_feature)] + 0 => println!("Array index start"), + _ => println!("Not an array index start"), + } + // False negative + let x = 1; + match x { + // => + _ => println!("Not an array index start"), + } } diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 795c8c3e24d7..cbbf5d29c024 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -167,5 +167,16 @@ LL | unwrapped LL | }) | -error: aborting due to 11 previous errors +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:112:5 + | +LL | / match match y { +LL | | 0 => 1, +LL | | _ => 2, +LL | | } { +LL | | _ => println!("Single branch"), +LL | | } + | |_____^ help: consider using the match body instead: `println!("Single branch");` + +error: aborting due to 12 previous errors From 1a5b9b037e0fb8cf204e44e604ff4ad09612b8b6 Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Sun, 13 Dec 2020 13:36:01 -0800 Subject: [PATCH 293/719] ./x.py fmt --- compiler/rustc_macros/src/symbols/tests.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_macros/src/symbols/tests.rs b/compiler/rustc_macros/src/symbols/tests.rs index 90a28b518020..82b4b876978f 100644 --- a/compiler/rustc_macros/src/symbols/tests.rs +++ b/compiler/rustc_macros/src/symbols/tests.rs @@ -58,10 +58,7 @@ fn check_dup_keywords() { } Symbols {} }; - test_symbols_macro( - input, - &["Symbol `crate` is duplicated", "location of previous definition"], - ); + test_symbols_macro(input, &["Symbol `crate` is duplicated", "location of previous definition"]); } #[test] @@ -73,10 +70,7 @@ fn check_dup_symbol() { splat, } }; - test_symbols_macro( - input, - &["Symbol `splat` is duplicated", "location of previous definition"], - ); + test_symbols_macro(input, &["Symbol `splat` is duplicated", "location of previous definition"]); } #[test] @@ -89,10 +83,7 @@ fn check_dup_symbol_and_keyword() { splat, } }; - test_symbols_macro( - input, - &["Symbol `splat` is duplicated", "location of previous definition"], - ); + test_symbols_macro(input, &["Symbol `splat` is duplicated", "location of previous definition"]); } #[test] From adda964bb5229a7e7fa21d28c77f7ad71afb9b15 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 12 Dec 2020 15:15:06 +0900 Subject: [PATCH 294/719] Check the number of entries in UI test --- src/tools/tidy/src/ui_tests.rs | 44 +++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 03f4efea983b..72ffdabd5222 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -1,9 +1,51 @@ -//! Tidy check to ensure that there are no stray `.stderr` files in UI test directories. +//! Tidy check to ensure below in UI test directories: +//! - the number of entries in each directory must be less than `ENTRY_LIMIT` +//! - there are no stray `.stderr` files use std::fs; use std::path::Path; +const ENTRY_LIMIT: usize = 1000; +// FIXME: The following limits should be reduced eventually. +const ROOT_ENTRY_LIMIT: usize = 1580; +const ISSUES_ENTRY_LIMIT: usize = 2830; + +fn check_entries(path: &Path, bad: &mut bool) { + let dirs = walkdir::WalkDir::new(&path.join("test/ui")) + .into_iter() + .filter_entry(|e| e.file_type().is_dir()); + for dir in dirs { + if let Ok(dir) = dir { + let dir_path = dir.path(); + + // Use special values for these dirs. + let is_root = path.join("test/ui") == dir_path; + let is_issues_dir = path.join("test/ui/issues") == dir_path; + let limit = if is_root { + ROOT_ENTRY_LIMIT + } else if is_issues_dir { + ISSUES_ENTRY_LIMIT + } else { + ENTRY_LIMIT + }; + + let count = std::fs::read_dir(dir_path).unwrap().count(); + if count >= limit { + tidy_error!( + bad, + "following path contains more than {} entries, \ + you should move the test to some relevant subdirectory (current: {}): {}", + limit, + count, + dir_path.display() + ); + } + } + } +} + pub fn check(path: &Path, bad: &mut bool) { + check_entries(&path, bad); for path in &[&path.join("test/ui"), &path.join("test/ui-fulldeps")] { super::walk_no_read(path, &mut |_| false, &mut |entry| { let file_path = entry.path(); From 426aba2ef4a00c5041b65116f542d3840a519e96 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Mon, 14 Dec 2020 11:57:35 +0900 Subject: [PATCH 295/719] Fix links in CONTRIBUTING.md --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49b64da1fb6b..d2a3c52dab98 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,10 +19,10 @@ All contributors are expected to follow the [Rust Code of Conduct]. - [Writing code](#writing-code) - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work) - [How Clippy works](#how-clippy-works) - - [Syncing changes between Clippy and [`rust-lang/rust`]](#syncing-changes-between-clippy-and-rust-langrust) + - [Syncing changes between Clippy and `rust-lang/rust`](#syncing-changes-between-clippy-and-rust-langrust) - [Patching git-subtree to work with big repos](#patching-git-subtree-to-work-with-big-repos) - - [Performing the sync from [`rust-lang/rust`] to Clippy](#performing-the-sync-from-rust-langrust-to-clippy) - - [Performing the sync from Clippy to [`rust-lang/rust`]](#performing-the-sync-from-clippy-to-rust-langrust) + - [Performing the sync from `rust-lang/rust` to Clippy](#performing-the-sync-from-rust-langrust-to-clippy) + - [Performing the sync from Clippy to `rust-lang/rust`](#performing-the-sync-from-clippy-to-rust-langrust) - [Defining remotes](#defining-remotes) - [Issue and PR triage](#issue-and-pr-triage) - [Bors and Homu](#bors-and-homu) From 850437b6f9915a5281c5085d45480b7d29f4e1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 9 Oct 2020 10:27:14 +0200 Subject: [PATCH 296/719] Cache link resolution results in current module Co-authored-by: Joshua Nelson --- .../passes/collect_intra_doc_links.rs | 93 ++++++++++++++++--- 1 file changed, 79 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7358eae6edc9..d888a87b9e7c 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -3,7 +3,7 @@ //! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md use rustc_ast as ast; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::SyntaxExtensionKind; use rustc_hir as hir; @@ -168,6 +168,31 @@ enum AnchorFailure { RustdocAnchorConflict(Res), } +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +struct CacheKey { + module_id: DefId, + dis: Option, + path_str: String, + extra_fragment: Option, +} + +impl CacheKey { + fn new( + module_id: DefId, + dis: Option, + path_str: String, + extra_fragment: Option, + ) -> Self { + Self { module_id, dis, path_str, extra_fragment } + } +} + +#[derive(Clone, Debug, Hash)] +struct CachedLink { + pub res: (Res, Option), + pub side_channel: Option<(DefKind, DefId)>, +} + struct LinkCollector<'a, 'tcx> { cx: &'a DocContext<'tcx>, /// A stack of modules used to decide what scope to resolve in. @@ -179,11 +204,18 @@ struct LinkCollector<'a, 'tcx> { /// because `clean` and the disambiguator code expect them to be different. /// See the code for associated items on inherent impls for details. kind_side_channel: Cell>, + /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link + visited_links: FxHashMap, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn new(cx: &'a DocContext<'tcx>) -> Self { - LinkCollector { cx, mod_ids: Vec::new(), kind_side_channel: Cell::new(None) } + LinkCollector { + cx, + mod_ids: Vec::new(), + kind_side_channel: Cell::new(None), + visited_links: FxHashMap::default(), + } } /// Given a full link, parse it as an [enum struct variant]. @@ -937,7 +969,7 @@ impl LinkCollector<'_, '_> { /// /// FIXME(jynelson): this is way too many arguments fn resolve_link( - &self, + &mut self, item: &Item, dox: &str, self_name: &Option, @@ -962,6 +994,7 @@ impl LinkCollector<'_, '_> { let link = ori_link.replace("`", ""); let parts = link.split('#').collect::>(); let (link, extra_fragment) = if parts.len() > 2 { + // A valid link can't have multiple #'s anchor_failure(cx, &item, &link, dox, link_range, AnchorFailure::MultipleAnchors); return None; } else if parts.len() == 2 { @@ -1075,16 +1108,9 @@ impl LinkCollector<'_, '_> { return None; } - let (mut res, mut fragment) = self.resolve_with_disambiguator( - disambiguator, - item, - dox, - path_str, - module_id, - extra_fragment, - &ori_link, - link_range.clone(), - )?; + let key = CacheKey::new(module_id, disambiguator, path_str.to_owned(), extra_fragment); + let (mut res, mut fragment) = + self.resolve_with_disambiguator_cached(key, item, dox, &ori_link, link_range.clone())?; // Check for a primitive which might conflict with a module // Report the ambiguity and require that the user specify which one they meant. @@ -1192,6 +1218,45 @@ impl LinkCollector<'_, '_> { } } + fn resolve_with_disambiguator_cached( + &mut self, + key: CacheKey, + item: &Item, + dox: &str, + ori_link: &str, + link_range: Option>, + ) -> Option<(Res, Option)> { + // Try to look up both the result and the corresponding side channel value + if let Some(ref cached) = self.visited_links.get(&key) { + self.kind_side_channel.set(cached.side_channel.clone()); + Some(cached.res.clone()) + } else { + match self.resolve_with_disambiguator( + key.dis, + item, + dox, + &key.path_str, + key.module_id, + key.extra_fragment.clone(), + ori_link, + link_range, + ) { + Some(res) => { + // Store result for the actual namespace + self.visited_links.insert( + key, + CachedLink { + res: res.clone(), + side_channel: self.kind_side_channel.clone().into_inner(), + }, + ); + Some(res) + } + _ => None, + } + } + } + /// After parsing the disambiguator, resolve the main part of the link. // FIXME(jynelson): wow this is just so much fn resolve_with_disambiguator( @@ -1356,7 +1421,7 @@ impl LinkCollector<'_, '_> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] /// Disambiguators for a link. enum Disambiguator { /// `prim@` From cc31b992b1919ddf0d0b05e90c0f37b40f77d4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 30 Nov 2020 23:16:50 +0100 Subject: [PATCH 297/719] Review suggestions --- .../passes/collect_intra_doc_links.rs | 166 +++++++++--------- 1 file changed, 87 insertions(+), 79 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index d888a87b9e7c..167eb07a690b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -169,22 +169,18 @@ enum AnchorFailure { } #[derive(Clone, Debug, Hash, PartialEq, Eq)] -struct CacheKey { +struct ResolutionInfo { module_id: DefId, dis: Option, path_str: String, extra_fragment: Option, } -impl CacheKey { - fn new( - module_id: DefId, - dis: Option, - path_str: String, - extra_fragment: Option, - ) -> Self { - Self { module_id, dis, path_str, extra_fragment } - } +struct DiagnosticInfo<'a> { + item: &'a Item, + dox: &'a str, + ori_link: &'a str, + link_range: Option>, } #[derive(Clone, Debug, Hash)] @@ -205,7 +201,7 @@ struct LinkCollector<'a, 'tcx> { /// See the code for associated items on inherent impls for details. kind_side_channel: Cell>, /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link - visited_links: FxHashMap, + visited_links: FxHashMap, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { @@ -1108,9 +1104,15 @@ impl LinkCollector<'_, '_> { return None; } - let key = CacheKey::new(module_id, disambiguator, path_str.to_owned(), extra_fragment); - let (mut res, mut fragment) = - self.resolve_with_disambiguator_cached(key, item, dox, &ori_link, link_range.clone())?; + let key = ResolutionInfo { + module_id, + dis: disambiguator, + path_str: path_str.to_owned(), + extra_fragment, + }; + let diag = + DiagnosticInfo { item, dox, ori_link: &ori_link, link_range: link_range.clone() }; + let (mut res, mut fragment) = self.resolve_with_disambiguator_cached(key, diag)?; // Check for a primitive which might conflict with a module // Report the ambiguity and require that the user specify which one they meant. @@ -1220,59 +1222,47 @@ impl LinkCollector<'_, '_> { fn resolve_with_disambiguator_cached( &mut self, - key: CacheKey, - item: &Item, - dox: &str, - ori_link: &str, - link_range: Option>, + key: ResolutionInfo, + diag: DiagnosticInfo<'_>, ) -> Option<(Res, Option)> { // Try to look up both the result and the corresponding side channel value if let Some(ref cached) = self.visited_links.get(&key) { self.kind_side_channel.set(cached.side_channel.clone()); - Some(cached.res.clone()) - } else { - match self.resolve_with_disambiguator( - key.dis, - item, - dox, - &key.path_str, - key.module_id, - key.extra_fragment.clone(), - ori_link, - link_range, - ) { - Some(res) => { - // Store result for the actual namespace - self.visited_links.insert( - key, - CachedLink { - res: res.clone(), - side_channel: self.kind_side_channel.clone().into_inner(), - }, - ); - Some(res) - } - _ => None, - } + return Some(cached.res.clone()); } + + let res = self.resolve_with_disambiguator(&key, diag); + + // Cache only if resolved successfully - don't silence duplicate errors + if let Some(res) = &res { + // Store result for the actual namespace + self.visited_links.insert( + key, + CachedLink { + res: res.clone(), + side_channel: self.kind_side_channel.clone().into_inner(), + }, + ); + } + + res } /// After parsing the disambiguator, resolve the main part of the link. // FIXME(jynelson): wow this is just so much fn resolve_with_disambiguator( &self, - disambiguator: Option, - item: &Item, - dox: &str, - path_str: &str, - base_node: DefId, - extra_fragment: Option, - ori_link: &str, - link_range: Option>, + key: &ResolutionInfo, + diag: DiagnosticInfo<'_>, ) -> Option<(Res, Option)> { + let disambiguator = key.dis; + let path_str = &key.path_str; + let base_node = key.module_id; + let extra_fragment = &key.extra_fragment; + match disambiguator.map(Disambiguator::ns) { Some(ns @ (ValueNS | TypeNS)) => { - match self.resolve(path_str, ns, base_node, &extra_fragment) { + match self.resolve(path_str, ns, base_node, extra_fragment) { Ok(res) => Some(res), Err(ErrorKind::Resolve(box mut kind)) => { // We only looked in one namespace. Try to give a better error if possible. @@ -1281,12 +1271,9 @@ impl LinkCollector<'_, '_> { // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator` // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach for &new_ns in &[other_ns, MacroNS] { - if let Some(res) = self.check_full_res( - new_ns, - path_str, - base_node, - &extra_fragment, - ) { + if let Some(res) = + self.check_full_res(new_ns, path_str, base_node, extra_fragment) + { kind = ResolutionFailure::WrongNamespace(res, ns); break; } @@ -1294,11 +1281,11 @@ impl LinkCollector<'_, '_> { } resolution_failure( self, - &item, + diag.item, path_str, disambiguator, - dox, - link_range, + diag.dox, + diag.link_range, smallvec![kind], ); // This could just be a normal link or a broken link @@ -1307,7 +1294,14 @@ impl LinkCollector<'_, '_> { return None; } Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(self.cx, &item, &ori_link, dox, link_range, msg); + anchor_failure( + self.cx, + diag.item, + diag.ori_link, + diag.dox, + diag.link_range, + msg, + ); return None; } } @@ -1318,21 +1312,35 @@ impl LinkCollector<'_, '_> { macro_ns: self .resolve_macro(path_str, base_node) .map(|res| (res, extra_fragment.clone())), - type_ns: match self.resolve(path_str, TypeNS, base_node, &extra_fragment) { + type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) { Ok(res) => { debug!("got res in TypeNS: {:?}", res); Ok(res) } Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(self.cx, &item, ori_link, dox, link_range, msg); + anchor_failure( + self.cx, + diag.item, + diag.ori_link, + diag.dox, + diag.link_range, + msg, + ); return None; } Err(ErrorKind::Resolve(box kind)) => Err(kind), }, - value_ns: match self.resolve(path_str, ValueNS, base_node, &extra_fragment) { + value_ns: match self.resolve(path_str, ValueNS, base_node, extra_fragment) { Ok(res) => Ok(res), Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(self.cx, &item, ori_link, dox, link_range, msg); + anchor_failure( + self.cx, + diag.item, + diag.ori_link, + diag.dox, + diag.link_range, + msg, + ); return None; } Err(ErrorKind::Resolve(box kind)) => Err(kind), @@ -1343,7 +1351,7 @@ impl LinkCollector<'_, '_> { Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { Err(ResolutionFailure::WrongNamespace(res, TypeNS)) } - _ => match (fragment, extra_fragment) { + _ => match (fragment, extra_fragment.clone()) { (Some(fragment), Some(_)) => { // Shouldn't happen but who knows? Ok((res, Some(fragment))) @@ -1359,11 +1367,11 @@ impl LinkCollector<'_, '_> { if len == 0 { resolution_failure( self, - &item, + diag.item, path_str, disambiguator, - dox, - link_range, + diag.dox, + diag.link_range, candidates.into_iter().filter_map(|res| res.err()).collect(), ); // this could just be a normal link @@ -1382,10 +1390,10 @@ impl LinkCollector<'_, '_> { let candidates = candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); ambiguity_error( self.cx, - &item, + diag.item, path_str, - dox, - link_range, + diag.dox, + diag.link_range, candidates.present_items().collect(), ); return None; @@ -1393,12 +1401,12 @@ impl LinkCollector<'_, '_> { } Some(MacroNS) => { match self.resolve_macro(path_str, base_node) { - Ok(res) => Some((res, extra_fragment)), + Ok(res) => Some((res, extra_fragment.clone())), Err(mut kind) => { // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible. for &ns in &[TypeNS, ValueNS] { if let Some(res) = - self.check_full_res(ns, path_str, base_node, &extra_fragment) + self.check_full_res(ns, path_str, base_node, extra_fragment) { kind = ResolutionFailure::WrongNamespace(res, MacroNS); break; @@ -1406,11 +1414,11 @@ impl LinkCollector<'_, '_> { } resolution_failure( self, - &item, + diag.item, path_str, disambiguator, - dox, - link_range, + diag.dox, + diag.link_range, smallvec![kind], ); return None; From fa64c272c8253c9df01fa4c28e34095735411e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 30 Nov 2020 23:17:11 +0100 Subject: [PATCH 298/719] Add test case for Self:: links --- src/test/rustdoc/intra-link-self-cache.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/rustdoc/intra-link-self-cache.rs diff --git a/src/test/rustdoc/intra-link-self-cache.rs b/src/test/rustdoc/intra-link-self-cache.rs new file mode 100644 index 000000000000..add1530a5a67 --- /dev/null +++ b/src/test/rustdoc/intra-link-self-cache.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] +// @has foo/enum.E1.html '//a/@href' '../foo/enum.E1.html#variant.A' + +/// [Self::A::b] +pub enum E1 { + A { b: usize } +} + +// @has foo/enum.E2.html '//a/@href' '../foo/enum.E2.html#variant.A' + +/// [Self::A::b] +pub enum E2 { + A { b: usize } +} From 6c7835e4410f820c2bcdcd3d34fa48f0053af7d4 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Fri, 20 Nov 2020 21:29:00 +0100 Subject: [PATCH 299/719] BTreeSet: simplify implementation of pop_first/pop_last --- library/alloc/src/collections/btree/set.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index d8ce47ed77d1..f63c3dd58040 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -679,7 +679,7 @@ impl BTreeSet { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn pop_first(&mut self) -> Option { - self.map.first_entry().map(|entry| entry.remove_entry().0) + self.map.pop_first().map(|kv| kv.0) } /// Removes the last value from the set and returns it, if any. @@ -701,7 +701,7 @@ impl BTreeSet { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn pop_last(&mut self) -> Option { - self.map.last_entry().map(|entry| entry.remove_entry().0) + self.map.pop_last().map(|kv| kv.0) } /// Adds a value to the set. From 44b331047dd5ab70d2e1e8671aeb8ee799a3b38d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 14 Dec 2020 12:52:41 +0100 Subject: [PATCH 300/719] Also emit vcode when emitting clif ir while using new style backends --- src/base.rs | 10 +++++ src/pretty_clif.rs | 100 +++++++++++++++++++++++++-------------------- 2 files changed, 66 insertions(+), 44 deletions(-) diff --git a/src/base.rs b/src/base.rs index 3af4897b4f0b..5ba992d93724 100644 --- a/src/base.rs +++ b/src/base.rs @@ -118,6 +118,8 @@ pub(crate) fn codegen_fn<'tcx>( context.eliminate_unreachable_code(cx.module.isa()).unwrap(); context.dce(cx.module.isa()).unwrap(); + context.want_disasm = crate::pretty_clif::should_write_ir(tcx); + // Define function let module = &mut cx.module; tcx.sess.time("define function", || { @@ -140,6 +142,14 @@ pub(crate) fn codegen_fn<'tcx>( &clif_comments, ); + if let Some(mach_compile_result) = &context.mach_compile_result { + if let Some(disasm) = &mach_compile_result.disasm { + crate::pretty_clif::write_ir_file(tcx, &format!("{}.vcode", tcx.symbol_name(instance).name), |file| { + file.write_all(disasm.as_bytes()) + }) + } + } + // Define debuginfo for function let isa = cx.module.isa(); let debug_context = &mut cx.debug_context; diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index a9f060e51d8f..1d17157a8761 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -53,6 +53,7 @@ //! ``` use std::fmt; +use std::io::Write; use cranelift_codegen::{ entity::SecondaryMap, @@ -200,32 +201,24 @@ impl FunctionCx<'_, '_, M> { } } -pub(crate) fn write_clif_file<'tcx>( - tcx: TyCtxt<'tcx>, - postfix: &str, - isa: Option<&dyn cranelift_codegen::isa::TargetIsa>, - instance: Instance<'tcx>, - context: &cranelift_codegen::Context, - mut clif_comments: &CommentWriter, -) { - use std::io::Write; - - if !cfg!(debug_assertions) - && !tcx +pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool { + cfg!(debug_assertions) + || tcx .sess .opts .output_types .contains_key(&OutputType::LlvmAssembly) - { +} + +pub(crate) fn write_ir_file<'tcx>( + tcx: TyCtxt<'tcx>, + name: &str, + write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>, +) { + if !should_write_ir(tcx) { return; } - let value_ranges = isa.map(|isa| { - context - .build_value_labels_ranges(isa) - .expect("value location ranges") - }); - let clif_output_dir = tcx.output_filenames(LOCAL_CRATE).with_extension("clif"); match std::fs::create_dir(&clif_output_dir) { @@ -234,39 +227,58 @@ pub(crate) fn write_clif_file<'tcx>( res @ Err(_) => res.unwrap(), } - let clif_file_name = clif_output_dir.join(format!( - "{}.{}.clif", - tcx.symbol_name(instance).name, - postfix - )); - - let mut clif = String::new(); - cranelift_codegen::write::decorate_function( - &mut clif_comments, - &mut clif, - &context.func, - &DisplayFunctionAnnotations { - isa: Some(&*crate::build_isa( - tcx.sess, true, /* PIC doesn't matter here */ - )), - value_ranges: value_ranges.as_ref(), - }, - ) - .unwrap(); + let clif_file_name = clif_output_dir.join(name); let res: std::io::Result<()> = try { let mut file = std::fs::File::create(clif_file_name)?; - let target_triple = crate::target_triple(tcx.sess); + write(&mut file)?; + }; + if let Err(err) = res { + tcx.sess.warn(&format!("error writing ir file: {}", err)); + } +} + +pub(crate) fn write_clif_file<'tcx>( + tcx: TyCtxt<'tcx>, + postfix: &str, + isa: Option<&dyn cranelift_codegen::isa::TargetIsa>, + instance: Instance<'tcx>, + context: &cranelift_codegen::Context, + mut clif_comments: &CommentWriter, +) { + write_ir_file(tcx, &format!( + "{}.{}.clif", + tcx.symbol_name(instance).name, + postfix + ), |file| { + let value_ranges = isa.map(|isa| { + context + .build_value_labels_ranges(isa) + .expect("value location ranges") + }); + + let mut clif = String::new(); + cranelift_codegen::write::decorate_function( + &mut clif_comments, + &mut clif, + &context.func, + &DisplayFunctionAnnotations { + isa: Some(&*crate::build_isa( + tcx.sess, true, /* PIC doesn't matter here */ + )), + value_ranges: value_ranges.as_ref(), + }, + ) + .unwrap(); + writeln!(file, "test compile")?; writeln!(file, "set is_pic")?; writeln!(file, "set enable_simd")?; - writeln!(file, "target {} haswell", target_triple)?; + writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?; writeln!(file)?; file.write_all(clif.as_bytes())?; - }; - if let Err(err) = res { - tcx.sess.warn(&format!("err writing clif file: {}", err)); - } + Ok(()) + }); } impl fmt::Debug for FunctionCx<'_, '_, M> { From becd0e8896079016cd615def3799b8133636b39e Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 14 Dec 2020 23:10:15 +0900 Subject: [PATCH 301/719] Replace some `println!` with `tidy_error!` to simplify --- src/tools/tidy/src/deps.rs | 29 +++++++++++++---------------- src/tools/tidy/src/extdeps.rs | 3 +-- src/tools/tidy/src/features.rs | 1 - src/tools/tidy/src/lib.rs | 4 ++++ src/tools/tidy/src/ui_tests.rs | 6 ++---- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 057b0884e287..952782175f13 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -214,12 +214,12 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { for (name, license) in EXCEPTIONS { // Check that the package actually exists. if !metadata.packages.iter().any(|p| p.name == *name) { - println!( + tidy_error!( + bad, "could not find exception package `{}`\n\ Remove from EXCEPTIONS list if it is no longer used.", name ); - *bad = true; } // Check that the license hasn't changed. for pkg in metadata.packages.iter().filter(|p| p.name == *name) { @@ -232,11 +232,11 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { } match &pkg.license { None => { - println!( + tidy_error!( + bad, "dependency exception `{}` does not declare a license expression", pkg.id ); - *bad = true; } Some(pkg_license) => { if pkg_license.as_str() != *license { @@ -273,8 +273,7 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { let license = match &pkg.license { Some(license) => license, None => { - println!("dependency `{}` does not define a license expression", pkg.id,); - *bad = true; + tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id); continue; } }; @@ -286,8 +285,7 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { // general, these should never be added. continue; } - println!("invalid license `{}` in `{}`", license, pkg.id); - *bad = true; + tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id); } } } @@ -300,12 +298,12 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) { // Check that the PERMITTED_DEPENDENCIES does not have unused entries. for name in PERMITTED_DEPENDENCIES { if !metadata.packages.iter().any(|p| p.name == *name) { - println!( + tidy_error!( + bad, "could not find allowed package `{}`\n\ Remove from PERMITTED_DEPENDENCIES list if it is no longer used.", name ); - *bad = true; } } // Get the list in a convenient form. @@ -322,11 +320,10 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) { } if !unapproved.is_empty() { - println!("Dependencies not explicitly permitted:"); + tidy_error!(bad, "Dependencies not explicitly permitted:"); for dep in unapproved { println!("* {}", dep); } - *bad = true; } } @@ -381,16 +378,17 @@ fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) { let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect(); match matches.len() { 0 => { - println!( + tidy_error!( + bad, "crate `{}` is missing, update `check_crate_duplicate` \ if it is no longer used", name ); - *bad = true; } 1 => {} _ => { - println!( + tidy_error!( + bad, "crate `{}` is duplicated in `Cargo.lock`, \ it is too expensive to build multiple times, \ so make sure only one version appears across all dependencies", @@ -399,7 +397,6 @@ fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) { for pkg in matches { println!(" * {}", pkg.id); } - *bad = true; } } } diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index 93d4d3d8047d..aad57cacbb41 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -27,8 +27,7 @@ pub fn check(root: &Path, bad: &mut bool) { // Ensure source is allowed. if !ALLOWED_SOURCES.contains(&&*source) { - println!("invalid source: {}", source); - *bad = true; + tidy_error!(bad, "invalid source: {}", source); } } } diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 3c2880d0d5e2..d78af2cd6164 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -330,7 +330,6 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features let issue_str = parts.next().unwrap().trim(); let tracking_issue = if issue_str.starts_with("None") { if level == Status::Unstable && !next_feature_omits_tracking_issue { - *bad = true; tidy_error!( bad, "{}:{}: no tracking issue for feature {}", diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index e11d293210b0..d282d240d823 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -28,6 +28,10 @@ macro_rules! t { } macro_rules! tidy_error { + ($bad:expr, $fmt:expr) => ({ + *$bad = true; + eprintln!("tidy error: {}", $fmt); + }); ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ *$bad = true; eprint!("tidy error: "); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 72ffdabd5222..d8d2b449fee8 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -67,14 +67,12 @@ pub fn check(path: &Path, bad: &mut bool) { let testname = file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0; if !file_path.with_file_name(testname).with_extension("rs").exists() { - println!("Stray file with UI testing output: {:?}", file_path); - *bad = true; + tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path); } if let Ok(metadata) = fs::metadata(file_path) { if metadata.len() == 0 { - println!("Empty file with UI testing output: {:?}", file_path); - *bad = true; + tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path); } } } From 357565dc19fc7f1b53d309ed10f61d21d0076459 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 14 Dec 2020 23:33:20 +0900 Subject: [PATCH 302/719] expand-yaml-anchors: Make the output directory separator-insensitive --- src/tools/expand-yaml-anchors/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/expand-yaml-anchors/src/main.rs b/src/tools/expand-yaml-anchors/src/main.rs index f7ff64036a1a..f8cf18a9309e 100644 --- a/src/tools/expand-yaml-anchors/src/main.rs +++ b/src/tools/expand-yaml-anchors/src/main.rs @@ -87,7 +87,8 @@ impl App { let content = std::fs::read_to_string(source) .with_context(|| format!("failed to read {}", self.path(source)))?; - let mut buf = HEADER_MESSAGE.replace("{source}", &self.path(source).to_string()); + let mut buf = + HEADER_MESSAGE.replace("{source}", &self.path(source).to_string().replace("\\", "/")); let documents = YamlLoader::load_from_str(&content) .with_context(|| format!("failed to parse {}", self.path(source)))?; From 8b1e9ed85b180553ce74af1555ad7d980f79667c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Mon, 14 Dec 2020 17:47:05 +0100 Subject: [PATCH 303/719] bump pinned nightly from nightly-2020-12-09 to nightly-2020-12-14 This should hopefully fix incremental compilation ICEs from rustc that I have been encountering multiple times while working with the previous nightly. --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index dfa7dea449a6..ac51154f8a9d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2020-12-09" +channel = "nightly-2020-12-14" components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] From 01c25200816cb03a2bafee7b34680cde7867d979 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Mon, 14 Dec 2020 12:47:11 -0500 Subject: [PATCH 304/719] Add explanation for skip_binder in relate --- compiler/rustc_middle/src/ty/relate.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 8a3a6305d01b..af7fc4297195 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -616,6 +616,7 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List = a.into_iter().collect(); let mut b_v: Vec<_> = b.into_iter().collect(); + // `skip_binder` here is okay because `stable_cmp` doesn't look at binders a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); a_v.dedup(); b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); From 4f550f1f930b9201bbeeb9fa10d42392a66cc9f2 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 14 Dec 2020 00:25:29 -0800 Subject: [PATCH 305/719] Improve warnings on incompatible options involving -Zinstrument-coverage Adds checks for: * `no_core` attribute * explicitly-enabled `legacy` symbol mangling * mir_opt_level > 1 (which enables inlining) I removed code from the `Inline` MIR pass that forcibly disabled inlining if `-Zinstrument-coverage` was set. The default `mir_opt_level` does not enable inlining anyway. But if the level is explicitly set and is greater than 1, I issue a warning. The new warnings show up in tests, which is much better for diagnosing potential option conflicts in these cases. --- compiler/rustc_interface/src/tests.rs | 4 +- compiler/rustc_metadata/src/creader.rs | 11 +++++- compiler/rustc_metadata/src/rmeta/encoder.rs | 7 +++- .../rustc_mir/src/transform/const_prop.rs | 8 ++-- compiler/rustc_mir/src/transform/dest_prop.rs | 3 +- .../src/transform/early_otherwise_branch.rs | 3 +- compiler/rustc_mir/src/transform/inline.rs | 11 +----- .../rustc_mir/src/transform/match_branches.rs | 3 +- compiler/rustc_mir/src/transform/mod.rs | 3 +- .../transform/multiple_return_terminators.rs | 3 +- compiler/rustc_mir/src/transform/nrvo.rs | 3 +- .../src/transform/unreachable_prop.rs | 3 +- compiler/rustc_session/src/config.rs | 38 ++++++++++++++++++- compiler/rustc_session/src/options.rs | 12 +++--- compiler/rustc_symbol_mangling/src/lib.rs | 6 ++- src/tools/clippy/src/driver.rs | 34 +++++++++-------- 16 files changed, 103 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 2273266a3ff8..7a7def0696db 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -561,7 +561,7 @@ fn test_debugging_options_tracking_hash() { tracked!(link_only, true); tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(mir_emit_retag, true); - tracked!(mir_opt_level, 3); + tracked!(mir_opt_level, Some(3)); tracked!(mutable_noalias, true); tracked!(new_llvm_pass_manager, true); tracked!(no_codegen, true); @@ -587,7 +587,7 @@ fn test_debugging_options_tracking_hash() { tracked!(share_generics, Some(true)); tracked!(show_span, Some(String::from("abc"))); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); - tracked!(symbol_mangling_version, SymbolManglingVersion::V0); + tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(teach, true); tracked!(thinlto, Some(true)); tracked!(tune_cpu, Some(String::from("abc"))); diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 33cbf0fb2345..019ca5174a22 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -706,7 +706,7 @@ impl<'a> CrateLoader<'a> { self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime()); } - fn inject_profiler_runtime(&mut self) { + fn inject_profiler_runtime(&mut self, krate: &ast::Crate) { if (self.sess.opts.debugging_opts.instrument_coverage || self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled()) @@ -714,6 +714,13 @@ impl<'a> CrateLoader<'a> { { info!("loading profiler"); + if self.sess.contains_name(&krate.attrs, sym::no_core) { + self.sess.err( + "`profiler_builtins` crate (required by compiler options) \ + is not compatible with crate attribute `#![no_core]`", + ); + } + let name = sym::profiler_builtins; let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, None); let data = self.cstore.get_crate_data(cnum); @@ -879,7 +886,7 @@ impl<'a> CrateLoader<'a> { } pub fn postprocess(&mut self, krate: &ast::Crate) { - self.inject_profiler_runtime(); + self.inject_profiler_runtime(krate); self.inject_allocator_crate(krate); self.inject_panic_runtime(krate); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 46dd0df65e06..b0c75c1de9d1 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -663,7 +663,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins), panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime), profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime), - symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version, + symbol_mangling_version: tcx + .sess + .opts + .debugging_opts + .symbol_mangling_version + .unwrap_or(SymbolManglingVersion::default()), crate_deps, dylib_dependency_formats, diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 1d949e020ed5..49b1cf92600e 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -22,6 +22,7 @@ use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{ self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable, }; +use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use rustc_session::lint; use rustc_span::{def_id::DefId, Span}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout}; @@ -708,7 +709,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } - if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 3 { + if self.tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) >= 3 { self.eval_rvalue_with_identities(rvalue, place) } else { self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place)) @@ -886,7 +887,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Returns `true` if and only if this `op` should be const-propagated into. fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool { - let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level; + let mir_opt_level = + self.tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT); if mir_opt_level == 0 { return false; @@ -1056,7 +1058,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { // Only const prop copies and moves on `mir_opt_level=2` as doing so // currently slightly increases compile time in some cases. - if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { + if self.tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) >= 2 { self.propagate_operand(operand) } } diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 46de5dba6e0e..2363b6d58e1d 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -115,6 +115,7 @@ use rustc_middle::mir::{ Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; // Empirical measurements have resulted in some observations: // - Running on a body with a single block and 500 locals takes barely any time @@ -129,7 +130,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Only run at mir-opt-level=2 or higher for now (we don't fix up debuginfo and remove // storage statements at the moment). - if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { + if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) <= 1 { return; } diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index f91477911a48..023561923eeb 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -1,6 +1,7 @@ use crate::{transform::MirPass, util::patch::MirPatch}; use rustc_middle::mir::*; use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use std::fmt::Debug; use super::simplify::simplify_cfg; @@ -26,7 +27,7 @@ pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { + if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) < 2 { return; } trace!("running EarlyOtherwiseBranch on {:?}", body.source); diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index 4eeb8969bb11..1a927f9bf505 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -9,6 +9,7 @@ use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use rustc_span::{hygiene::ExpnKind, ExpnData, Span}; use rustc_target::spec::abi::Abi; @@ -37,15 +38,7 @@ struct CallSite<'tcx> { impl<'tcx> MirPass<'tcx> for Inline { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { - return; - } - - if tcx.sess.opts.debugging_opts.instrument_coverage { - // The current implementation of source code coverage injects code region counters - // into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code- - // based function. - debug!("function inlining is disabled when compiling with `instrument_coverage`"); + if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) < 2 { return; } diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index 53eeecc780f6..e28e3f59a5e0 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -1,6 +1,7 @@ use crate::transform::MirPass; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; pub struct MatchBranchSimplification; @@ -38,7 +39,7 @@ pub struct MatchBranchSimplification; impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { + if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) <= 1 { return; } diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index e86d11e248fc..039dfe2c0d50 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -10,6 +10,7 @@ use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; +use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use rustc_span::{Span, Symbol}; use std::borrow::Cow; @@ -373,7 +374,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc } fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let mir_opt_level = tcx.sess.opts.debugging_opts.mir_opt_level; + let mir_opt_level = tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT); // Lowering generator control-flow and variables has to happen before we do anything else // to them. We run some optimizations before that, because they may be harder to do on the state diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs index 617086622cc1..de4aee7ddbcc 100644 --- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs +++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs @@ -5,12 +5,13 @@ use crate::transform::{simplify, MirPass}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; pub struct MultipleReturnTerminators; impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level < 3 { + if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) < 3 { return; } diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs index ce02fb261df6..6e1dc03b9cb3 100644 --- a/compiler/rustc_mir/src/transform/nrvo.rs +++ b/compiler/rustc_mir/src/transform/nrvo.rs @@ -5,6 +5,7 @@ use rustc_index::bit_set::HybridBitSet; use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, BasicBlock, Local, Location}; use rustc_middle::ty::TyCtxt; +use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use crate::transform::MirPass; @@ -34,7 +35,7 @@ pub struct RenameReturnPlace; impl<'tcx> MirPass<'tcx> for RenameReturnPlace { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level == 0 { + if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) == 0 { return; } diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs index e39c8656021b..c9053ce81cd0 100644 --- a/compiler/rustc_mir/src/transform/unreachable_prop.rs +++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs @@ -7,12 +7,13 @@ use crate::transform::MirPass; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; pub struct UnreachablePropagation; impl MirPass<'_> for UnreachablePropagation { fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level < 3 { + if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) < 3 { // Enable only under -Zmir-opt-level=3 as in some cases (check the deeply-nested-opt // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code. return; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 54abb65dc388..47e494b78c7d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -174,6 +174,8 @@ pub enum MirSpanview { Block, } +pub const MIR_OPT_LEVEL_DEFAULT: usize = 1; + #[derive(Clone, PartialEq, Hash)] pub enum LinkerPluginLto { LinkerPlugin(PathBuf), @@ -212,6 +214,12 @@ pub enum SymbolManglingVersion { V0, } +impl SymbolManglingVersion { + pub fn default() -> Self { + SymbolManglingVersion::Legacy + } +} + impl_stable_hash_via_hash!(SymbolManglingVersion); #[derive(Clone, Copy, Debug, PartialEq, Hash)] @@ -1757,7 +1765,33 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over // multiple runs, including some changes to source code; so mangled names must be consistent // across compilations. - debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0; + match debugging_opts.symbol_mangling_version { + None => { + debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0); + } + Some(SymbolManglingVersion::Legacy) => { + early_warn( + error_format, + "-Z instrument-coverage requires symbol mangling version `v0`, \ + but `-Z symbol-mangling-version=legacy` was specified", + ); + } + Some(SymbolManglingVersion::V0) => {} + } + + match debugging_opts.mir_opt_level { + Some(level) if level > 1 => { + early_warn( + error_format, + &format!( + "`-Z mir-opt-level={}` (any level > 1) enables function inlining, which \ + limits the effectiveness of `-Z instrument-coverage`.", + level, + ), + ); + } + _ => {} + } } if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { @@ -2162,7 +2196,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(Edition); impl_dep_tracking_hash_via_hash!(LinkerPluginLto); impl_dep_tracking_hash_via_hash!(SwitchWithOptPath); - impl_dep_tracking_hash_via_hash!(SymbolManglingVersion); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(TrimmedDefPaths); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 74578f2dc179..1909550aca48 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -677,12 +677,12 @@ macro_rules! options { } fn parse_symbol_mangling_version( - slot: &mut SymbolManglingVersion, + slot: &mut Option, v: Option<&str>, ) -> bool { *slot = match v { - Some("legacy") => SymbolManglingVersion::Legacy, - Some("v0") => SymbolManglingVersion::V0, + Some("legacy") => Some(SymbolManglingVersion::Legacy), + Some("v0") => Some(SymbolManglingVersion::V0), _ => return false, }; true @@ -970,7 +970,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, mir_emit_retag: bool = (false, parse_bool, [TRACKED], "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ (default: no)"), - mir_opt_level: usize = (1, parse_uint, [TRACKED], + mir_opt_level: Option = (None, parse_opt_uint, [TRACKED], "MIR optimization level (0-3; default: 1)"), mutable_noalias: bool = (false, parse_bool, [TRACKED], "emit noalias metadata for mutable references (default: no)"), @@ -1088,9 +1088,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), - symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy, + symbol_mangling_version: Option = (None, parse_symbol_mangling_version, [TRACKED], - "which mangling version to use for symbol names"), + "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 10245d21b63a..945e788a1460 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -245,7 +245,11 @@ fn compute_symbol_name( // 2. we favor `instantiating_crate` where possible (i.e. when `Some`) let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate); let mangling_version = if mangling_version_crate == LOCAL_CRATE { - tcx.sess.opts.debugging_opts.symbol_mangling_version + tcx.sess + .opts + .debugging_opts + .symbol_mangling_version + .unwrap_or(SymbolManglingVersion::default()) } else { tcx.symbol_mangling_version(mangling_version_crate) }; diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index ef31c72481a2..9e5ae21f7026 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -41,7 +41,7 @@ fn arg_value<'a, T: Deref>( match arg.next().or_else(|| args.next()) { Some(v) if pred(v) => return Some(v), - _ => {}, + _ => {} } } None @@ -85,7 +85,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // run on the unoptimized MIR. On the other hand this results in some false negatives. If // MIR passes can be enabled / disabled separately, we should figure out, what passes to // use for Clippy. - config.opts.debugging_opts.mir_opt_level = 0; + config.opts.debugging_opts.mir_opt_level = Some(0); } } @@ -121,11 +121,12 @@ You can use tool lints to allow or deny lints from your code, eg.: const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new"; -static ICE_HOOK: SyncLazy) + Sync + Send + 'static>> = SyncLazy::new(|| { - let hook = panic::take_hook(); - panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); - hook -}); +static ICE_HOOK: SyncLazy) + Sync + Send + 'static>> = + SyncLazy::new(|| { + let hook = panic::take_hook(); + panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); + hook + }); fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace @@ -257,14 +258,17 @@ pub fn main() { // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programmatically, so we ignore this/ - let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref()); + let wrapper_mode = + orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref()); if wrapper_mode { // we still want to be able to invoke it normally though orig_args.remove(1); } - if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) { + if !wrapper_mode + && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) + { display_help(); exit(0); } @@ -285,13 +289,11 @@ pub fn main() { if clippy_enabled { args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]); if let Ok(extra_args) = env::var("CLIPPY_ARGS") { - args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| { - if s.is_empty() { - None - } else { - Some(s.to_string()) - } - })); + args.extend( + extra_args + .split("__CLIPPY_HACKERY__") + .filter_map(|s| if s.is_empty() { None } else { Some(s.to_string()) }), + ); } } let mut clippy = ClippyCallbacks; From 3043a7b5d9c990c63335cb31869fff58f8ca5617 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 14 Dec 2020 00:25:29 -0800 Subject: [PATCH 306/719] Improve warnings on incompatible options involving -Zinstrument-coverage Adds checks for: * `no_core` attribute * explicitly-enabled `legacy` symbol mangling * mir_opt_level > 1 (which enables inlining) I removed code from the `Inline` MIR pass that forcibly disabled inlining if `-Zinstrument-coverage` was set. The default `mir_opt_level` does not enable inlining anyway. But if the level is explicitly set and is greater than 1, I issue a warning. The new warnings show up in tests, which is much better for diagnosing potential option conflicts in these cases. --- src/driver.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index ef31c72481a2..9e5ae21f7026 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -41,7 +41,7 @@ fn arg_value<'a, T: Deref>( match arg.next().or_else(|| args.next()) { Some(v) if pred(v) => return Some(v), - _ => {}, + _ => {} } } None @@ -85,7 +85,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // run on the unoptimized MIR. On the other hand this results in some false negatives. If // MIR passes can be enabled / disabled separately, we should figure out, what passes to // use for Clippy. - config.opts.debugging_opts.mir_opt_level = 0; + config.opts.debugging_opts.mir_opt_level = Some(0); } } @@ -121,11 +121,12 @@ You can use tool lints to allow or deny lints from your code, eg.: const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new"; -static ICE_HOOK: SyncLazy) + Sync + Send + 'static>> = SyncLazy::new(|| { - let hook = panic::take_hook(); - panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); - hook -}); +static ICE_HOOK: SyncLazy) + Sync + Send + 'static>> = + SyncLazy::new(|| { + let hook = panic::take_hook(); + panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); + hook + }); fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace @@ -257,14 +258,17 @@ pub fn main() { // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programmatically, so we ignore this/ - let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref()); + let wrapper_mode = + orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref()); if wrapper_mode { // we still want to be able to invoke it normally though orig_args.remove(1); } - if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) { + if !wrapper_mode + && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) + { display_help(); exit(0); } @@ -285,13 +289,11 @@ pub fn main() { if clippy_enabled { args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]); if let Ok(extra_args) = env::var("CLIPPY_ARGS") { - args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| { - if s.is_empty() { - None - } else { - Some(s.to_string()) - } - })); + args.extend( + extra_args + .split("__CLIPPY_HACKERY__") + .filter_map(|s| if s.is_empty() { None } else { Some(s.to_string()) }), + ); } } let mut clippy = ClippyCallbacks; From 777ca999a999a601b1b4eb3b6147fa77d2ea902c Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 14 Dec 2020 21:01:19 +0200 Subject: [PATCH 307/719] Optimization for bool's PartialOrd impl --- library/core/src/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f752472c3ba8..0c459a820c6e 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1236,7 +1236,7 @@ mod impls { impl PartialOrd for bool { #[inline] fn partial_cmp(&self, other: &bool) -> Option { - (*self as u8).partial_cmp(&(*other as u8)) + Some(self.cmp(other)) } } From a72b739bf0b21d714ed7072fd9c7e807cd549872 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Mon, 14 Dec 2020 23:33:47 +0100 Subject: [PATCH 308/719] Remove unused `TyEncoder::tcx` required method --- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 ---- compiler/rustc_middle/src/ty/codec.rs | 1 - compiler/rustc_middle/src/ty/query/on_disk_cache.rs | 3 --- 3 files changed, 8 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 46dd0df65e06..63aa4a23a3a5 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -319,10 +319,6 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { self.opaque.position() } - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - fn type_shorthands(&mut self) -> &mut FxHashMap, usize> { &mut self.type_shorthands } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index b2fc3710cd67..1983af17dd07 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -69,7 +69,6 @@ impl OpaqueEncoder for rustc_serialize::opaque::Encoder { pub trait TyEncoder<'tcx>: Encoder { const CLEAR_CROSS_CRATE: bool; - fn tcx(&self) -> TyCtxt<'tcx>; fn position(&self) -> usize; fn type_shorthands(&mut self) -> &mut FxHashMap, usize>; fn predicate_shorthands(&mut self) -> &mut FxHashMap, usize>; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 3eed94b1ffbc..e006dfeb6633 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -1044,9 +1044,6 @@ where { const CLEAR_CROSS_CRATE: bool = false; - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } fn position(&self) -> usize { self.encoder.encoder_position() } From a9ff4bd838a976e0215d3b6c06014eabc028550e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 15 Dec 2020 00:00:00 +0000 Subject: [PATCH 309/719] Always run intrinsics lowering pass Move intrinsics lowering pass from the optimization phase (where it would not run if -Zmir-opt-level=0), to the drop lowering phase where it runs unconditionally. The implementation of those intrinsics in code generation and interpreter is unnecessary. Remove it. --- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 16 +--------- .../rustc_mir/src/interpret/intrinsics.rs | 31 +++++-------------- compiler/rustc_mir/src/transform/mod.rs | 2 +- ...trinsics.discriminant.LowerIntrinsics.diff | 4 +++ ...wer_intrinsics.forget.LowerIntrinsics.diff | 8 +++++ ..._intrinsics.non_const.LowerIntrinsics.diff | 4 +++ ...er_intrinsics.size_of.LowerIntrinsics.diff | 4 +++ ...ntrinsics.unreachable.LowerIntrinsics.diff | 4 +++ ...r_intrinsics.wrapping.LowerIntrinsics.diff | 4 +++ 9 files changed, 38 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 72a64a8c5103..34022643101b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -83,9 +83,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - sym::unreachable => { - return; - } sym::va_start => bx.va_start(args[0].immediate()), sym::va_end => bx.va_end(args[0].immediate()), sym::size_of_val => { @@ -106,8 +103,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes()) } } - sym::size_of - | sym::pref_align_of + sym::pref_align_of | sym::min_align_of | sym::needs_drop | sym::type_id @@ -119,10 +115,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .unwrap(); OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) } - // Effectively no-op - sym::forget => { - return; - } sym::offset => { let ptr = args[0].immediate(); let offset = args[1].immediate(); @@ -218,9 +210,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow - | sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul | sym::unchecked_div | sym::unchecked_rem | sym::unchecked_shl @@ -254,9 +243,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - sym::wrapping_add => bx.add(args[0].immediate(), args[1].immediate()), - sym::wrapping_sub => bx.sub(args[0].immediate(), args[1].immediate()), - sym::wrapping_mul => bx.mul(args[0].immediate(), args[1].immediate()), sym::exact_div => { if signed { bx.exactsdiv(args[0].immediate(), args[1].immediate()) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index dfd77a8fca96..474e1f8e577f 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -61,12 +61,11 @@ crate fn eval_nullary_intrinsic<'tcx>( ConstValue::Slice { data: alloc, start: 0, end: alloc.len() } } sym::needs_drop => ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)), - sym::size_of | sym::min_align_of | sym::pref_align_of => { + sym::min_align_of | sym::pref_align_of => { let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?; let n = match name { sym::pref_align_of => layout.align.pref.bytes(), sym::min_align_of => layout.align.abi.bytes(), - sym::size_of => layout.size.bytes(), _ => bug!(), }; ConstValue::from_machine_usize(n, &tcx) @@ -125,7 +124,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (dest, ret) = match ret { None => match intrinsic_name { sym::transmute => throw_ub_format!("transmuting to uninhabited type"), - sym::unreachable => throw_ub!(Unreachable), sym::abort => M::abort(self, "the program aborted execution".to_owned())?, // Unsupported diverging intrinsic. _ => return Ok(false), @@ -160,13 +158,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::min_align_of | sym::pref_align_of | sym::needs_drop - | sym::size_of | sym::type_id | sym::type_name | sym::variant_count => { let gid = GlobalId { instance, promoted: None }; let ty = match intrinsic_name { - sym::min_align_of | sym::pref_align_of | sym::size_of | sym::variant_count => { + sym::min_align_of | sym::pref_align_of | sym::variant_count => { self.tcx.types.usize } sym::needs_drop => self.tcx.types.bool, @@ -212,28 +209,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let out_val = numeric_intrinsic(intrinsic_name, bits, kind)?; self.write_scalar(out_val, dest)?; } - sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul - | sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow => { + sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { let lhs = self.read_immediate(args[0])?; let rhs = self.read_immediate(args[1])?; - let (bin_op, ignore_overflow) = match intrinsic_name { - sym::wrapping_add => (BinOp::Add, true), - sym::wrapping_sub => (BinOp::Sub, true), - sym::wrapping_mul => (BinOp::Mul, true), - sym::add_with_overflow => (BinOp::Add, false), - sym::sub_with_overflow => (BinOp::Sub, false), - sym::mul_with_overflow => (BinOp::Mul, false), + let bin_op = match intrinsic_name { + sym::add_with_overflow => BinOp::Add, + sym::sub_with_overflow => BinOp::Sub, + sym::mul_with_overflow => BinOp::Mul, _ => bug!("Already checked for int ops"), }; - if ignore_overflow { - self.binop_ignore_overflow(bin_op, lhs, rhs, dest)?; - } else { - self.binop_with_overflow(bin_op, lhs, rhs, dest)?; - } + self.binop_with_overflow(bin_op, lhs, rhs, dest)?; } sym::saturating_add | sym::saturating_sub => { let l = self.read_immediate(args[0])?; diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 809e29fb982d..7f3b421cf76f 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -364,6 +364,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late, // but before optimizations begin. &add_retag::AddRetag, + &lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops"), // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening // and it can help optimizations. @@ -392,7 +393,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ - &lower_intrinsics::LowerIntrinsics, &remove_unneeded_drops::RemoveUnneededDrops, &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index a21cbfa767ed..7da2ff02006b 100644 --- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -120,5 +120,9 @@ bb5: { return; // scope 0 at $DIR/lower_intrinsics.rs:73:2: 73:2 } + + bb6 (cleanup): { + resume; // scope 0 at $DIR/lower_intrinsics.rs:68:1: 73:2 + } } diff --git a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff index 6b2d3833c2f5..e9cc72f21388 100644 --- a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff @@ -25,7 +25,15 @@ StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:19:40: 19:41 StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:19:43: 19:44 _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:18:24: 20:2 + goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:20:1: 20:2 + } + + bb2: { return; // scope 0 at $DIR/lower_intrinsics.rs:20:2: 20:2 } + + bb3 (cleanup): { + resume; // scope 0 at $DIR/lower_intrinsics.rs:18:1: 20:2 + } } diff --git a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff index e973014c40d1..218b1c964334 100644 --- a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff @@ -27,5 +27,9 @@ StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:59:1: 59:2 return; // scope 0 at $DIR/lower_intrinsics.rs:59:2: 59:2 } + + bb2 (cleanup): { + resume; // scope 0 at $DIR/lower_intrinsics.rs:55:1: 59:2 + } } diff --git a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff index 262385e9f5e2..b5a77702a8ef 100644 --- a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff @@ -16,5 +16,9 @@ bb1: { return; // scope 0 at $DIR/lower_intrinsics.rs:15:2: 15:2 } + + bb2 (cleanup): { + resume; // scope 0 at $DIR/lower_intrinsics.rs:13:1: 15:2 + } } diff --git a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff index b58cb333244f..a04b79d47d4c 100644 --- a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff @@ -18,5 +18,9 @@ - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(Scalar()) } + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:24:14: 24:45 } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/lower_intrinsics.rs:23:1: 25:2 + } } diff --git a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff index ce03ce90e522..badfef30e6fc 100644 --- a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff @@ -79,5 +79,9 @@ StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:10:1: 10:2 return; // scope 0 at $DIR/lower_intrinsics.rs:10:2: 10:2 } + + bb4 (cleanup): { + resume; // scope 0 at $DIR/lower_intrinsics.rs:6:1: 10:2 + } } From 0b18ed833c4406d8fc654b9f4990d2f80dc205c4 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 14 Dec 2020 07:35:03 -0500 Subject: [PATCH 310/719] Disable the constant debuginfo promotion pass by default It doesn't work correctly on *-pc-windows-gnu --- .../rustc_mir/src/transform/const_debuginfo.rs | 6 +++++- src/test/incremental/hashes/let_expressions.rs | 4 ++-- src/test/mir-opt/const_debuginfo.rs | 2 +- ...ariable.main.SimplifyLocals.after.32bit.mir | 18 +++++++++++++++--- ...ariable.main.SimplifyLocals.after.64bit.mir | 18 +++++++++++++++--- ...line_scopes_parenting.main.Inline.after.mir | 6 +++++- ...ower_intrinsics.f_u64.PreCodegen.before.mir | 2 +- ...change_loop_body.PreCodegen.after.32bit.mir | 6 +++++- ...change_loop_body.PreCodegen.after.64bit.mir | 6 +++++- 9 files changed, 54 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir/src/transform/const_debuginfo.rs b/compiler/rustc_mir/src/transform/const_debuginfo.rs index ed2c48b35680..3cdaf4c7dcd4 100644 --- a/compiler/rustc_mir/src/transform/const_debuginfo.rs +++ b/compiler/rustc_mir/src/transform/const_debuginfo.rs @@ -15,7 +15,11 @@ use rustc_index::{bit_set::BitSet, vec::IndexVec}; pub struct ConstDebugInfo; impl<'tcx> MirPass<'tcx> for ConstDebugInfo { - fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + return; + } + trace!("running ConstDebugInfo on {:?}", body.source); for (local, constant) in find_optimization_oportunities(body) { diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 2c37b2e78ffa..918e72582d69 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -86,7 +86,7 @@ pub fn change_mutability_of_slot() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck")] + except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_slot() { let _x: u64 = 0; @@ -166,7 +166,7 @@ pub fn change_mutability_of_binding_in_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck")] + except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_binding_in_pattern() { let (mut _a, _b) = (99u8, 'q'); diff --git a/src/test/mir-opt/const_debuginfo.rs b/src/test/mir-opt/const_debuginfo.rs index a66d66c60c7a..a188da385262 100644 --- a/src/test/mir-opt/const_debuginfo.rs +++ b/src/test/mir-opt/const_debuginfo.rs @@ -1,4 +1,4 @@ -// compile-flags: -C overflow-checks=no +// compile-flags: -C overflow-checks=no -Zunsound-mir-opts struct Point { x: u32, diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir index e4fbba3abfea..a78a6341c299 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir @@ -2,18 +2,30 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 scope 1 { - debug x => const 4_i32; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 2 { - debug y => const 3_i32; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 scope 3 { - debug z => const 42_u32; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } bb0: { + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + _2 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + _3 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 _0 = const (); // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 + StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir index e4fbba3abfea..a78a6341c299 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir @@ -2,18 +2,30 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 scope 1 { - debug x => const 4_i32; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 2 { - debug y => const 3_i32; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 scope 3 { - debug z => const 42_u32; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } bb0: { + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 + _1 = const 4_i32; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 + _2 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + _3 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 _0 = const (); // scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 + StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir index 4abbad2c1efc..3d386e3b1756 100644 --- a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir @@ -11,8 +11,9 @@ fn main() -> () { debug f => _1; // in scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10 scope 2 (inlined main::{closure#0}) { // at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 debug x => _5; // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + let _6: (); // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 scope 3 { - debug y => const (); // in scope 3 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + debug y => _6; // in scope 3 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 } } } @@ -26,7 +27,10 @@ fn main() -> () { (_3.0: ()) = move _4; // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 StorageLive(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 _5 = move (_3.0: ()); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + StorageLive(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + _6 = const (); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 _0 = const (); // scope 3 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 + StorageDead(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 StorageDead(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 StorageDead(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:9: 6:10 StorageDead(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:9: 6:10 diff --git a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir index bd4f148285b1..654dd8275c9d 100644 --- a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir +++ b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir @@ -3,7 +3,7 @@ fn f_u64() -> () { let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:16 scope 1 (inlined f_dispatch::) { // at $DIR/lower_intrinsics.rs:35:5: 35:21 - debug t => const 0_u64; // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 + debug t => _2; // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 let _1: (); // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 let mut _2: u64; // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 scope 2 (inlined std::mem::size_of::) { // at $DIR/lower_intrinsics.rs:35:5: 35:21 diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir index cb3632e0fb13..dae0cbb65a4b 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir +++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir @@ -2,12 +2,16 @@ fn change_loop_body() -> () { let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27 + let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 scope 1 { - debug _x => const 0_i32; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 + debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 } bb0: { + StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 + _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19 _0 = const (); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 + StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 } } diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir index cb3632e0fb13..dae0cbb65a4b 100644 --- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir +++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir @@ -2,12 +2,16 @@ fn change_loop_body() -> () { let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27 + let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 scope 1 { - debug _x => const 0_i32; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 + debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15 } bb0: { + StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15 + _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19 _0 = const (); // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6 + StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2 return; // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2 } } From 36c639a2ce2808c2c95cacf0856026235ad6350f Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 14 Dec 2020 13:12:15 -0800 Subject: [PATCH 311/719] Convenience funcs for `some_option.unwrap_or(...)` This ensures consistent handling of default values for options that are None if not specified on the command line. --- compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 7 +--- .../rustc_mir/src/transform/const_prop.rs | 8 ++--- compiler/rustc_mir/src/transform/dest_prop.rs | 3 +- .../src/transform/early_otherwise_branch.rs | 3 +- compiler/rustc_mir/src/transform/inline.rs | 3 +- .../rustc_mir/src/transform/match_branches.rs | 3 +- compiler/rustc_mir/src/transform/mod.rs | 3 +- .../transform/multiple_return_terminators.rs | 3 +- compiler/rustc_mir/src/transform/nrvo.rs | 3 +- .../src/transform/unreachable_prop.rs | 3 +- compiler/rustc_session/src/config.rs | 33 ++++++++----------- compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_symbol_mangling/src/lib.rs | 6 +--- src/tools/clippy/src/driver.rs | 2 +- 15 files changed, 29 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 7a7def0696db..3e94f1637734 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -561,7 +561,7 @@ fn test_debugging_options_tracking_hash() { tracked!(link_only, true); tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(mir_emit_retag, true); - tracked!(mir_opt_level, Some(3)); + tracked!(mir_opt_level, 3); tracked!(mutable_noalias, true); tracked!(new_llvm_pass_manager, true); tracked!(no_codegen, true); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b0c75c1de9d1..7b67d15f64a2 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -663,12 +663,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins), panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime), profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime), - symbol_mangling_version: tcx - .sess - .opts - .debugging_opts - .symbol_mangling_version - .unwrap_or(SymbolManglingVersion::default()), + symbol_mangling_version: tcx.sess.opts.debugging_opts.get_symbol_mangling_version(), crate_deps, dylib_dependency_formats, diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 49b1cf92600e..1d949e020ed5 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -22,7 +22,6 @@ use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{ self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable, }; -use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use rustc_session::lint; use rustc_span::{def_id::DefId, Span}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout}; @@ -709,7 +708,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } - if self.tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) >= 3 { + if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 3 { self.eval_rvalue_with_identities(rvalue, place) } else { self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place)) @@ -887,8 +886,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Returns `true` if and only if this `op` should be const-propagated into. fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool { - let mir_opt_level = - self.tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT); + let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level; if mir_opt_level == 0 { return false; @@ -1058,7 +1056,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { // Only const prop copies and moves on `mir_opt_level=2` as doing so // currently slightly increases compile time in some cases. - if self.tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) >= 2 { + if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { self.propagate_operand(operand) } } diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 2363b6d58e1d..46de5dba6e0e 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -115,7 +115,6 @@ use rustc_middle::mir::{ Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; // Empirical measurements have resulted in some observations: // - Running on a body with a single block and 500 locals takes barely any time @@ -130,7 +129,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Only run at mir-opt-level=2 or higher for now (we don't fix up debuginfo and remove // storage statements at the moment). - if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) <= 1 { + if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { return; } diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 023561923eeb..f91477911a48 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -1,7 +1,6 @@ use crate::{transform::MirPass, util::patch::MirPatch}; use rustc_middle::mir::*; use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use std::fmt::Debug; use super::simplify::simplify_cfg; @@ -27,7 +26,7 @@ pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) < 2 { + if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } trace!("running EarlyOtherwiseBranch on {:?}", body.source); diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index 1a927f9bf505..6e7575c1d71b 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -9,7 +9,6 @@ use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; -use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use rustc_span::{hygiene::ExpnKind, ExpnData, Span}; use rustc_target::spec::abi::Abi; @@ -38,7 +37,7 @@ struct CallSite<'tcx> { impl<'tcx> MirPass<'tcx> for Inline { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) < 2 { + if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index e28e3f59a5e0..53eeecc780f6 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -1,7 +1,6 @@ use crate::transform::MirPass; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; pub struct MatchBranchSimplification; @@ -39,7 +38,7 @@ pub struct MatchBranchSimplification; impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) <= 1 { + if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { return; } diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 039dfe2c0d50..e86d11e248fc 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -10,7 +10,6 @@ use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; -use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use rustc_span::{Span, Symbol}; use std::borrow::Cow; @@ -374,7 +373,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc } fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let mir_opt_level = tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT); + let mir_opt_level = tcx.sess.opts.debugging_opts.mir_opt_level; // Lowering generator control-flow and variables has to happen before we do anything else // to them. We run some optimizations before that, because they may be harder to do on the state diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs index de4aee7ddbcc..617086622cc1 100644 --- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs +++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs @@ -5,13 +5,12 @@ use crate::transform::{simplify, MirPass}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; pub struct MultipleReturnTerminators; impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) < 3 { + if tcx.sess.opts.debugging_opts.mir_opt_level < 3 { return; } diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs index 6e1dc03b9cb3..ce02fb261df6 100644 --- a/compiler/rustc_mir/src/transform/nrvo.rs +++ b/compiler/rustc_mir/src/transform/nrvo.rs @@ -5,7 +5,6 @@ use rustc_index::bit_set::HybridBitSet; use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, BasicBlock, Local, Location}; use rustc_middle::ty::TyCtxt; -use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; use crate::transform::MirPass; @@ -35,7 +34,7 @@ pub struct RenameReturnPlace; impl<'tcx> MirPass<'tcx> for RenameReturnPlace { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) == 0 { + if tcx.sess.opts.debugging_opts.mir_opt_level == 0 { return; } diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs index c9053ce81cd0..e39c8656021b 100644 --- a/compiler/rustc_mir/src/transform/unreachable_prop.rs +++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs @@ -7,13 +7,12 @@ use crate::transform::MirPass; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use rustc_session::config::MIR_OPT_LEVEL_DEFAULT; pub struct UnreachablePropagation; impl MirPass<'_> for UnreachablePropagation { fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level.unwrap_or(MIR_OPT_LEVEL_DEFAULT) < 3 { + if tcx.sess.opts.debugging_opts.mir_opt_level < 3 { // Enable only under -Zmir-opt-level=3 as in some cases (check the deeply-nested-opt // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code. return; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 47e494b78c7d..b77a8b631e05 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -174,8 +174,6 @@ pub enum MirSpanview { Block, } -pub const MIR_OPT_LEVEL_DEFAULT: usize = 1; - #[derive(Clone, PartialEq, Hash)] pub enum LinkerPluginLto { LinkerPlugin(PathBuf), @@ -214,12 +212,6 @@ pub enum SymbolManglingVersion { V0, } -impl SymbolManglingVersion { - pub fn default() -> Self { - SymbolManglingVersion::Legacy - } -} - impl_stable_hash_via_hash!(SymbolManglingVersion); #[derive(Clone, Copy, Debug, PartialEq, Hash)] @@ -700,6 +692,10 @@ impl DebuggingOptions { deduplicate_diagnostics: self.deduplicate_diagnostics, } } + + pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { + self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) + } } // The type of entry function, so users can have their own entry functions @@ -1779,18 +1775,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { Some(SymbolManglingVersion::V0) => {} } - match debugging_opts.mir_opt_level { - Some(level) if level > 1 => { - early_warn( - error_format, - &format!( - "`-Z mir-opt-level={}` (any level > 1) enables function inlining, which \ - limits the effectiveness of `-Z instrument-coverage`.", - level, - ), - ); - } - _ => {} + if debugging_opts.mir_opt_level > 1 { + early_warn( + error_format, + &format!( + "`-Z mir-opt-level={}` (any level > 1) enables function inlining, which \ + limits the effectiveness of `-Z instrument-coverage`.", + debugging_opts.mir_opt_level, + ), + ); } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1909550aca48..49a7888fd6a4 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -970,7 +970,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, mir_emit_retag: bool = (false, parse_bool, [TRACKED], "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ (default: no)"), - mir_opt_level: Option = (None, parse_opt_uint, [TRACKED], + mir_opt_level: usize = (1, parse_uint, [TRACKED], "MIR optimization level (0-3; default: 1)"), mutable_noalias: bool = (false, parse_bool, [TRACKED], "emit noalias metadata for mutable references (default: no)"), diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 945e788a1460..7f8cded0ac0e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -245,11 +245,7 @@ fn compute_symbol_name( // 2. we favor `instantiating_crate` where possible (i.e. when `Some`) let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate); let mangling_version = if mangling_version_crate == LOCAL_CRATE { - tcx.sess - .opts - .debugging_opts - .symbol_mangling_version - .unwrap_or(SymbolManglingVersion::default()) + tcx.sess.opts.debugging_opts.get_symbol_mangling_version() } else { tcx.symbol_mangling_version(mangling_version_crate) }; diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 9e5ae21f7026..87dd19c5d4d0 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -85,7 +85,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // run on the unoptimized MIR. On the other hand this results in some false negatives. If // MIR passes can be enabled / disabled separately, we should figure out, what passes to // use for Clippy. - config.opts.debugging_opts.mir_opt_level = Some(0); + config.opts.debugging_opts.mir_opt_level = 0; } } From ae288df51fed67c60e4c5d5f1b5aff0bc974e906 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 14 Dec 2020 13:12:15 -0800 Subject: [PATCH 312/719] Convenience funcs for `some_option.unwrap_or(...)` This ensures consistent handling of default values for options that are None if not specified on the command line. --- src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/driver.rs b/src/driver.rs index 9e5ae21f7026..87dd19c5d4d0 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -85,7 +85,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // run on the unoptimized MIR. On the other hand this results in some false negatives. If // MIR passes can be enabled / disabled separately, we should figure out, what passes to // use for Clippy. - config.opts.debugging_opts.mir_opt_level = Some(0); + config.opts.debugging_opts.mir_opt_level = 0; } } From 89fc5034f4f8bca86cbf2c29c8c00366a7b4a33c Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 14 Dec 2020 19:06:41 -0500 Subject: [PATCH 313/719] Remove unnecessary unwrap_or This was always questionable, and removing it doesn't fail any tests, so I think this was not affecting the behavior. It dates all the way back to the very first commit of rustdoc: 268f3f0ff5d80544ca21d565354eae6d3e29fb91 --- src/librustdoc/clean/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1a63a5092ca0..1a004231a100 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -254,7 +254,6 @@ impl Clean for doctree::Module<'_> { cx, ); Item { - name: Some(what_rustc_thinks.name.unwrap_or_default()), attrs, source: span.clean(cx), ..what_rustc_thinks From 7d452430fa9b3f9c7660c90adb2f05e4c4453336 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 14 Dec 2020 18:44:59 -0500 Subject: [PATCH 314/719] Get rid of `clean::Deprecation` This brings the size of `item.deprecation` from 56 to 16 bytes. --- compiler/rustc_attr/src/builtin.rs | 2 +- src/librustdoc/clean/mod.rs | 10 ---------- src/librustdoc/clean/types.rs | 11 ++--------- src/librustdoc/html/render/mod.rs | 19 +++++++++++++------ src/librustdoc/json/conversions.rs | 9 +++++---- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index bb7562bc80c7..ead90f23ce7a 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -621,7 +621,7 @@ pub fn eval_condition( } } -#[derive(Encodable, Decodable, Clone, HashStable_Generic)] +#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic)] pub struct Deprecation { pub since: Option, /// The note to issue a reason. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1a63a5092ca0..d62bd44dcf1d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2342,16 +2342,6 @@ impl Clean for (&hir::MacroDef<'_>, Option) { } } -impl Clean for attr::Deprecation { - fn clean(&self, _: &DocContext<'_>) -> Deprecation { - Deprecation { - since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()), - note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()), - is_since_rustc_version: self.is_since_rustc_version, - } - } -} - impl Clean for hir::TypeBinding<'_> { fn clean(&self, cx: &DocContext<'_>) -> TypeBinding { TypeBinding { name: self.ident.name.clean(cx), kind: self.kind.clean(cx) } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0228d63ac00e..26b630440a19 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -12,7 +12,7 @@ use rustc_ast::attr; use rustc_ast::util::comments::beautify_doc_string; use rustc_ast::{self as ast, AttrStyle}; use rustc_ast::{FloatTy, IntTy, UintTy}; -use rustc_attr::{ConstStability, Stability, StabilityLevel}; +use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_feature::UnstableFeatures; use rustc_hir as hir; @@ -156,7 +156,7 @@ impl Item { attrs: cx.tcx.get_attrs(def_id).clean(cx), visibility: cx.tcx.visibility(def_id).clean(cx), stability: cx.tcx.lookup_stability(def_id).cloned(), - deprecation: cx.tcx.lookup_deprecation(def_id).clean(cx), + deprecation: cx.tcx.lookup_deprecation(def_id), const_stability: cx.tcx.lookup_const_stability(def_id).cloned(), } } @@ -1793,13 +1793,6 @@ crate struct ProcMacro { crate helpers: Vec, } -#[derive(Clone, Debug)] -crate struct Deprecation { - crate since: Option, - crate note: Option, - crate is_since_rustc_version: bool, -} - /// An type binding on an associated type (e.g., `A = Bar` in `Foo` or /// `A: Send + Sync` in `Foo`). #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index db04624dca84..5a120172c946 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -49,7 +49,7 @@ use std::sync::Arc; use itertools::Itertools; use rustc_ast_pretty::pprust; -use rustc_attr::StabilityLevel; +use rustc_attr::{Deprecation, StabilityLevel}; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; @@ -65,7 +65,7 @@ use rustc_span::symbol::{sym, Symbol}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; -use crate::clean::{self, AttributesExt, Deprecation, GetDefId, RenderedLink, SelfTy, TypeKind}; +use crate::clean::{self, AttributesExt, GetDefId, RenderedLink, SelfTy, TypeKind}; use crate::config::{RenderInfo, RenderOptions}; use crate::docfs::{DocFS, PathError}; use crate::doctree; @@ -2219,7 +2219,10 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item) -> String { // The trailing space after each tag is to space it properly against the rest of the docs. if let Some(depr) = &item.deprecation { let mut message = "Deprecated"; - if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) { + if !stability::deprecation_in_effect( + depr.is_since_rustc_version, + depr.since.map(|s| s.as_str()).as_deref(), + ) { message = "Deprecation planned"; } tags += &tag_html("deprecated", "", message); @@ -2268,20 +2271,24 @@ fn short_item_info(item: &clean::Item, cx: &Context, parent: Option<&clean::Item let mut extra_info = vec![]; let error_codes = cx.shared.codes; - if let Some(Deprecation { ref note, ref since, is_since_rustc_version }) = item.deprecation { + if let Some(Deprecation { note, since, is_since_rustc_version, suggestion: _ }) = + item.deprecation + { // We display deprecation messages for #[deprecated] and #[rustc_deprecated] // but only display the future-deprecation messages for #[rustc_deprecated]. let mut message = if let Some(since) = since { + let since = &since.as_str(); if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) { - format!("Deprecating in {}", Escape(&since)) + format!("Deprecating in {}", Escape(since)) } else { - format!("Deprecated since {}", Escape(&since)) + format!("Deprecated since {}", Escape(since)) } } else { String::from("Deprecated") }; if let Some(note) = note { + let note = note.as_str(); let mut ids = cx.id_map.borrow_mut(); let html = MarkdownHtml( ¬e, diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index c463481db86d..2da38be6ebe4 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -77,10 +77,11 @@ impl JsonRenderer { } } -impl From for Deprecation { - fn from(deprecation: clean::Deprecation) -> Self { - let clean::Deprecation { since, note, is_since_rustc_version: _ } = deprecation; - Deprecation { since, note } +impl From for Deprecation { + fn from(deprecation: rustc_attr::Deprecation) -> Self { + #[rustfmt::skip] + let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation; + Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) } } } From a16904fecf0ad1c46f9c11c6b193bdbb6421bf17 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 14 Dec 2020 19:30:36 -0500 Subject: [PATCH 315/719] Switch to Symbol for item.name This decreases the size of `Item` from 680 to 616 bytes. It also does a lot less work since it no longer has to copy as much. --- compiler/rustc_span/src/symbol.rs | 4 ++ src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 22 ++++----- src/librustdoc/clean/types.rs | 48 +++++++++++++++---- src/librustdoc/clean/utils.rs | 2 +- src/librustdoc/formats/renderer.rs | 3 +- src/librustdoc/html/render/cache.rs | 2 +- src/librustdoc/html/render/mod.rs | 27 +++++------ src/librustdoc/json/conversions.rs | 2 +- .../passes/collect_intra_doc_links.rs | 11 ++++- 10 files changed, 78 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b60d466c3a79..f61a32a0f790 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1469,6 +1469,10 @@ impl Symbol { self.0.as_u32() } + pub fn is_empty(self) -> bool { + self == kw::Invalid + } + /// This method is supposed to be used in error messages, so it's expected to be /// identical to printing the original identifier token written in source code /// (`token_to_string`, `Ident::to_string`), except that symbols don't keep the rawness flag diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f7b6553a9359..d358a7a369d8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -124,7 +124,7 @@ crate fn try_inline( let attrs = merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone); cx.renderinfo.borrow_mut().inlined.insert(did); - let what_rustc_thinks = clean::Item::from_def_id_and_parts(did, Some(name.clean(cx)), kind, cx); + let what_rustc_thinks = clean::Item::from_def_id_and_parts(did, Some(name), kind, cx); ret.push(clean::Item { attrs, ..what_rustc_thinks }); Some(ret) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1a004231a100..2d2465e56f37 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -169,7 +169,7 @@ impl Clean for CrateNum { for attr in attrs.lists(sym::doc) { if attr.has_name(sym::keyword) { if let Some(v) = attr.value_str() { - keyword = Some(v.to_string()); + keyword = Some(v); break; } } @@ -253,11 +253,7 @@ impl Clean for doctree::Module<'_> { ModuleItem(Module { is_crate: self.is_crate, items }), cx, ); - Item { - attrs, - source: span.clean(cx), - ..what_rustc_thinks - } + Item { attrs, source: span.clean(cx), ..what_rustc_thinks } } } @@ -1095,7 +1091,7 @@ impl Clean for hir::TraitItem<'_> { AssocTypeItem(bounds.clean(cx), default.clean(cx)) } }; - Item::from_def_id_and_parts(local_did, Some(self.ident.name.clean(cx)), inner, cx) + Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx) }) } } @@ -1123,7 +1119,7 @@ impl Clean for hir::ImplItem<'_> { TypedefItem(Typedef { type_, generics: Generics::default(), item_type }, true) } }; - Item::from_def_id_and_parts(local_did, Some(self.ident.name.clean(cx)), inner, cx) + Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx) }) } } @@ -1280,7 +1276,7 @@ impl Clean for ty::AssocItem { } }; - Item::from_def_id_and_parts(self.def_id, Some(self.ident.name.clean(cx)), kind, cx) + Item::from_def_id_and_parts(self.def_id, Some(self.ident.name), kind, cx) } } @@ -1770,7 +1766,7 @@ impl Clean for ty::FieldDef { fn clean(&self, cx: &DocContext<'_>) -> Item { let what_rustc_thinks = Item::from_def_id_and_parts( self.did, - Some(self.ident.name.clean(cx)), + Some(self.ident.name), StructFieldItem(cx.tcx.type_of(self.did).clean(cx)), cx, ); @@ -1846,7 +1842,7 @@ impl Clean for ty::VariantDef { .fields .iter() .map(|field| { - let name = Some(field.ident.name.clean(cx)); + let name = Some(field.ident.name); let kind = StructFieldItem(cx.tcx.type_of(field.did).clean(cx)); let what_rustc_thinks = Item::from_def_id_and_parts(field.did, name, kind, cx); @@ -1858,7 +1854,7 @@ impl Clean for ty::VariantDef { }; let what_rustc_thinks = Item::from_def_id_and_parts( self.def_id, - Some(self.ident.name.clean(cx)), + Some(self.ident.name), VariantItem(Variant { kind }), cx, ); @@ -2032,7 +2028,7 @@ impl Clean> for (&hir::Item<'_>, Option) { _ => unreachable!("not yet converted"), }; - vec![Item::from_def_id_and_parts(def_id, Some(name.clean(cx)), kind, cx)] + vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)] }) } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0228d63ac00e..2c353a1e0819 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -70,7 +70,7 @@ crate struct ExternalCrate { crate src: FileName, crate attrs: Attributes, crate primitives: Vec<(DefId, PrimitiveType)>, - crate keywords: Vec<(DefId, String)>, + crate keywords: Vec<(DefId, Symbol)>, } /// Anything with a source location and set of attributes and, optionally, a @@ -81,7 +81,7 @@ crate struct Item { /// Stringified span crate source: Span, /// Not everything has a name. E.g., impls - crate name: Option, + crate name: Option, crate attrs: Attributes, crate visibility: Visibility, crate kind: ItemKind, @@ -123,17 +123,12 @@ impl Item { kind: ItemKind, cx: &DocContext<'_>, ) -> Item { - Item::from_def_id_and_parts( - cx.tcx.hir().local_def_id(hir_id).to_def_id(), - name.clean(cx), - kind, - cx, - ) + Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx) } pub fn from_def_id_and_parts( def_id: DefId, - name: Option, + name: Option, kind: ItemKind, cx: &DocContext<'_>, ) -> Item { @@ -334,7 +329,7 @@ crate enum ItemKind { AssocTypeItem(Vec, Option), /// An item that has been stripped by a rustdoc pass StrippedItem(Box), - KeywordItem(String), + KeywordItem(Symbol), } impl ItemKind { @@ -1163,6 +1158,8 @@ crate enum Type { } #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] +/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't +/// paths, like `Unit`. crate enum PrimitiveType { Isize, I8, @@ -1502,6 +1499,37 @@ impl PrimitiveType { crate fn to_url_str(&self) -> &'static str { self.as_str() } + + crate fn as_sym(&self) -> Symbol { + use PrimitiveType::*; + match self { + Isize => sym::isize, + I8 => sym::i8, + I16 => sym::i16, + I32 => sym::i32, + I64 => sym::i64, + I128 => sym::i128, + Usize => sym::usize, + U8 => sym::u8, + U16 => sym::u16, + U32 => sym::u32, + U64 => sym::u64, + U128 => sym::u128, + F32 => sym::f32, + F64 => sym::f64, + Str => sym::str, + Bool => sym::bool, + Char => sym::char, + Array => sym::array, + Slice => sym::slice, + Tuple => sym::tuple, + Unit => sym::unit, + RawPointer => sym::pointer, + Reference => sym::reference, + Fn => kw::Fn, + Never => sym::never, + } + } } impl From for PrimitiveType { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 1b22d26f49bd..f8743a4c42e9 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -68,7 +68,7 @@ crate fn krate(mut cx: &mut DocContext<'_>) -> Crate { m.items.extend(primitives.iter().map(|&(def_id, prim)| { Item::from_def_id_and_parts( def_id, - Some(prim.to_url_str().to_owned()), + Some(prim.as_sym()), ItemKind::PrimitiveItem(prim), cx, ) diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index 6334524eb1ca..c332da4db4ee 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use rustc_data_structures::sync::Lrc; use rustc_session::Session; use rustc_span::edition::Edition; +use rustc_span::Symbol; use crate::clean; use crate::config::{RenderInfo, RenderOptions}; @@ -75,7 +76,7 @@ crate fn run_format( None => return Ok(()), }; - item.name = Some(krate.name.clone()); + item.name = Some(Symbol::intern(&krate.name)); // Render the crate documentation let mut work = vec![(format_renderer.clone(), item)]; diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 97f764517faf..91037bc160ab 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -76,7 +76,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { if let Some(&(ref fqp, _)) = paths.get(&did) { search_index.push(IndexItem { ty: item.type_(), - name: item.name.clone().unwrap(), + name: item.name.unwrap().to_string(), path: fqp[..fqp.len() - 1].join("::"), desc: item.doc_value().map_or_else(|| String::new(), short_markdown_summary), parent: Some(did), diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index db04624dca84..00f3723ce239 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -61,7 +61,7 @@ use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::FileName; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; @@ -665,7 +665,7 @@ impl FormatRenderer for Context { if !buf.is_empty() { let name = item.name.as_ref().unwrap(); let item_type = item.type_(); - let file_name = &item_path(item_type, name); + let file_name = &item_path(item_type, &name.as_str()); self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join(file_name); self.shared.fs.write(&joint_dst, buf.as_bytes())?; @@ -1543,7 +1543,7 @@ impl Context { if !title.is_empty() { title.push_str("::"); } - title.push_str(it.name.as_ref().unwrap()); + title.push_str(&it.name.unwrap().as_str()); } title.push_str(" - Rust"); let tyname = it.type_(); @@ -1815,7 +1815,7 @@ fn item_path(ty: ItemType, name: &str) -> String { fn full_path(cx: &Context, item: &clean::Item) -> String { let mut s = cx.current.join("::"); s.push_str("::"); - s.push_str(item.name.as_ref().unwrap()); + s.push_str(&item.name.unwrap().as_str()); s } @@ -2065,9 +2065,9 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: (true, false) => return Ordering::Greater, } } - let lhs = i1.name.as_ref().map_or("", |s| &**s); - let rhs = i2.name.as_ref().map_or("", |s| &**s); - compare_names(lhs, rhs) + let lhs = i1.name.unwrap_or(kw::Invalid).as_str(); + let rhs = i2.name.unwrap_or(kw::Invalid).as_str(); + compare_names(&lhs, &rhs) } if cx.shared.sort_modules_alphabetically { @@ -2191,7 +2191,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: add = add, stab = stab.unwrap_or_else(String::new), unsafety_flag = unsafety_flag, - href = item_path(myitem.type_(), myitem.name.as_ref().unwrap()), + href = item_path(myitem.type_(), &myitem.name.unwrap().as_str()), title = [full_path(cx, myitem), myitem.type_().to_string()] .iter() .filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None }) @@ -2623,7 +2623,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item, cache: &Cache) { let name = m.name.as_ref().unwrap(); - info!("Documenting {} on {}", name, t.name.as_deref().unwrap_or_default()); + info!("Documenting {} on {:?}", name, t.name); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); write!(w, "

", id = id,); @@ -2951,7 +2951,7 @@ fn render_assoc_item( AssocItemLink::GotoSource(did, provided_methods) => { // We're creating a link from an impl-item to the corresponding // trait-item and need to map the anchored type accordingly. - let ty = if provided_methods.contains(name) { + let ty = if provided_methods.contains(&*name.as_str()) { ItemType::Method } else { ItemType::TyMethod @@ -3434,10 +3434,7 @@ fn render_assoc_items( what: AssocItemRender<'_>, cache: &Cache, ) { - info!( - "Documenting associated items of {}", - containing_item.name.as_deref().unwrap_or_default() - ); + info!("Documenting associated items of {:?}", containing_item.name); let v = match cache.impls.get(&it) { Some(v) => v, None => return, @@ -4139,7 +4136,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca ty: \"{ty}\", \ relpath: \"{path}\"\ }};", - name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), + name = it.name.unwrap_or(kw::Invalid), ty = it.type_(), path = relpath ); diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index c463481db86d..49de4c6d2e75 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -33,7 +33,7 @@ impl JsonRenderer { _ => Some(Item { id: def_id.into(), crate_id: def_id.krate.as_u32(), - name, + name: name.map(|sym| sym.to_string()), source: self.convert_span(source), visibility: visibility.into(), docs: attrs.collapsed_doc_value().unwrap_or_default(), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7358eae6edc9..3ec2d4b7c51b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -668,7 +668,7 @@ fn resolve_associated_trait_item( // Give precedence to methods that were overridden if !impl_.provided_trait_methods.contains(&*item_name.as_str()) { let mut items = impl_.items.into_iter().filter_map(|assoc| { - if assoc.name.as_deref() != Some(&*item_name.as_str()) { + if assoc.name != Some(item_name) { return None; } let kind = assoc @@ -1942,7 +1942,14 @@ fn privacy_error( dox: &str, link_range: Option>, ) { - let item_name = item.name.as_deref().unwrap_or(""); + let sym; + let item_name = match item.name { + Some(name) => { + sym = name.as_str(); + &*sym + } + None => "", + }; let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); From 4652a13f44b89193dc163991485b7638fa0f9ea7 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Mon, 30 Nov 2020 22:24:04 -0800 Subject: [PATCH 316/719] write_slice(_cloned) --- library/core/src/mem/maybe_uninit.rs | 150 +++++++++++++++++++++++++++ library/core/tests/lib.rs | 2 + library/core/tests/mem.rs | 124 ++++++++++++++++++++++ 3 files changed, 276 insertions(+) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 8800d7714cf4..57e0bb1499bd 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -860,4 +860,154 @@ impl MaybeUninit { pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } + + /// Copies the elements from `src` to `this`, returning a mutable reference to the now initalized contents of `this`. + /// + /// If `T` does not implement `Copy`, use [`write_slice_cloned`] + /// + /// This is similar to [`slice::copy_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// use std::mem::MaybeUninit; + /// + /// let mut dst = [MaybeUninit::uninit(); 32]; + /// let src = [0; 32]; + /// + /// let init = MaybeUninit::write_slice(&mut dst, &src); + /// + /// assert_eq!(init, src); + /// ``` + /// + /// ``` + /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)] + /// use std::mem::MaybeUninit; + /// + /// let mut vec = Vec::with_capacity(32); + /// let src = [0; 16]; + /// + /// MaybeUninit::write_slice(&mut vec.spare_capacity_mut()[..src.len()], &src); + /// + /// // SAFETY: we have just copied all the elements of len into the spare capacity + /// // the first src.len() elements of the vec are valid now. + /// unsafe { + /// vec.set_len(src.len()); + /// } + /// + /// assert_eq!(vec, src); + /// ``` + /// + /// [`write_slice_cloned`]: MaybeUninit::write_slice_cloned + /// [`slice::copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice + #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + pub fn write_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] + where + T: Copy, + { + // SAFETY: &[T] and &[MaybeUninit] have the same layout + let uninit_src: &[MaybeUninit] = unsafe { super::transmute(src) }; + + this.copy_from_slice(uninit_src); + + // SAFETY: Valid elements have just been copied into `this` so it is initalized + unsafe { MaybeUninit::slice_assume_init_mut(this) } + } + + /// Clones the elements from `src` to `this`, returning a mutable reference to the now initalized contents of `this`. + /// Any already initalized elements will not be dropped. + /// + /// If `T` implements `Copy`, use [`write_slice`] + /// + /// This is similar to [`slice::clone_from_slice`] but does not drop existing elements. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths, or if the implementation of `Clone` panics. + /// + /// If there is a panic, the already cloned elements will be dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// use std::mem::MaybeUninit; + /// + /// let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + /// let src = ["wibbly".to_string(), "wobbly".to_string(), "timey".to_string(), "wimey".to_string(), "stuff".to_string()]; + /// + /// let init = MaybeUninit::write_slice_cloned(&mut dst, &src); + /// + /// assert_eq!(init, src); + /// ``` + /// + /// ``` + /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)] + /// use std::mem::MaybeUninit; + /// + /// let mut vec = Vec::with_capacity(32); + /// let src = ["rust", "is", "a", "pretty", "cool", "language"]; + /// + /// MaybeUninit::write_slice_cloned(&mut vec.spare_capacity_mut()[..src.len()], &src); + /// + /// // SAFETY: we have just cloned all the elements of len into the spare capacity + /// // the first src.len() elements of the vec are valid now. + /// unsafe { + /// vec.set_len(src.len()); + /// } + /// + /// assert_eq!(vec, src); + /// ``` + /// + /// [`write_slice`]: MaybeUninit::write_slice + /// [`slice::clone_from_slice`]: ../../std/primitive.slice.html#method.clone_from_slice + #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + pub fn write_slice_cloned<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] + where + T: Clone, + { + // unlike copy_from_slice this does not call clone_from_slice on the slice + // this is because `MaybeUninit` does not implement Clone. + + struct Guard<'a, T> { + slice: &'a mut [MaybeUninit], + initialized: usize, + } + + impl<'a, T> Drop for Guard<'a, T> { + fn drop(&mut self) { + let initialized_part = &mut self.slice[..self.initialized]; + // SAFETY: this raw slice will contain only initialized objects + // that's why, it is allowed to drop it. + unsafe { + crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part)); + } + } + } + + assert_eq!(this.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 = this.len(); + let src = &src[..len]; + + // guard is needed b/c panic might happen during a clone + let mut guard = Guard { slice: this, initialized: 0 }; + + for i in 0..len { + guard.slice[i].write(src[i].clone()); + guard.initialized += 1; + } + + super::forget(guard); + + // SAFETY: Valid elements have just been written into `this` so it is initalized + unsafe { MaybeUninit::slice_assume_init_mut(this) } + } } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 2aa3598a0d94..2828235c3e38 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -8,6 +8,7 @@ #![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] +#![feature(cfg_panic)] #![feature(cfg_target_has_atomic)] #![feature(const_assume)] #![feature(const_cell_into_inner)] @@ -33,6 +34,7 @@ #![feature(raw)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] +#![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(step_trait)] #![feature(step_trait_ext)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 268c2ed283f6..5e24fa690ef5 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -1,5 +1,7 @@ use core::mem::*; +use std::rc::Rc; + #[test] fn size_of_basic() { assert_eq!(size_of::(), 1); @@ -137,3 +139,125 @@ fn assume_init_good() { assert!(TRUE); } + +#[test] +fn uninit_write_slice() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 64]; + + assert_eq!(MaybeUninit::write_slice(&mut dst, &src), &src); +} + +#[test] +#[should_panic(expected = "source slice length (32) does not match destination slice length (64)")] +fn uninit_write_slice_panic_lt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 32]; + + MaybeUninit::write_slice(&mut dst, &src); +} + +#[test] +#[should_panic(expected = "source slice length (128) does not match destination slice length (64)")] +fn uninit_write_slice_panic_gt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 128]; + + MaybeUninit::write_slice(&mut dst, &src); +} + +#[test] +fn uninit_clone_from_slice() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 64]; + + assert_eq!(MaybeUninit::write_slice_cloned(&mut dst, &src), &src); +} + +#[test] +#[should_panic(expected = "destination and source slices have different lengths")] +fn uninit_write_slice_cloned_panic_lt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 32]; + + MaybeUninit::write_slice_cloned(&mut dst, &src); +} + +#[test] +#[should_panic(expected = "destination and source slices have different lengths")] +fn uninit_write_slice_cloned_panic_gt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 128]; + + MaybeUninit::write_slice_cloned(&mut dst, &src); +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_write_slice_cloned_mid_panic() { + use std::panic; + + enum IncrementOrPanic { + Increment(Rc<()>), + ExpectedPanic, + UnexpectedPanic, + } + + impl Clone for IncrementOrPanic { + fn clone(&self) -> Self { + match self { + Self::Increment(rc) => Self::Increment(rc.clone()), + Self::ExpectedPanic => panic!("expected panic on clone"), + Self::UnexpectedPanic => panic!("unexpected panic on clone"), + } + } + } + + let rc = Rc::new(()); + + let mut dst = [ + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + ]; + + let src = [ + IncrementOrPanic::Increment(rc.clone()), + IncrementOrPanic::Increment(rc.clone()), + IncrementOrPanic::ExpectedPanic, + IncrementOrPanic::UnexpectedPanic, + ]; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::write_slice_cloned(&mut dst, &src); + })); + + drop(src); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +fn uninit_write_slice_cloned_no_drop() { + let rc = Rc::new(()); + + let mut dst = [MaybeUninit::uninit()]; + let src = [rc.clone()]; + + MaybeUninit::write_slice_cloned(&mut dst, &src); + + drop(src); + + assert_eq!(Rc::strong_count(&rc), 2); +} From 39bcf8e55438016fb86427f9b8a78b6a32a84126 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Tue, 15 Dec 2020 23:18:03 +0100 Subject: [PATCH 317/719] Handle fatal errors when parsing doctests --- clippy_lints/src/doc.rs | 112 ++++++++++++++++++---------------- clippy_lints/src/lib.rs | 1 + tests/ui/needless_doc_main.rs | 6 ++ 3 files changed, 66 insertions(+), 53 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 55e4755c278a..77203a286dd0 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -451,66 +451,72 @@ fn check_doc<'a, Events: Iterator, Range, text: &str, span: Span) { - fn has_needless_main(code: &str) -> bool { - let filename = FileName::anon_source_code(code); + fn has_needless_main(cx: &LateContext<'_>, code: &str) -> bool { + rustc_driver::catch_fatal_errors(|| { + rustc_span::with_session_globals(cx.tcx.sess.edition(), || { + let filename = FileName::anon_source_code(code); - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false); - let handler = Handler::with_emitter(false, None, box emitter); - let sess = ParseSess::with_span_handler(handler, sm); + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false); + let handler = Handler::with_emitter(false, None, box emitter); + let sess = ParseSess::with_span_handler(handler, sm); - let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code.into()) { - Ok(p) => p, - Err(errs) => { - for mut err in errs { - err.cancel(); - } - return false; - }, - }; - - let mut relevant_main_found = false; - loop { - match parser.parse_item() { - Ok(Some(item)) => match &item.kind { - // Tests with one of these items are ignored - ItemKind::Static(..) - | ItemKind::Const(..) - | ItemKind::ExternCrate(..) - | ItemKind::ForeignMod(..) => return false, - // We found a main function ... - ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym::main => { - let is_async = matches!(sig.header.asyncness, Async::Yes { .. }); - let returns_nothing = match &sig.decl.output { - FnRetTy::Default(..) => true, - FnRetTy::Ty(ty) if ty.kind.is_unit() => true, - _ => false, - }; - - if returns_nothing && !is_async && !block.stmts.is_empty() { - // This main function should be linted, but only if there are no other functions - relevant_main_found = true; - } else { - // This main function should not be linted, we're done - return false; + let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code.into()) { + Ok(p) => p, + Err(errs) => { + for mut err in errs { + err.cancel(); } + return false; }, - // Another function was found; this case is ignored too - ItemKind::Fn(..) => return false, - _ => {}, - }, - Ok(None) => break, - Err(mut e) => { - e.cancel(); - return false; - }, - } - } + }; - relevant_main_found + let mut relevant_main_found = false; + loop { + match parser.parse_item() { + Ok(Some(item)) => match &item.kind { + // Tests with one of these items are ignored + ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::ExternCrate(..) + | ItemKind::ForeignMod(..) => return false, + // We found a main function ... + ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym::main => { + let is_async = matches!(sig.header.asyncness, Async::Yes { .. }); + let returns_nothing = match &sig.decl.output { + FnRetTy::Default(..) => true, + FnRetTy::Ty(ty) if ty.kind.is_unit() => true, + _ => false, + }; + + if returns_nothing && !is_async && !block.stmts.is_empty() { + // This main function should be linted, but only if there are no other functions + relevant_main_found = true; + } else { + // This main function should not be linted, we're done + return false; + } + }, + // Another function was found; this case is ignored too + ItemKind::Fn(..) => return false, + _ => {}, + }, + Ok(None) => break, + Err(mut e) => { + e.cancel(); + return false; + }, + } + } + + relevant_main_found + }) + }) + .ok() + .unwrap_or_default() } - if has_needless_main(text) { + if has_needless_main(cx, text) { span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f06926fa91d3..651b9e711318 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -27,6 +27,7 @@ extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; extern crate rustc_data_structures; +extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_hir_pretty; diff --git a/tests/ui/needless_doc_main.rs b/tests/ui/needless_doc_main.rs index 883683e08a2a..52c84089fa8e 100644 --- a/tests/ui/needless_doc_main.rs +++ b/tests/ui/needless_doc_main.rs @@ -128,6 +128,12 @@ fn bad_doctests() {} /// ``` fn no_false_positives() {} +/// Yields a parse error when interpreted as rust code: +/// ``` +/// r#"hi" +/// ``` +fn issue_6022() {} + fn main() { bad_doctests(); no_false_positives(); From 6580f11a5239296d55c717fbe54fa2f71b861469 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 3 Dec 2020 20:14:11 -0500 Subject: [PATCH 318/719] Don't look for blanket impls in intra-doc links This never worked and has been causing severe performance problems. Hopefully it will be re-landed at some point in the future when it actually works, but in the meantime it makes no sense to have the code around when it does nothing and actively makes rustdoc harder to use. --- src/librustdoc/clean/types.rs | 11 +-- .../passes/collect_intra_doc_links.rs | 83 ++++--------------- 2 files changed, 15 insertions(+), 79 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2c353a1e0819..699dbda32162 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -21,7 +21,7 @@ use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::Mutability; use rustc_index::vec::IndexVec; -use rustc_middle::ty::{AssocKind, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DUMMY_SP; @@ -375,15 +375,6 @@ impl ItemKind { _ => false, } } - - crate fn as_assoc_kind(&self) -> Option { - match *self { - ItemKind::AssocConstItem(..) => Some(AssocKind::Const), - ItemKind::AssocTypeItem(..) => Some(AssocKind::Type), - ItemKind::TyMethodItem(..) | ItemKind::MethodItem(..) => Some(AssocKind::Fn), - _ => None, - } - } } #[derive(Clone, Debug)] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index dc6f8ed6cbbc..f9d81fb86353 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -31,7 +31,7 @@ use std::cell::Cell; use std::mem; use std::ops::Range; -use crate::clean::{self, Crate, GetDefId, Item, ItemLink, PrimitiveType}; +use crate::clean::{self, Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::markdown_links; @@ -685,78 +685,23 @@ fn resolve_associated_trait_item( ns: Namespace, cx: &DocContext<'_>, ) -> Option<(ty::AssocKind, DefId)> { - let ty = cx.tcx.type_of(did); - // First consider blanket impls: `impl From for T` - let implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did); - let mut candidates: Vec<_> = implicit_impls - .flat_map(|impl_outer| { - match impl_outer.kind { - clean::ImplItem(impl_) => { - debug!("considering auto or blanket impl for trait {:?}", impl_.trait_); - // Give precedence to methods that were overridden - if !impl_.provided_trait_methods.contains(&*item_name.as_str()) { - let mut items = impl_.items.into_iter().filter_map(|assoc| { - if assoc.name != Some(item_name) { - return None; - } - let kind = assoc - .kind - .as_assoc_kind() - .expect("inner items for a trait should be associated items"); - if kind.namespace() != ns { - return None; - } - - trace!("considering associated item {:?}", assoc.kind); - // We have a slight issue: normal methods come from `clean` types, - // but provided methods come directly from `tcx`. - // Fortunately, we don't need the whole method, we just need to know - // what kind of associated item it is. - Some((kind, assoc.def_id)) - }); - let assoc = items.next(); - debug_assert_eq!(items.count(), 0); - assoc - } else { - // These are provided methods or default types: - // ``` - // trait T { - // type A = usize; - // fn has_default() -> A { 0 } - // } - // ``` - let trait_ = impl_.trait_.unwrap().def_id().unwrap(); - cx.tcx - .associated_items(trait_) - .find_by_name_and_namespace( - cx.tcx, - Ident::with_dummy_span(item_name), - ns, - trait_, - ) - .map(|assoc| (assoc.kind, assoc.def_id)) - } - } - _ => panic!("get_impls returned something that wasn't an impl"), - } - }) - .collect(); + // FIXME: this should also consider blanket impls (`impl X for T`). Unfortunately + // `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the + // meantime, just don't look for these blanket impls. // Next consider explicit impls: `impl MyTrait for MyType` // Give precedence to inherent impls. - if candidates.is_empty() { - let traits = traits_implemented_by(cx, did, module); - debug!("considering traits {:?}", traits); - candidates.extend(traits.iter().filter_map(|&trait_| { - cx.tcx - .associated_items(trait_) - .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_) - .map(|assoc| (assoc.kind, assoc.def_id)) - })); - } + let traits = traits_implemented_by(cx, did, module); + debug!("considering traits {:?}", traits); + let mut candidates = traits.iter().filter_map(|&trait_| { + cx.tcx + .associated_items(trait_) + .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_) + .map(|assoc| (assoc.kind, assoc.def_id)) + }); // FIXME(#74563): warn about ambiguity - debug!("the candidates were {:?}", candidates); - candidates.pop() + debug!("the candidates were {:?}", candidates.clone().collect::>()); + candidates.next() } /// Given a type, return all traits in scope in `module` implemented by that type. From 41b5ebebfdc583d9e3702dd61c8d897999d1e7f5 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Wed, 16 Dec 2020 00:14:47 +0100 Subject: [PATCH 319/719] needless_doctest_main: add edition support --- clippy_lints/src/doc.rs | 26 ++++++++++++++++++-------- tests/ui/needless_doc_main.rs | 4 ++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 77203a286dd0..08134cc16c00 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -14,6 +14,7 @@ use rustc_middle::ty; use rustc_parse::maybe_new_parser_from_source_str; use rustc_session::parse::ParseSess; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::edition::Edition; use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span}; use rustc_span::{sym, FileName, Pos}; use std::io; @@ -377,7 +378,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs check_doc(cx, valid_idents, events, &spans) } -const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail", "edition2018"]; +const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"]; fn check_doc<'a, Events: Iterator, Range)>>( cx: &LateContext<'_>, @@ -400,13 +401,21 @@ fn check_doc<'a, Events: Iterator, Range { in_code = true; if let CodeBlockKind::Fenced(lang) = kind { - is_rust = - lang.is_empty() || !lang.contains("ignore") && lang.split(',').any(|i| RUST_CODE.contains(&i)); + let infos = lang.split(',').collect::>(); + is_rust = !infos.iter().any(|&i| i == "ignore") + && infos + .iter() + .any(|i| i.is_empty() || i.starts_with("edition") || RUST_CODE.contains(&i)); + edition = infos + .iter() + .find_map(|i| i.starts_with("edition").then(|| i[7..].parse::().ok())) + .flatten(); } }, End(CodeBlock(_)) => { @@ -436,7 +445,8 @@ fn check_doc<'a, Events: Iterator, Range, Range, text: &str, span: Span) { - fn has_needless_main(cx: &LateContext<'_>, code: &str) -> bool { +fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { + fn has_needless_main(code: &str, edition: Edition) -> bool { rustc_driver::catch_fatal_errors(|| { - rustc_span::with_session_globals(cx.tcx.sess.edition(), || { + rustc_span::with_session_globals(edition, || { let filename = FileName::anon_source_code(code); let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); @@ -516,7 +526,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, span: Span) { .unwrap_or_default() } - if has_needless_main(cx, text) { + if has_needless_main(text, edition) { span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); } } diff --git a/tests/ui/needless_doc_main.rs b/tests/ui/needless_doc_main.rs index 52c84089fa8e..83e9bbaa3af4 100644 --- a/tests/ui/needless_doc_main.rs +++ b/tests/ui/needless_doc_main.rs @@ -10,7 +10,7 @@ /// ``` /// /// With an explicit return type it should lint too -/// ``` +/// ```edition2015 /// fn main() -> () { /// unimplemented!(); /// } @@ -39,7 +39,7 @@ fn bad_doctests() {} /// ``` /// /// This shouldn't lint either, because main is async: -/// ``` +/// ```edition2018 /// async fn main() { /// assert_eq!(42, ANSWER); /// } From 8fb553c7daf3b82721f53336c607c16559cf1570 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 15 Dec 2020 20:22:12 -0500 Subject: [PATCH 320/719] Add `&mut` as an alias for 'reference' primitive --- library/std/src/primitive_docs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 55171ef2292d..25736cc3b50e 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -920,6 +920,7 @@ mod prim_usize {} #[doc(primitive = "reference")] #[doc(alias = "&")] +#[doc(alias = "&mut")] // /// References, both shared and mutable. /// From 5afb95a6ca94071a67fb4ab74a1636ea7dfaaa5d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 15 Dec 2020 20:47:06 -0500 Subject: [PATCH 321/719] Test that `core::assert!` is valid --- src/test/ui/no-std-macros.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/test/ui/no-std-macros.rs diff --git a/src/test/ui/no-std-macros.rs b/src/test/ui/no-std-macros.rs new file mode 100644 index 000000000000..ada643c7ac04 --- /dev/null +++ b/src/test/ui/no-std-macros.rs @@ -0,0 +1,13 @@ +// compile-flags: --crate-type=lib +// check-pass +// issue #55482 +#![no_std] + +macro_rules! foo { + ($e:expr) => { + $crate::core::assert!($e); + $crate::core::assert_eq!($e, true); + }; +} + +pub fn foo() { foo!(true); } From c18c7c7059cb1c63aad9892ecbed58c229c74098 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 14 Dec 2020 22:28:24 -0500 Subject: [PATCH 322/719] Remove redundant assignment `crate.name` is already set by `tcx.crate_name`, there's no need to override it. --- src/librustdoc/lib.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 94b6617a071a..24045b4e29dc 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -519,17 +519,12 @@ fn main_options(options: config::Options) -> MainResult { // compiler all the way through the analysis passes. The rustdoc output is // then generated from the cleaned AST of the crate. This runs all the // plug/cleaning passes. - let crate_name = options.crate_name.clone(); let crate_version = options.crate_version.clone(); let output_format = options.output_format; let (mut krate, renderinfo, renderopts, sess) = core::run_core(options); info!("finished with rustc"); - if let Some(name) = crate_name { - krate.name = name - } - krate.version = crate_version; if show_coverage { From 7ee8e1816f6603502e36b105990bca0f7e440816 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 14 Dec 2020 23:23:58 -0500 Subject: [PATCH 323/719] Use `Symbol`s for crate names --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 4 ++-- src/librustdoc/formats/cache.rs | 11 ++++++----- src/librustdoc/formats/renderer.rs | 3 +-- src/librustdoc/html/render/cache.rs | 2 +- src/librustdoc/html/render/mod.rs | 28 ++++++++++++++++------------ src/librustdoc/html/sources.rs | 2 +- src/librustdoc/json/mod.rs | 2 +- 8 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2d2465e56f37..a531956fb96d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -209,7 +209,7 @@ impl Clean for CrateNum { }; ExternalCrate { - name: cx.tcx.crate_name(*self).to_string(), + name: cx.tcx.crate_name(*self), src: krate_src, attrs: cx.tcx.get_attrs(root).clean(cx), primitives, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2c353a1e0819..cf9e81f30b1f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -51,7 +51,7 @@ thread_local!(crate static MAX_DEF_ID: RefCell> = Def #[derive(Clone, Debug)] crate struct Crate { - crate name: String, + crate name: Symbol, crate version: Option, crate src: FileName, crate module: Option, @@ -66,7 +66,7 @@ crate struct Crate { #[derive(Clone, Debug)] crate struct ExternalCrate { - crate name: String, + crate name: Symbol, crate src: FileName, crate attrs: Attributes, crate primitives: Vec<(DefId, PrimitiveType)>, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index e82bc540e95a..77a3e9fa9549 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; use rustc_middle::middle::privacy::AccessLevels; use rustc_span::source_map::FileName; +use rustc_span::Symbol; use crate::clean::{self, GetDefId}; use crate::config::RenderInfo; @@ -74,7 +75,7 @@ crate struct Cache { crate implementors: FxHashMap>, /// Cache of where external crate documentation can be found. - crate extern_locations: FxHashMap, + crate extern_locations: FxHashMap, /// Cache of where documentation for primitives can be found. crate primitive_locations: FxHashMap, @@ -173,10 +174,10 @@ impl Cache { }, _ => PathBuf::new(), }; - let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u); + let extern_url = extern_html_root_urls.get(&*e.name.as_str()).map(|u| &**u); cache .extern_locations - .insert(n, (e.name.clone(), src_root, extern_location(e, extern_url, &dst))); + .insert(n, (e.name, src_root, extern_location(e, extern_url, &dst))); let did = DefId { krate: n, index: CRATE_DEF_INDEX }; cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); @@ -195,7 +196,7 @@ impl Cache { cache.primitive_locations.insert(prim, def_id); } - cache.stack.push(krate.name.clone()); + cache.stack.push(krate.name.to_string()); krate = cache.fold_crate(krate); for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) { @@ -340,7 +341,7 @@ impl DocFolder for Cache { // Keep track of the fully qualified path for this item. let pushed = match item.name { - Some(ref n) if !n.is_empty() => { + Some(n) if !n.is_empty() => { self.stack.push(n.to_string()); true } diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index c332da4db4ee..f61919d78a09 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use rustc_data_structures::sync::Lrc; use rustc_session::Session; use rustc_span::edition::Edition; -use rustc_span::Symbol; use crate::clean; use crate::config::{RenderInfo, RenderOptions}; @@ -76,7 +75,7 @@ crate fn run_format( None => return Ok(()), }; - item.name = Some(Symbol::intern(&krate.name)); + item.name = Some(krate.name); // Render the crate documentation let mut work = vec![(format_renderer.clone(), item)]; diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 91037bc160ab..ba06b6b182b0 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -31,7 +31,7 @@ crate fn extern_location( ) -> ExternalLocation { use ExternalLocation::*; // See if there's documentation generated into the local directory - let local_location = dst.join(&e.name); + let local_location = dst.join(&*e.name.as_str()); if local_location.is_dir() { return Local; } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 00f3723ce239..d517151bc31e 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -418,14 +418,15 @@ impl FormatRenderer for Context { // If user passed in `--playground-url` arg, we fill in crate name here let mut playground = None; if let Some(url) = playground_url { - playground = Some(markdown::Playground { crate_name: Some(krate.name.clone()), url }); + playground = + Some(markdown::Playground { crate_name: Some(krate.name.to_string()), url }); } let mut layout = layout::Layout { logo: String::new(), favicon: String::new(), external_html, default_settings, - krate: krate.name.clone(), + krate: krate.name.to_string(), css_file_extension: extension_css, generate_search_filter, }; @@ -445,7 +446,7 @@ impl FormatRenderer for Context { } (sym::html_playground_url, Some(s)) => { playground = Some(markdown::Playground { - crate_name: Some(krate.name.clone()), + crate_name: Some(krate.name.to_string()), url: s.to_string(), }); } @@ -530,7 +531,7 @@ impl FormatRenderer for Context { } fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> { - let final_file = self.dst.join(&krate.name).join("all.html"); + let final_file = self.dst.join(&*krate.name.as_str()).join("all.html"); let settings_file = self.dst.join("settings.html"); let crate_name = krate.name.clone(); @@ -1019,7 +1020,8 @@ themePicker.onblur = handleThemeButtonsBlur; } let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix)); - let (mut all_sources, _krates) = try_err!(collect(&dst, &krate.name, "sourcesIndex"), &dst); + let (mut all_sources, _krates) = + try_err!(collect(&dst, &krate.name.as_str(), "sourcesIndex"), &dst); all_sources.push(format!( "sourcesIndex[\"{}\"] = {};", &krate.name, @@ -1035,7 +1037,7 @@ themePicker.onblur = handleThemeButtonsBlur; // Update the search index let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix)); - let (mut all_indexes, mut krates) = try_err!(collect_json(&dst, &krate.name), &dst); + let (mut all_indexes, mut krates) = try_err!(collect_json(&dst, &krate.name.as_str()), &dst); all_indexes.push(search_index); // Sort the indexes by crate so the file will be generated identically even @@ -1070,7 +1072,7 @@ themePicker.onblur = handleThemeButtonsBlur; extra_scripts: &[], static_extra_scripts: &[], }; - krates.push(krate.name.clone()); + krates.push(krate.name.to_string()); krates.sort(); krates.dedup(); @@ -1162,7 +1164,7 @@ themePicker.onblur = handleThemeButtonsBlur; mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1])); let (mut all_implementors, _) = - try_err!(collect(&mydst, &krate.name, "implementors"), &mydst); + try_err!(collect(&mydst, &krate.name.as_str(), "implementors"), &mydst); all_implementors.push(implementors); // Sort the implementors by crate so the file will be generated // identically even with rustdoc running in parallel. @@ -1648,16 +1650,17 @@ impl Context { }; let file = &file; + let symbol; let (krate, path) = if cnum == LOCAL_CRATE { if let Some(path) = self.shared.local_sources.get(file) { - (&self.shared.layout.krate, path) + (self.shared.layout.krate.as_str(), path) } else { return None; } } else { let (krate, src_root) = match *cache.extern_locations.get(&cnum)? { - (ref name, ref src, ExternalLocation::Local) => (name, src), - (ref name, ref src, ExternalLocation::Remote(ref s)) => { + (name, ref src, ExternalLocation::Local) => (name, src), + (name, ref src, ExternalLocation::Remote(ref s)) => { root = s.to_string(); (name, src) } @@ -1671,7 +1674,8 @@ impl Context { let mut fname = file.file_name().expect("source has no filename").to_os_string(); fname.push(".html"); path.push_str(&fname.to_string_lossy()); - (krate, &path) + symbol = krate.as_str(); + (&*symbol, &path) }; let loline = item.source.lo(self.sess()).line; diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index ef9e9f350fb8..b6c3300906bf 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -19,7 +19,7 @@ crate fn render( krate: clean::Crate, ) -> Result { info!("emitting source files"); - let dst = dst.join("src").join(&krate.name); + let dst = dst.join("src").join(&*krate.name.as_str()); scx.ensure_dir(&dst)?; let mut folder = SourceCollector { dst, scx }; Ok(folder.fold_crate(krate)) diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 5c5239d1b6a2..7af26558b76e 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -223,7 +223,7 @@ impl FormatRenderer for JsonRenderer { ( k.as_u32(), types::ExternalCrate { - name: v.0.clone(), + name: v.0.to_string(), html_root_url: match &v.2 { ExternalLocation::Remote(s) => Some(s.clone()), _ => None, From f732cc5cd6aeb06e07bd478d78fccaa625daa685 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Wed, 16 Dec 2020 06:05:25 +0200 Subject: [PATCH 324/719] Remove unsafe code --- clippy_lints/src/utils/internal_lints.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 0de87fab528a..9ba39f73ee88 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -868,8 +868,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths { #[derive(Default)] pub struct InterningDefinedSymbol { - // Maps the symbol to the constant name. - symbol_map: FxHashMap, + // Maps the symbol value to the constant name. + symbol_map: FxHashMap, } impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL]); @@ -889,10 +889,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id); if let Ok(value) = value.to_u32(); then { - // SAFETY: We're converting the raw bytes of the symbol value back - // into a Symbol instance. - let symbol = unsafe { std::mem::transmute::(value) }; - self.symbol_map.insert(symbol.to_string(), item.ident.to_string()); + self.symbol_map.insert(value, item.ident.to_string()); } } } @@ -905,7 +902,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind(); if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN); if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg); - if let Some(symbol_const) = self.symbol_map.get(&arg); + let value = Symbol::intern(&arg).as_u32(); + if let Some(symbol_const) = self.symbol_map.get(&value); then { span_lint_and_sugg( cx, From 1d6b455fb476115712cf7246c5f4cecb7c66915b Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 15 Dec 2020 23:33:47 -0800 Subject: [PATCH 325/719] Fixed conflict with drop elaboration and coverage See https://github.com/rust-lang/rust/issues/80045#issuecomment-745733339 Coverage statements are moved to the beginning of the BCB. This does also affect what's counted before a panic, changing some results, but I think these results may even be preferred? In any case, there are no guarantees about what's counted when a panic occurs (by design). --- .../rustc_mir/src/transform/coverage/mod.rs | 4 ++-- ...rage_graphviz.bar.InstrumentCoverage.0.dot | 2 +- ...age_graphviz.main.InstrumentCoverage.0.dot | 2 +- ...ument_coverage.bar.InstrumentCoverage.diff | 2 +- ...ment_coverage.main.InstrumentCoverage.diff | 8 ++++---- .../expected_export_coverage.assert.json | 20 +++++++++---------- .../expected_export_coverage.overflow.json | 20 +++++++++---------- ...expected_export_coverage.panic_unwind.json | 20 +++++++++---------- .../expected_show_coverage.assert.txt | 8 ++++---- .../expected_show_coverage.overflow.txt | 10 +++++----- .../expected_show_coverage.panic_unwind.txt | 8 ++++---- ...expected_show_coverage_counters.assert.txt | 16 +++++++-------- ...pected_show_coverage_counters.overflow.txt | 16 +++++++-------- ...ed_show_coverage_counters.panic_unwind.txt | 16 +++++++-------- 14 files changed, 76 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 53f7c28ee35b..4590d37c182e 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -310,7 +310,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { inject_statement( self.mir_body, counter_kind, - self.bcb_last_bb(bcb), + self.bcb_leader_bb(bcb), Some(make_code_region(file_name, &self.source_file, span, body_span)), ); } @@ -470,7 +470,7 @@ fn inject_statement( code_region: some_code_region, }), }; - data.statements.push(statement); + data.statements.insert(0, statement); } // Non-code expressions are injected into the coverage map, without generating executable code. diff --git a/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot b/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot index 124f2d8b97a0..c00eae96e083 100644 --- a/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot +++ b/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot @@ -2,5 +2,5 @@ digraph Cov_0_4 { graph [fontname="Courier, monospace"]; node [fontname="Courier, monospace"]; edge [fontname="Courier, monospace"]; - bcb0__Cov_0_4 [shape="none", label=<
bcb0
Counter(bcb0) at 18:1-20:2
19:5-19:9: @0[0]: _0 = const true
20:2-20:2: @0.Return: return
bb0: Return
>]; + bcb0__Cov_0_4 [shape="none", label=<
bcb0
Counter(bcb0) at 18:1-20:2
19:5-19:9: @0[0]: Coverage::Counter(1) for $DIR/coverage_graphviz.rs:18:1 - 20:2
20:2-20:2: @0.Return: return
bb0: Return
>]; } diff --git a/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot b/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot index d88193da4fb1..5b6d73a7deef 100644 --- a/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot +++ b/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot @@ -2,7 +2,7 @@ digraph Cov_0_3 { graph [fontname="Courier, monospace"]; node [fontname="Courier, monospace"]; edge [fontname="Courier, monospace"]; - bcb2__Cov_0_3 [shape="none", label=<
bcb2
Expression(bcb0 - bcb1) at 13:10-13:10
13:10-13:10: @4[0]: _1 = const ()
bb4: Goto
>]; + bcb2__Cov_0_3 [shape="none", label=<
bcb2
Expression(bcb0 - bcb1) at 13:10-13:10
13:10-13:10: @4[0]: Coverage::Expression(4294967295) = 1 - 2 for $DIR/coverage_graphviz.rs:13:10 - 13:11
bb4: Goto
>]; bcb1__Cov_0_3 [shape="none", label=<
bcb1
Counter(bcb1) at 12:13-12:18
12:13-12:18: @5[0]: _0 = const ()
Expression(bcb1 + 0) at 15:2-15:2
15:2-15:2: @5.Return: return
bb3: FalseEdge
bb5: Return
>]; bcb0__Cov_0_3 [shape="none", label=<
bcb0
Counter(bcb0) at 9:1-11:17
11:12-11:17: @1.Call: _2 = bar() -> [return: bb2, unwind: bb6]
11:12-11:17: @2[0]: FakeRead(ForMatchedPlace, _2)
bb0: FalseUnwind
bb1: Call
bb2: SwitchInt
>]; bcb2__Cov_0_3 -> bcb0__Cov_0_3 [label=<>]; diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index 112a69830927..fef696df770b 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -5,8 +5,8 @@ let mut _0: bool; // return place in scope 0 at /the/src/instrument_coverage.rs:19:13: 19:17 bb0: { - _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 + Coverage::Counter(1) for /the/src/instrument_coverage.rs:19:1 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 + _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 return; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 83dee7efa6db..9bd8c9cf6133 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -8,6 +8,7 @@ let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10 bb0: { ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 falseUnwind -> [real: bb1, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } @@ -21,26 +22,25 @@ bb2: { FakeRead(ForMatchedPlace, _2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 -+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 switchInt(_2) -> [false: bb4, otherwise: bb3]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 } bb3: { ++ Coverage::Expression(4294967294) = 2 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 ++ Coverage::Counter(2) for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 } bb4: { ++ Coverage::Expression(4294967295) = 1 - 2 for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:14:10: 14:10 StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6 -+ Coverage::Expression(4294967295) = 1 - 2 for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 goto -> bb0; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } bb5: { _0 = const (); // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18 StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6 -+ Coverage::Counter(2) for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 -+ Coverage::Expression(4294967294) = 2 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 return; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json index 024b5f11179a..bb857ba3f3b3 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json @@ -17,14 +17,14 @@ }, "lines": { "count": 15, - "covered": 12, - "percent": 80 + "covered": 13, + "percent": 86.66666666666667 }, "regions": { "count": 14, - "covered": 12, - "notcovered": 2, - "percent": 85.71428571428571 + "covered": 13, + "notcovered": 1, + "percent": 92.85714285714286 } } } @@ -42,14 +42,14 @@ }, "lines": { "count": 15, - "covered": 12, - "percent": 80 + "covered": 13, + "percent": 86.66666666666667 }, "regions": { "count": 14, - "covered": 12, - "notcovered": 2, - "percent": 85.71428571428571 + "covered": 13, + "notcovered": 1, + "percent": 92.85714285714286 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json index 030d7b033f00..128f5888ed11 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json @@ -17,14 +17,14 @@ }, "lines": { "count": 23, - "covered": 19, - "percent": 82.6086956521739 + "covered": 21, + "percent": 91.30434782608695 }, "regions": { "count": 13, - "covered": 11, - "notcovered": 2, - "percent": 84.61538461538461 + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 } } } @@ -42,14 +42,14 @@ }, "lines": { "count": 23, - "covered": 19, - "percent": 82.6086956521739 + "covered": 21, + "percent": 91.30434782608695 }, "regions": { "count": 13, - "covered": 11, - "notcovered": 2, - "percent": 84.61538461538461 + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json index b1d44fdfeac5..9c08dfd41a12 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json @@ -17,14 +17,14 @@ }, "lines": { "count": 19, - "covered": 16, - "percent": 84.21052631578947 + "covered": 17, + "percent": 89.47368421052632 }, "regions": { "count": 13, - "covered": 11, - "notcovered": 2, - "percent": 84.61538461538461 + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 } } } @@ -42,14 +42,14 @@ }, "lines": { "count": 19, - "covered": 16, - "percent": 84.21052631578947 + "covered": 17, + "percent": 89.47368421052632 }, "regions": { "count": 13, - "covered": 11, - "notcovered": 2, - "percent": 84.61538461538461 + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt index 355b53f7f3b6..405688806eaa 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt @@ -9,13 +9,13 @@ 8| | 9| 1|fn main() -> Result<(),u8> { 10| 1| let mut countdown = 10; - 11| 10| while countdown > 0 { - 12| 10| if countdown == 1 { - 13| 0| might_fail_assert(3); + 11| 11| while countdown > 0 { + 12| 11| if countdown == 1 { + 13| 1| might_fail_assert(3); 14| 10| } else if countdown < 5 { 15| 3| might_fail_assert(2); 16| 6| } - 17| 9| countdown -= 1; + 17| 10| countdown -= 1; 18| | } 19| 0| Ok(()) 20| 0|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt index 4dccb3413eae..25e822bffd11 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt @@ -14,15 +14,15 @@ 14| | 15| 1|fn main() -> Result<(),u8> { 16| 1| let mut countdown = 10; - 17| 10| while countdown > 0 { - 18| 10| if countdown == 1 { - 19| 0| let result = might_overflow(10); - 20| 0| println!("Result: {}", result); + 17| 11| while countdown > 0 { + 18| 11| if countdown == 1 { + 19| 1| let result = might_overflow(10); + 20| 1| println!("Result: {}", result); 21| 10| } else if countdown < 5 { 22| 3| let result = might_overflow(1); 23| 3| println!("Result: {}", result); 24| 6| } - 25| 9| countdown -= 1; + 25| 10| countdown -= 1; 26| | } 27| 0| Ok(()) 28| 0|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt index 9ae78fee4b5e..c77ee5ddc207 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt @@ -12,13 +12,13 @@ 12| | 13| 1|fn main() -> Result<(), u8> { 14| 1| let mut countdown = 10; - 15| 10| while countdown > 0 { - 16| 10| if countdown == 1 { - 17| 0| might_panic(true); + 15| 11| while countdown > 0 { + 16| 11| if countdown == 1 { + 17| 1| might_panic(true); 18| 10| } else if countdown < 5 { 19| 3| might_panic(false); 20| 6| } - 21| 9| countdown -= 1; + 21| 10| countdown -= 1; 22| | } 23| 0| Ok(()) 24| 0|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt index 916ebbbcc29d..0866a9a59a11 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt @@ -20,13 +20,13 @@ Combined regions: 6:37 -> 6:61 (count=1) 7:1 -> 7:2 (count=3) 9:1 -> 10:27 (count=1) - 11:11 -> 11:24 (count=10) - 12:12 -> 12:26 (count=10) - 12:27 -> 14:10 (count=0) + 11:11 -> 11:24 (count=11) + 12:12 -> 12:26 (count=11) + 12:27 -> 14:10 (count=1) 14:19 -> 14:32 (count=10) 14:33 -> 16:10 (count=3) 16:10 -> 16:11 (count=6) - 17:9 -> 17:23 (count=9) + 17:9 -> 17:23 (count=10) 19:5 -> 20:2 (count=0) Segment at 4:1 (count = 4), RegionEntry Segment at 4:41 (count = 0), Skipped @@ -40,18 +40,18 @@ Segment at 7:1 (count = 3), RegionEntry Segment at 7:2 (count = 0), Skipped Segment at 9:1 (count = 1), RegionEntry Segment at 10:27 (count = 0), Skipped -Segment at 11:11 (count = 10), RegionEntry +Segment at 11:11 (count = 11), RegionEntry Segment at 11:24 (count = 0), Skipped -Segment at 12:12 (count = 10), RegionEntry +Segment at 12:12 (count = 11), RegionEntry Segment at 12:26 (count = 0), Skipped -Segment at 12:27 (count = 0), RegionEntry +Segment at 12:27 (count = 1), RegionEntry Segment at 14:10 (count = 0), Skipped Segment at 14:19 (count = 10), RegionEntry Segment at 14:32 (count = 0), Skipped Segment at 14:33 (count = 3), RegionEntry Segment at 16:10 (count = 6), RegionEntry Segment at 16:11 (count = 0), Skipped -Segment at 17:9 (count = 9), RegionEntry +Segment at 17:9 (count = 10), RegionEntry Segment at 17:23 (count = 0), Skipped Segment at 19:5 (count = 0), RegionEntry Segment at 20:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt index fbc3adbfb6d7..380bb7cf1701 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt @@ -18,13 +18,13 @@ Combined regions: 7:6 -> 7:7 (count=3) 8:9 -> 13:2 (count=4) 15:1 -> 16:27 (count=1) - 17:11 -> 17:24 (count=10) - 18:12 -> 18:26 (count=10) - 18:27 -> 21:10 (count=0) + 17:11 -> 17:24 (count=11) + 18:12 -> 18:26 (count=11) + 18:27 -> 21:10 (count=1) 21:19 -> 21:32 (count=10) 21:33 -> 24:10 (count=3) 24:10 -> 24:11 (count=6) - 25:9 -> 25:23 (count=9) + 25:9 -> 25:23 (count=10) 27:5 -> 28:2 (count=0) Segment at 4:1 (count = 4), RegionEntry Segment at 5:18 (count = 0), Skipped @@ -35,18 +35,18 @@ Segment at 8:9 (count = 4), RegionEntry Segment at 13:2 (count = 0), Skipped Segment at 15:1 (count = 1), RegionEntry Segment at 16:27 (count = 0), Skipped -Segment at 17:11 (count = 10), RegionEntry +Segment at 17:11 (count = 11), RegionEntry Segment at 17:24 (count = 0), Skipped -Segment at 18:12 (count = 10), RegionEntry +Segment at 18:12 (count = 11), RegionEntry Segment at 18:26 (count = 0), Skipped -Segment at 18:27 (count = 0), RegionEntry +Segment at 18:27 (count = 1), RegionEntry Segment at 21:10 (count = 0), Skipped Segment at 21:19 (count = 10), RegionEntry Segment at 21:32 (count = 0), Skipped Segment at 21:33 (count = 3), RegionEntry Segment at 24:10 (count = 6), RegionEntry Segment at 24:11 (count = 0), Skipped -Segment at 25:9 (count = 9), RegionEntry +Segment at 25:9 (count = 10), RegionEntry Segment at 25:23 (count = 0), Skipped Segment at 27:5 (count = 0), RegionEntry Segment at 28:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt index ad87f03026d3..b3f61ad325d1 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt @@ -18,13 +18,13 @@ Combined regions: 6:9 -> 7:26 (count=1) 8:12 -> 11:2 (count=3) 13:1 -> 14:27 (count=1) - 15:11 -> 15:24 (count=10) - 16:12 -> 16:26 (count=10) - 16:27 -> 18:10 (count=0) + 15:11 -> 15:24 (count=11) + 16:12 -> 16:26 (count=11) + 16:27 -> 18:10 (count=1) 18:19 -> 18:32 (count=10) 18:33 -> 20:10 (count=3) 20:10 -> 20:11 (count=6) - 21:9 -> 21:23 (count=9) + 21:9 -> 21:23 (count=10) 23:5 -> 24:2 (count=0) Segment at 4:1 (count = 4), RegionEntry Segment at 4:36 (count = 0), Skipped @@ -36,18 +36,18 @@ Segment at 8:12 (count = 3), RegionEntry Segment at 11:2 (count = 0), Skipped Segment at 13:1 (count = 1), RegionEntry Segment at 14:27 (count = 0), Skipped -Segment at 15:11 (count = 10), RegionEntry +Segment at 15:11 (count = 11), RegionEntry Segment at 15:24 (count = 0), Skipped -Segment at 16:12 (count = 10), RegionEntry +Segment at 16:12 (count = 11), RegionEntry Segment at 16:26 (count = 0), Skipped -Segment at 16:27 (count = 0), RegionEntry +Segment at 16:27 (count = 1), RegionEntry Segment at 18:10 (count = 0), Skipped Segment at 18:19 (count = 10), RegionEntry Segment at 18:32 (count = 0), Skipped Segment at 18:33 (count = 3), RegionEntry Segment at 20:10 (count = 6), RegionEntry Segment at 20:11 (count = 0), Skipped -Segment at 21:9 (count = 9), RegionEntry +Segment at 21:9 (count = 10), RegionEntry Segment at 21:23 (count = 0), Skipped Segment at 23:5 (count = 0), RegionEntry Segment at 24:2 (count = 0), Skipped From acc63bc5baa1f5b51640e8f8ce7fd8b53d45c891 Mon Sep 17 00:00:00 2001 From: Jakub Kulik Date: Wed, 16 Dec 2020 10:41:07 +0100 Subject: [PATCH 326/719] Add support for target aliases --- compiler/rustc_session/src/config.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 54abb65dc388..0e9cb7f325f6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1433,7 +1433,7 @@ fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType early_error(error_format, &format!("target file {:?} does not exist", path)) }) } - Some(target) => TargetTriple::TargetTriple(target), + Some(target) => TargetTriple::from_alias(target), _ => TargetTriple::from_triple(host_triple()), } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8d749493d0a4..8d72df6850fc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1800,6 +1800,24 @@ impl TargetTriple { Ok(TargetTriple::TargetPath(canonicalized_path)) } + /// Creates a target triple from its alias + pub fn from_alias(triple: String) -> Self { + macro_rules! target_aliases { + ( $(($alias:literal, $target:literal ),)+ ) => { + match triple.as_str() { + $( $alias => TargetTriple::from_triple($target), )+ + _ => TargetTriple::TargetTriple(triple), + } + } + } + + target_aliases! { + // `x86_64-pc-solaris` is an alias for `x86_64_sun_solaris` for backwards compatibility reasons. + // (See .) + ("x86_64-pc-solaris", "x86_64-sun-solaris"), + } + } + /// Returns a string triple for this target. /// /// If this target is a path, the file name (without extension) is returned. From 341aa97adb20ca22e0fcb0851014bfa2297ff932 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Sep 2020 16:25:20 +0100 Subject: [PATCH 327/719] llvm: update ffi bindings for split dwarf This commit modifies the FFI bindings to LLVM required for Split DWARF support in rustc. In particular: - `addPassesToEmitFile`'s wrapper, `LLVMRustWriteOutputFile` now takes a `DwoPath` `const char*`. When disabled, `nullptr` should be provided which will preserve existing behaviour. When enabled, the path to the `.dwo` file should be provided. - `createCompileUnit`'s wrapper, `LLVMRustDIBuilderCreateCompileUnit` now has two additional arguments, for the `DWOId` and to enable `SplitDebugInlining`. `DWOId` should always be zero. - `createTargetMachine`'s wrapper, `LLVMRustCreateTargetMachine` has an additional argument which should be provided the path to the `.dwo` when enabled. Signed-off-by: David Wood --- compiler/rustc_codegen_llvm/src/back/write.rs | 11 +++++++- .../src/debuginfo/metadata.rs | 2 ++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 +++ .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 26 ++++++++++++++++--- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 5 ++-- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 7407dfc455d8..a6b866a0498c 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -53,7 +53,14 @@ pub fn write_output_file( ) -> Result<(), FatalError> { unsafe { let output_c = path_to_c_string(output); - let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type); + let result = llvm::LLVMRustWriteOutputFile( + target, + pm, + m, + output_c.as_ptr(), + std::ptr::null(), + file_type, + ); result.into_result().map_err(|()| { let msg = format!("could not write output to {}", output.display()); llvm_err(handler, &msg) @@ -164,6 +171,7 @@ pub fn target_machine_factory( !sess.opts.debugging_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section); Arc::new(move || { + let split_dwarf_file = std::ptr::null(); let tm = unsafe { llvm::LLVMRustCreateTargetMachine( triple.as_ptr(), @@ -182,6 +190,7 @@ pub fn target_machine_factory( emit_stack_size_section, relax_elf_relocations, use_init_array, + split_dwarf_file, ) }; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 31e43893ac8b..41c8a5e57052 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1039,6 +1039,8 @@ pub fn compile_unit_metadata( split_name.as_ptr().cast(), split_name.len(), kind, + 0, + true, ); if tcx.sess.opts.debugging_opts.profile { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 41482d18946a..707aaa2b53ff 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1830,6 +1830,8 @@ extern "C" { SplitName: *const c_char, SplitNameLen: size_t, kind: DebugEmissionKind, + DWOId: u64, + SplitDebugInlining: bool, ) -> &'a DIDescriptor; pub fn LLVMRustDIBuilderCreateFile( @@ -2151,6 +2153,7 @@ extern "C" { EmitStackSizeSection: bool, RelaxELFRelocations: bool, UseInitArray: bool, + SplitDwarfFile: *const c_char, ) -> Option<&'static mut TargetMachine>; pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine); pub fn LLVMRustAddBuilderLibraryInfo( @@ -2179,6 +2182,7 @@ extern "C" { PM: &PassManager<'a>, M: &'a Module, Output: *const c_char, + DwoOutput: *const c_char, FileType: FileType, ) -> LLVMRustResult; pub fn LLVMRustOptimizeWithNewPassManager( diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 01d76bb3e94f..2264908995bb 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -450,7 +450,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( bool AsmComments, bool EmitStackSizeSection, bool RelaxELFRelocations, - bool UseInitArray) { + bool UseInitArray, + const char *SplitDwarfFile) { auto OptLevel = fromRust(RustOptLevel); auto RM = fromRust(RustReloc); @@ -476,6 +477,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.MCOptions.AsmVerbose = AsmComments; Options.MCOptions.PreserveAsmComments = AsmComments; Options.MCOptions.ABIName = ABIStr; + if (SplitDwarfFile) { + Options.MCOptions.SplitDwarfFile = SplitDwarfFile; + } Options.RelaxELFRelocations = RelaxELFRelocations; Options.UseInitArray = UseInitArray; @@ -610,7 +614,7 @@ static TargetMachine::CodeGenFileType fromRust(LLVMRustFileType Type) { extern "C" LLVMRustResult LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, - LLVMModuleRef M, const char *Path, + LLVMModuleRef M, const char *Path, const char *DwoPath, LLVMRustFileType RustFileType) { llvm::legacy::PassManager *PM = unwrap(PMR); auto FileType = fromRust(RustFileType); @@ -626,8 +630,22 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, } buffer_ostream BOS(OS); - unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, false); - PM->run(*unwrap(M)); + if (DwoPath) { + raw_fd_ostream DOS(DwoPath, EC, sys::fs::F_None); + EC.clear(); + if (EC) + ErrorInfo = EC.message(); + if (ErrorInfo != "") { + LLVMRustSetLastError(ErrorInfo.c_str()); + return LLVMRustResult::Failure; + } + buffer_ostream DBOS(DOS); + unwrap(Target)->addPassesToEmitFile(*PM, BOS, &DBOS, FileType, false); + PM->run(*unwrap(M)); + } else { + unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, false); + PM->run(*unwrap(M)); + } // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output // stream (OS), so the only real safe place to delete this is here? Don't we diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index e17f933932e6..c0ff62c17beb 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -690,13 +690,14 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( const char *Producer, size_t ProducerLen, bool isOptimized, const char *Flags, unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, - LLVMRustDebugEmissionKind Kind) { + LLVMRustDebugEmissionKind Kind, + uint64_t DWOId, bool SplitDebugInlining) { auto *File = unwrapDI(FileRef); return wrap(Builder->createCompileUnit(Lang, File, StringRef(Producer, ProducerLen), isOptimized, Flags, RuntimeVer, StringRef(SplitName, SplitNameLen), - fromRust(Kind))); + fromRust(Kind), DWOId, SplitDebugInlining)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile( From 57d05d35765a443fbb0b789a823e84ddff7c0cb1 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Sep 2020 16:50:58 +0100 Subject: [PATCH 328/719] session: add `split-dwarf` flag This commit adds a flag for Split DWARF, which enables debuginfo to be split into multiple files. Signed-off-by: David Wood --- compiler/rustc_session/src/config.rs | 17 +++++++++++++++++ compiler/rustc_session/src/options.rs | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b77a8b631e05..b5354513dc2e 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -221,6 +221,23 @@ pub enum DebugInfo { Full, } +/// Some debuginfo requires link-time relocation and some does not. LLVM can partition the debuginfo +/// into sections depending on whether or not it requires link-time relocation. Split DWARF +/// provides a mechanism which allows the linker to skip the sections which don't require link-time +/// relocation - either by putting those sections into DWARF object files, or keeping them in the +/// object file in such a way that the linker will skip them. +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +pub enum SplitDwarfKind { + /// Disabled. + None, + /// Sections which do not require relocation are written into the object file but ignored + /// by the linker. + Single, + /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file, + /// which is skipped by the linker by virtue of being a different file. + Split, +} + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] #[derive(Encodable, Decodable)] pub enum OutputType { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 49a7888fd6a4..81f79f4b0e0f 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -269,6 +269,7 @@ macro_rules! options { pub const parse_switch_with_opt_path: &str = "an optional path to the profiling data output directory"; pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`"; + pub const parse_split_dwarf_kind: &str = "one of: `none`, `single` or `split`"; pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)"; pub const parse_src_file_hash: &str = "either `md5` or `sha1`"; pub const parse_relocation_model: &str = @@ -676,6 +677,19 @@ macro_rules! options { true } + fn parse_split_dwarf_kind( + slot: &mut SplitDwarfKind, + v: Option<&str>, + ) -> bool { + *slot = match v { + Some("none") => SplitDwarfKind::None, + Some("split") => SplitDwarfKind::Split, + Some("single") => SplitDwarfKind::Single, + _ => return false, + }; + true + } + fn parse_symbol_mangling_version( slot: &mut Option, v: Option<&str>, @@ -1088,6 +1102,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), + split_dwarf: SplitDwarfKind = (SplitDwarfKind::None, parse_split_dwarf_kind, [UNTRACKED], + "enable generation of split dwarf"), + split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED], + "provide minimal debug info in the object/executable to facilitate online \ + symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"), symbol_mangling_version: Option = (None, parse_symbol_mangling_version, [TRACKED], "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), From cf49c2a1efe65d8cbe671ef02e5c4d870529da13 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 14 Oct 2020 15:52:16 +0100 Subject: [PATCH 329/719] cg_ssa: correct documentation comments This commit changes some comments to documentation comments so that they can be read on the generated rustdoc. Signed-off-by: David Wood --- compiler/rustc_codegen_ssa/src/back/link.rs | 105 +++++++++----------- 1 file changed, 49 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 70cf876a08a5..5001e97016ce 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -279,12 +279,12 @@ pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeT out_filename } -// Create an 'rlib' -// -// An rlib in its current incarnation is essentially a renamed .a file. The -// rlib primarily contains the object file of the crate, but it also contains -// all of the object files from native libraries. This is done by unzipping -// native libraries and inserting all of the contents into this archive. +/// Create an 'rlib'. +/// +/// An rlib in its current incarnation is essentially a renamed .a file. The rlib primarily contains +/// the object file of the crate, but it also contains all of the object files from native +/// libraries. This is done by unzipping native libraries and inserting all of the contents into +/// this archive. fn link_rlib<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, codegen_results: &CodegenResults, @@ -379,18 +379,17 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( ab } -// Create a static archive -// -// This is essentially the same thing as an rlib, but it also involves adding -// all of the upstream crates' objects into the archive. This will slurp in -// all of the native libraries of upstream dependencies as well. -// -// Additionally, there's no way for us to link dynamic libraries, so we warn -// about all dynamic library dependencies that they're not linked in. -// -// There's no need to include metadata in a static archive, so ensure to not -// link in the metadata object file (and also don't prepare the archive with a -// metadata file). +/// Create a static archive. +/// +/// This is essentially the same thing as an rlib, but it also involves adding all of the upstream +/// crates' objects into the archive. This will slurp in all of the native libraries of upstream +/// dependencies as well. +/// +/// Additionally, there's no way for us to link dynamic libraries, so we warn about all dynamic +/// library dependencies that they're not linked in. +/// +/// There's no need to include metadata in a static archive, so ensure to not link in the metadata +/// object file (and also don't prepare the archive with a metadata file). fn link_staticlib<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, codegen_results: &CodegenResults, @@ -447,10 +446,10 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( } } -// Create a dynamic library or executable -// -// This will invoke the system linker/cc to create the resulting file. This -// links to all upstream files as well. +/// Create a dynamic library or executable. +/// +/// This will invoke the system linker/cc to create the resulting file. This links to all upstream +/// files as well. fn link_natively<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, crate_type: CrateType, @@ -1677,17 +1676,15 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( cmd.take_cmd() } -// # Native library linking -// -// User-supplied library search paths (-L on the command line). These are -// the same paths used to find Rust crates, so some of them may have been -// added already by the previous crate linking code. This only allows them -// to be found at compile time so it is still entirely up to outside -// forces to make sure that library can be found at runtime. -// -// Also note that the native libraries linked here are only the ones located -// in the current crate. Upstream crates with native library dependencies -// may have their native library pulled in above. +/// # Native library linking +/// +/// User-supplied library search paths (-L on the command line). These are the same paths used to +/// find Rust crates, so some of them may have been added already by the previous crate linking +/// code. This only allows them to be found at compile time so it is still entirely up to outside +/// forces to make sure that library can be found at runtime. +/// +/// Also note that the native libraries linked here are only the ones located in the current crate. +/// Upstream crates with native library dependencies may have their native library pulled in above. fn add_local_native_libraries( cmd: &mut dyn Linker, sess: &Session, @@ -1727,11 +1724,10 @@ fn add_local_native_libraries( } } -// # Rust Crate linking -// -// Rust crates are not considered at all when creating an rlib output. All -// dependencies will be linked when producing the final output (instead of -// the intermediate rlib version) +/// # Rust Crate linking +/// +/// Rust crates are not considered at all when creating an rlib output. All dependencies will be +/// linked when producing the final output (instead of the intermediate rlib version). fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( cmd: &mut dyn Linker, sess: &'a Session, @@ -1996,24 +1992,21 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( } } -// Link in all of our upstream crates' native dependencies. Remember that -// all of these upstream native dependencies are all non-static -// dependencies. We've got two cases then: -// -// 1. The upstream crate is an rlib. In this case we *must* link in the -// native dependency because the rlib is just an archive. -// -// 2. The upstream crate is a dylib. In order to use the dylib, we have to -// have the dependency present on the system somewhere. Thus, we don't -// gain a whole lot from not linking in the dynamic dependency to this -// crate as well. -// -// The use case for this is a little subtle. In theory the native -// dependencies of a crate are purely an implementation detail of the crate -// itself, but the problem arises with generic and inlined functions. If a -// generic function calls a native function, then the generic function must -// be instantiated in the target crate, meaning that the native symbol must -// also be resolved in the target crate. +/// Link in all of our upstream crates' native dependencies. Remember that all of these upstream +/// native dependencies are all non-static dependencies. We've got two cases then: +/// +/// 1. The upstream crate is an rlib. In this case we *must* link in the native dependency because +/// the rlib is just an archive. +/// +/// 2. The upstream crate is a dylib. In order to use the dylib, we have to have the dependency +/// present on the system somewhere. Thus, we don't gain a whole lot from not linking in the +/// dynamic dependency to this crate as well. +/// +/// The use case for this is a little subtle. In theory the native dependencies of a crate are +/// purely an implementation detail of the crate itself, but the problem arises with generic and +/// inlined functions. If a generic function calls a native function, then the generic function +/// must be instantiated in the target crate, meaning that the native symbol must also be resolved +/// in the target crate. fn add_upstream_native_libraries( cmd: &mut dyn Linker, sess: &Session, From 6890312ea3b7f59bc18de68930524b8853442627 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Sep 2020 16:57:50 +0100 Subject: [PATCH 330/719] cg_ssa: introduce `TargetMachineFactoryFn` alias This commit removes the `TargetMachineFactory` struct and adds a `TargetMachineFactoryFn` type alias which is used everywhere that the previous, long type was used. Signed-off-by: David Wood --- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 +- compiler/rustc_codegen_llvm/src/back/write.rs | 6 ++++-- compiler/rustc_codegen_llvm/src/lib.rs | 9 +++++---- compiler/rustc_codegen_ssa/src/back/write.rs | 16 ++++------------ compiler/rustc_codegen_ssa/src/traits/backend.rs | 4 ++-- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 64fd1d09cc24..64ca7efb4865 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -728,7 +728,7 @@ pub unsafe fn optimize_thin_module( cgcx: &CodegenContext, ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); - let tm = (cgcx.tm_factory.0)().map_err(|e| write::llvm_err(&diag_handler, &e))?; + let tm = (cgcx.tm_factory)().map_err(|e| write::llvm_err(&diag_handler, &e))?; // Right now the implementation we've got only works over serialized // modules, so we create a fresh new LLVM context and parse the module diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index a6b866a0498c..612ed4405bb8 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -11,7 +11,9 @@ use crate::llvm_util; use crate::type_::Type; use crate::LlvmCodegenBackend; use crate::ModuleLlvm; -use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; +use rustc_codegen_ssa::back::write::{ + BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryFn, +}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::small_c_str::SmallCStr; @@ -129,7 +131,7 @@ fn to_llvm_code_model(code_model: Option) -> llvm::CodeModel { pub fn target_machine_factory( sess: &Session, optlvl: config::OptLevel, -) -> Arc Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { +) -> TargetMachineFactoryFn { let reloc_model = to_llvm_relocation_model(sess.relocation_model()); let (opt_level, _) = to_llvm_opt_settings(optlvl); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 5974b59d39e4..4fe0384b3696 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -19,7 +19,9 @@ use back::write::{create_informational_target_machine, create_target_machine}; pub use llvm_util::target_features; use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; -use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; +use rustc_codegen_ssa::back::write::{ + CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn, +}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; @@ -34,7 +36,6 @@ use rustc_span::symbol::Symbol; use std::any::Any; use std::ffi::CStr; -use std::sync::Arc; mod back { pub mod archive; @@ -109,7 +110,7 @@ impl ExtraBackendMethods for LlvmCodegenBackend { &self, sess: &Session, optlvl: OptLevel, - ) -> Arc Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { + ) -> TargetMachineFactoryFn { back::write::target_machine_factory(sess, optlvl) } fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str { @@ -352,7 +353,7 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?; - let tm = match (cgcx.tm_factory.0)() { + let tm = match (cgcx.tm_factory)() { Ok(m) => m, Err(e) => { handler.struct_err(&e).emit(); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7f2bb7b5bcda..615eeecf54ea 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -274,16 +274,8 @@ impl ModuleConfig { } } -// HACK(eddyb) work around `#[derive]` producing wrong bounds for `Clone`. -pub struct TargetMachineFactory( - pub Arc Result + Send + Sync>, -); - -impl Clone for TargetMachineFactory { - fn clone(&self) -> Self { - TargetMachineFactory(self.0.clone()) - } -} +pub type TargetMachineFactoryFn = + Arc Result<::TargetMachine, String> + Send + Sync>; pub type ExportedSymbols = FxHashMap>>; @@ -305,7 +297,7 @@ pub struct CodegenContext { pub regular_module_config: Arc, pub metadata_module_config: Arc, pub allocator_module_config: Arc, - pub tm_factory: TargetMachineFactory, + pub tm_factory: TargetMachineFactoryFn, pub msvc_imps_needed: bool, pub is_pe_coff: bool, pub target_pointer_width: u32, @@ -1020,7 +1012,7 @@ fn start_executing_work( regular_module_config: regular_config, metadata_module_config: metadata_config, allocator_module_config: allocator_config, - tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol)), + tm_factory: backend.target_machine_factory(tcx.sess, ol), total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), is_pe_coff: tcx.sess.target.is_like_windows, diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index b9c555c2eb06..f28db2fe84b6 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -1,5 +1,6 @@ use super::write::WriteBackendMethods; use super::CodegenObject; +use crate::back::write::TargetMachineFactoryFn; use crate::{CodegenResults, ModuleCodegen}; use rustc_ast::expand::allocator::AllocatorKind; @@ -21,7 +22,6 @@ use rustc_target::spec::Target; pub use rustc_data_structures::sync::MetadataRef; use std::any::Any; -use std::sync::Arc; pub trait BackendTypes { type Value: CodegenObject; @@ -123,7 +123,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se &self, sess: &Session, opt_level: config::OptLevel, - ) -> Arc Result + Send + Sync>; + ) -> TargetMachineFactoryFn; fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str; fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>; } From 241160de72b5b55187ca54243e2a6e82e336d07c Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 14 Oct 2020 18:16:05 +0100 Subject: [PATCH 331/719] bootstrap: copy `llvm-dwp` to sysroot `llvm-dwp` is required for linking the DWARF objects into DWARF packages when using Split DWARF, especially given that rustc produces multiple DWARF objects (one for each codegen unit). Signed-off-by: David Wood --- src/bootstrap/compile.rs | 20 +++++++++++++++----- src/bootstrap/dist.rs | 15 +++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index cdad1cb4d499..fbebb26c7462 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -969,15 +969,25 @@ impl Step for Assemble { copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler); + // We prepend this bin directory to the user PATH when linking Rust binaries. To + // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`. let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host); + let libdir_bin = libdir.parent().unwrap().join("bin"); + t!(fs::create_dir_all(&libdir_bin)); + if let Some(lld_install) = lld_install { let src_exe = exe("lld", target_compiler.host); let dst_exe = exe("rust-lld", target_compiler.host); - // we prepend this bin directory to the user PATH when linking Rust binaries. To - // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`. - let dst = libdir.parent().unwrap().join("bin"); - t!(fs::create_dir_all(&dst)); - builder.copy(&lld_install.join("bin").join(&src_exe), &dst.join(&dst_exe)); + builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe)); + } + + // Similarly, copy `llvm-dwp` into libdir for Split DWARF. + { + let src_exe = exe("llvm-dwp", target_compiler.host); + let dst_exe = exe("rust-llvm-dwp", target_compiler.host); + let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host }); + let llvm_bin_dir = llvm_config_bin.parent().unwrap(); + builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe)); } // Ensure that `libLLVM.so` ends up in the newly build compiler directory, diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 360e51ed2bb2..25905895116f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -523,17 +523,20 @@ impl Step for Rustc { // component for now. maybe_install_llvm_runtime(builder, host, image); + let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin"); + let dst_dir = image.join("lib/rustlib").join(&*host.triple).join("bin"); + t!(fs::create_dir_all(&dst_dir)); + // Copy over lld if it's there if builder.config.lld_enabled { let exe = exe("rust-lld", compiler.host); - let src = - builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin").join(&exe); - // for the rationale about this rename check `compile::copy_lld_to_sysroot` - let dst = image.join("lib/rustlib").join(&*host.triple).join("bin").join(&exe); - t!(fs::create_dir_all(&dst.parent().unwrap())); - builder.copy(&src, &dst); + builder.copy(&src_dir.join(&exe), &dst_dir.join(&exe)); } + // Copy over llvm-dwp if it's there + let exe = exe("rust-llvm-dwp", compiler.host); + builder.copy(&src_dir.join(&exe), &dst_dir.join(&exe)); + // Man pages t!(fs::create_dir_all(image.join("share/man/man1"))); let man_src = builder.src.join("src/doc/man"); From e3fdae9d81052cf521298d19f8bb32ba0332b589 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Sep 2020 17:33:54 +0100 Subject: [PATCH 332/719] cg_llvm: implement split dwarf support This commit implements Split DWARF support, wiring up the flag (added in earlier commits) to the modified FFI wrapper (also from earlier commits). Signed-off-by: David Wood --- compiler/rustc_codegen_llvm/src/back/lto.rs | 21 ++-- compiler/rustc_codegen_llvm/src/back/write.rs | 76 ++++++++++--- .../src/debuginfo/metadata.rs | 8 +- compiler/rustc_codegen_llvm/src/lib.rs | 12 ++- compiler/rustc_codegen_ssa/src/back/link.rs | 100 +++++++++++++++--- compiler/rustc_codegen_ssa/src/back/write.rs | 24 ++++- compiler/rustc_codegen_ssa/src/lib.rs | 5 +- compiler/rustc_session/src/config.rs | 28 ++++- 8 files changed, 228 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 64ca7efb4865..834fc02c48ab 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -6,7 +6,9 @@ use crate::llvm::{self, build_string, False, True}; use crate::{LlvmCodegenBackend, ModuleLlvm}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; -use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; +use rustc_codegen_ssa::back::write::{ + CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, +}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::fx::FxHashMap; @@ -728,7 +730,14 @@ pub unsafe fn optimize_thin_module( cgcx: &CodegenContext, ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); - let tm = (cgcx.tm_factory)().map_err(|e| write::llvm_err(&diag_handler, &e))?; + + let module_name = &thin_module.shared.module_names[thin_module.idx]; + let split_dwarf_file = cgcx + .output_filenames + .split_dwarf_file(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap())); + let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file }; + let tm = + (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?; // Right now the implementation we've got only works over serialized // modules, so we create a fresh new LLVM context and parse the module @@ -736,12 +745,8 @@ pub unsafe fn optimize_thin_module( // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = parse_module( - llcx, - &thin_module.shared.module_names[thin_module.idx], - thin_module.data(), - &diag_handler, - )? as *const _; + let llmod_raw = + parse_module(llcx, &module_name, thin_module.data(), &diag_handler)? as *const _; let module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, llcx, tm }, name: thin_module.name().to_string(), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 612ed4405bb8..ef99c87053c7 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -12,7 +12,8 @@ use crate::type_::Type; use crate::LlvmCodegenBackend; use crate::ModuleLlvm; use rustc_codegen_ssa::back::write::{ - BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryFn, + BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig, + TargetMachineFactoryFn, }; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; @@ -22,7 +23,9 @@ use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath}; +use rustc_session::config::{ + self, Lto, OutputType, Passes, SanitizerSet, SplitDwarfKind, SwitchWithOptPath, +}; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::InnerSpan; @@ -51,18 +54,31 @@ pub fn write_output_file( pm: &llvm::PassManager<'ll>, m: &'ll llvm::Module, output: &Path, + dwo_output: Option<&Path>, file_type: llvm::FileType, ) -> Result<(), FatalError> { unsafe { let output_c = path_to_c_string(output); - let result = llvm::LLVMRustWriteOutputFile( - target, - pm, - m, - output_c.as_ptr(), - std::ptr::null(), - file_type, - ); + let result = if let Some(dwo_output) = dwo_output { + let dwo_output_c = path_to_c_string(dwo_output); + llvm::LLVMRustWriteOutputFile( + target, + pm, + m, + output_c.as_ptr(), + dwo_output_c.as_ptr(), + file_type, + ) + } else { + llvm::LLVMRustWriteOutputFile( + target, + pm, + m, + output_c.as_ptr(), + std::ptr::null(), + file_type, + ) + }; result.into_result().map_err(|()| { let msg = format!("could not write output to {}", output.display()); llvm_err(handler, &msg) @@ -71,12 +87,17 @@ pub fn write_output_file( } pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine { - target_machine_factory(sess, config::OptLevel::No)() + let config = TargetMachineFactoryConfig { split_dwarf_file: None }; + target_machine_factory(sess, config::OptLevel::No)(config) .unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise()) } -pub fn create_target_machine(tcx: TyCtxt<'_>) -> &'static mut llvm::TargetMachine { - target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))() +pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine { + let split_dwarf_file = tcx + .output_filenames(LOCAL_CRATE) + .split_dwarf_file(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name)); + let config = TargetMachineFactoryConfig { split_dwarf_file }; + target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))(config) .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise()) } @@ -172,8 +193,10 @@ pub fn target_machine_factory( let use_init_array = !sess.opts.debugging_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section); - Arc::new(move || { - let split_dwarf_file = std::ptr::null(); + Arc::new(move |config: TargetMachineFactoryConfig| { + let split_dwarf_file = config.split_dwarf_file.unwrap_or_default(); + let split_dwarf_file = CString::new(split_dwarf_file.to_str().unwrap()).unwrap(); + let tm = unsafe { llvm::LLVMRustCreateTargetMachine( triple.as_ptr(), @@ -192,7 +215,7 @@ pub fn target_machine_factory( emit_stack_size_section, relax_elf_relocations, use_init_array, - split_dwarf_file, + split_dwarf_file.as_ptr(), ) }; @@ -796,7 +819,15 @@ pub(crate) unsafe fn codegen( llmod }; with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(diag_handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile) + write_output_file( + diag_handler, + tm, + cpm, + llmod, + &path, + None, + llvm::FileType::AssemblyFile, + ) })?; } @@ -805,6 +836,15 @@ pub(crate) unsafe fn codegen( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]); + + let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name); + let dwo_out = match cgcx.split_dwarf_kind { + // Don't change how DWARF is emitted in single mode (or when disabled). + SplitDwarfKind::None | SplitDwarfKind::Single => None, + // Emit (a subset of the) DWARF into a separate file in split mode. + SplitDwarfKind::Split => Some(dwo_out.as_path()), + }; + with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file( diag_handler, @@ -812,6 +852,7 @@ pub(crate) unsafe fn codegen( cpm, llmod, &obj_out, + dwo_out, llvm::FileType::ObjectFile, ) })?; @@ -839,6 +880,7 @@ pub(crate) unsafe fn codegen( Ok(module.into_compiled_module( config.emit_obj != EmitObj::None, + cgcx.split_dwarf_kind == SplitDwarfKind::Split, config.emit_bc, &cgcx.output_filenames, )) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 41c8a5e57052..a9eff59b6aff 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -995,7 +995,11 @@ pub fn compile_unit_metadata( let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); let work_dir = tcx.sess.working_dir.0.to_string_lossy(); let flags = "\0"; - let split_name = ""; + let split_name = tcx + .output_filenames(LOCAL_CRATE) + .split_dwarf_file(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name)) + .unwrap_or_default(); + let split_name = split_name.to_str().unwrap(); // FIXME(#60020): // @@ -1040,7 +1044,7 @@ pub fn compile_unit_metadata( split_name.len(), kind, 0, - true, + tcx.sess.opts.debugging_opts.split_dwarf_inlining, ); if tcx.sess.opts.debugging_opts.profile { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 4fe0384b3696..a5f125d114d2 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -20,7 +20,7 @@ pub use llvm_util::target_features; use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ - CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn, + CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, }; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; @@ -332,7 +332,7 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; - ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx) } + ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, mod_name) } } } @@ -353,7 +353,13 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?; - let tm = match (cgcx.tm_factory)() { + + let split_dwarf_file = cgcx + .output_filenames + .split_dwarf_file(cgcx.split_dwarf_kind, Some(name.to_str().unwrap())); + let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file }; + + let tm = match (cgcx.tm_factory)(tm_factory_config) { Ok(m) => m, Err(e) => { handler.struct_err(&e).emit(); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 5001e97016ce..123d1ae55fb9 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -21,7 +21,9 @@ use super::archive::ArchiveBuilder; use super::command::Command; use super::linker::{self, Linker}; use super::rpath::{self, RPathConfig}; -use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME}; +use crate::{ + looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, METADATA_FILENAME, +}; use cc::windows_registry; use tempfile::Builder as TempFileBuilder; @@ -96,6 +98,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( path.as_ref(), target_cpu, ); + if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Split { + link_dwarf_object(sess, &out_filename); + } } } if sess.opts.json_artifact_notifications { @@ -107,22 +112,30 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( // Remove the temporary object file and metadata if we aren't saving temps sess.time("link_binary_remove_temps", || { if !sess.opts.cg.save_temps { + let remove_temps_from_module = |module: &CompiledModule| { + if let Some(ref obj) = module.object { + remove(sess, obj); + } + + if let Some(ref obj) = module.dwarf_object { + remove(sess, obj); + } + }; + if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) { - for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { - remove(sess, obj); + for module in &codegen_results.modules { + remove_temps_from_module(module); } } + if let Some(ref metadata_module) = codegen_results.metadata_module { - if let Some(ref obj) = metadata_module.object { - remove(sess, obj); - } + remove_temps_from_module(metadata_module); } + if let Some(ref allocator_module) = codegen_results.allocator_module { - if let Some(ref obj) = allocator_module.object { - remove(sess, obj); - } + remove_temps_from_module(allocator_module); } } }); @@ -446,6 +459,69 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( } } +fn escape_stdout_stderr_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from)); + x + }) +} + +const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp"; + +/// Invoke `llvm-dwp` (shipped alongside rustc) to link `dwo` files from Split DWARF into a `dwp` +/// file. +fn link_dwarf_object<'a>(sess: &'a Session, executable_out_filename: &Path) { + info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap()); + + let dwp_out_filename = executable_out_filename.with_extension("dwp"); + let mut cmd = Command::new(LLVM_DWP_EXECUTABLE); + cmd.arg("-e"); + cmd.arg(executable_out_filename); + cmd.arg("-o"); + cmd.arg(&dwp_out_filename); + + let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(false); + if let Some(path) = env::var_os("PATH") { + new_path.extend(env::split_paths(&path)); + } + let new_path = env::join_paths(new_path).unwrap(); + cmd.env("PATH", new_path); + + info!("{:?}", &cmd); + match sess.time("run_dwp", || cmd.output()) { + Ok(prog) if !prog.status.success() => { + sess.struct_err(&format!( + "linking dwarf objects with `{}` failed: {}", + LLVM_DWP_EXECUTABLE, prog.status + )) + .note(&format!("{:?}", &cmd)) + .note(&escape_stdout_stderr_string(&prog.stdout)) + .note(&escape_stdout_stderr_string(&prog.stderr)) + .emit(); + info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout)); + } + Ok(_) => {} + Err(e) => { + let dwp_not_found = e.kind() == io::ErrorKind::NotFound; + let mut err = if dwp_not_found { + sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE)) + } else { + sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE)) + }; + + err.note(&e.to_string()); + + if !dwp_not_found { + err.note(&format!("{:?}", &cmd)); + } + + err.emit(); + } + } +} + /// Create a dynamic library or executable. /// /// This will invoke the system linker/cc to create the resulting file. This links to all upstream @@ -661,7 +737,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( prog.status )) .note(&format!("{:?}", &cmd)) - .note(&escape_string(&output)) + .note(&escape_stdout_stderr_string(&output)) .emit(); // If MSVC's `link.exe` was expected but the return code @@ -714,8 +790,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( sess.abort_if_errors(); } - info!("linker stderr:\n{}", escape_string(&prog.stderr)); - info!("linker stdout:\n{}", escape_string(&prog.stdout)); + info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout)); } Err(e) => { let linker_not_found = e.kind() == io::ErrorKind::NotFound; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 615eeecf54ea..c84b87964b84 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -274,8 +274,19 @@ impl ModuleConfig { } } -pub type TargetMachineFactoryFn = - Arc Result<::TargetMachine, String> + Send + Sync>; +/// Configuration passed to the function returned by the `target_machine_factory`. +pub struct TargetMachineFactoryConfig { + /// Split DWARF is enabled in LLVM by checking that `TM.MCOptions.SplitDwarfFile` isn't empty, + /// so the path to the dwarf object has to be provided when we create the target machine. + /// This can be ignored by backends which do not need it for their Split DWARF support. + pub split_dwarf_file: Option, +} + +pub type TargetMachineFactoryFn = Arc< + dyn Fn(TargetMachineFactoryConfig) -> Result<::TargetMachine, String> + + Send + + Sync, +>; pub type ExportedSymbols = FxHashMap>>; @@ -303,6 +314,7 @@ pub struct CodegenContext { pub target_pointer_width: u32, pub target_arch: String, pub debuginfo: config::DebugInfo, + pub split_dwarf_kind: config::SplitDwarfKind, // Number of cgus excluding the allocator/metadata modules pub total_cgus: usize, @@ -619,6 +631,12 @@ fn produce_final_output_artifacts( } } + if let Some(ref path) = module.dwarf_object { + if !keep_numbered_objects { + remove(sess, path); + } + } + if let Some(ref path) = module.bytecode { if !keep_numbered_bitcode { remove(sess, path); @@ -841,6 +859,7 @@ fn execute_copy_from_cache_work_item( name: module.name, kind: ModuleKind::Regular, object, + dwarf_object: None, bytecode: None, })) } @@ -1019,6 +1038,7 @@ fn start_executing_work( target_pointer_width: tcx.sess.target.pointer_width, target_arch: tcx.sess.target.arch.clone(), debuginfo: tcx.sess.opts.debuginfo, + split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf, }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 8ec1eed44045..ee889d552412 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -64,13 +64,15 @@ impl ModuleCodegen { pub fn into_compiled_module( self, emit_obj: bool, + emit_dwarf_obj: bool, emit_bc: bool, outputs: &OutputFilenames, ) -> CompiledModule { let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); + let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name))); let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); - CompiledModule { name: self.name.clone(), kind: self.kind, object, bytecode } + CompiledModule { name: self.name.clone(), kind: self.kind, object, dwarf_object, bytecode } } } @@ -79,6 +81,7 @@ pub struct CompiledModule { pub name: String, pub kind: ModuleKind, pub object: Option, + pub dwarf_object: Option, pub bytecode: Option, } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b5354513dc2e..b3d4c6e3ec73 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -550,6 +550,7 @@ impl_stable_hash_via_hash!(OutputFilenames); pub const RLINK_EXT: &str = "rlink"; pub const RUST_CGU_EXT: &str = "rcgu"; +pub const DWARF_OBJECT_EXT: &str = "dwo"; impl OutputFilenames { pub fn new( @@ -583,7 +584,12 @@ impl OutputFilenames { self.temp_path_ext(extension, codegen_unit_name) } - /// Like temp_path, but also supports things where there is no corresponding + /// Like `temp_path`, but specifically for dwarf objects. + pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf { + self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name) + } + + /// Like `temp_path`, but also supports things where there is no corresponding /// OutputType, like noopt-bitcode or lto-bitcode. pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf { let mut extension = String::new(); @@ -610,6 +616,26 @@ impl OutputFilenames { path.set_extension(extension); path } + + /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF + /// mode is being used, which is the logic that this function is intended to encapsulate. + pub fn split_dwarf_file( + &self, + split_dwarf_kind: SplitDwarfKind, + cgu_name: Option<&str>, + ) -> Option { + let obj_out = self.temp_path(OutputType::Object, cgu_name); + let dwo_out = self.temp_path_dwo(cgu_name); + match split_dwarf_kind { + SplitDwarfKind::None => None, + // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes + // (pointing at the path which is being determined here). Use the path to the current + // object file. + SplitDwarfKind::Single => Some(obj_out), + // Split mode emits the DWARF into a different file, use that path. + SplitDwarfKind::Split => Some(dwo_out), + } + } } pub fn host_triple() -> &'static str { From 6c4350dc177a3cddb25fd4ac2d60bb5b52290176 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 8 Nov 2020 14:01:23 +0000 Subject: [PATCH 333/719] cg_clif: fix build with split dwarf This commit makes minor changes to the cranelift backend so that it can build given changes in cg_ssa for Split DWARF. Signed-off-by: David Wood --- compiler/rustc_codegen_cranelift/src/driver/aot.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 491d6cbbf796..78d6ff0cb001 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -75,6 +75,7 @@ fn emit_module( name, kind, object: Some(tmp_file), + dwarf_object: None, bytecode: None, }, work_product, @@ -111,6 +112,7 @@ fn reuse_workproduct_for_cgu( name: cgu.name().to_string(), kind: ModuleKind::Regular, object, + dwarf_object: None, bytecode: None, } } @@ -290,6 +292,7 @@ pub(super) fn run_aot( name: metadata_cgu_name, kind: ModuleKind::Metadata, object: Some(tmp_file), + dwarf_object: None, bytecode: None, }) } else { From 5f6c32af159c427fedb6fd25dfd9b6933affe068 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 8 Nov 2020 14:01:23 +0000 Subject: [PATCH 334/719] cg_clif: fix build with split dwarf This commit makes minor changes to the cranelift backend so that it can build given changes in cg_ssa for Split DWARF. Signed-off-by: David Wood --- src/driver/aot.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 491d6cbbf796..78d6ff0cb001 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -75,6 +75,7 @@ fn emit_module( name, kind, object: Some(tmp_file), + dwarf_object: None, bytecode: None, }, work_product, @@ -111,6 +112,7 @@ fn reuse_workproduct_for_cgu( name: cgu.name().to_string(), kind: ModuleKind::Regular, object, + dwarf_object: None, bytecode: None, } } @@ -290,6 +292,7 @@ pub(super) fn run_aot( name: metadata_cgu_name, kind: ModuleKind::Metadata, object: Some(tmp_file), + dwarf_object: None, bytecode: None, }) } else { From 2b22670bdf614374b9371a229e9bcf692f58c6b3 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 8 Nov 2020 17:26:59 +0000 Subject: [PATCH 335/719] tests: add run-make-fulldeps split-dwarf test This commit adds a run-make-fulldeps test which checks that a DWARF package file is emitted. Signed-off-by: David Wood --- src/test/run-make-fulldeps/split-dwarf/Makefile | 8 ++++++++ src/test/run-make-fulldeps/split-dwarf/foo.rs | 1 + 2 files changed, 9 insertions(+) create mode 100644 src/test/run-make-fulldeps/split-dwarf/Makefile create mode 100644 src/test/run-make-fulldeps/split-dwarf/foo.rs diff --git a/src/test/run-make-fulldeps/split-dwarf/Makefile b/src/test/run-make-fulldeps/split-dwarf/Makefile new file mode 100644 index 000000000000..e1a78e2edfc4 --- /dev/null +++ b/src/test/run-make-fulldeps/split-dwarf/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk + +# only-linux + +all: + $(RUSTC) -Z split-dwarf=split foo.rs + rm $(TMPDIR)/foo.dwp + rm $(TMPDIR)/$(call BIN,foo) diff --git a/src/test/run-make-fulldeps/split-dwarf/foo.rs b/src/test/run-make-fulldeps/split-dwarf/foo.rs new file mode 100644 index 000000000000..f328e4d9d04c --- /dev/null +++ b/src/test/run-make-fulldeps/split-dwarf/foo.rs @@ -0,0 +1 @@ +fn main() {} From 99ad915e32744eb771e9a0968bf7d0d1f52a9a07 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 8 Nov 2020 17:27:33 +0000 Subject: [PATCH 336/719] compiletest: add split dwarf compare mode This commit adds a Split DWARF compare mode to compiletest so that debuginfo tests are also tested using Split DWARF in split mode (and manually in single mode). Signed-off-by: David Wood --- compiler/rustc_codegen_ssa/src/back/link.rs | 7 +++++++ src/bootstrap/test.rs | 7 ++++++- src/tools/compiletest/src/common.rs | 6 ++++++ src/tools/compiletest/src/header.rs | 2 ++ src/tools/compiletest/src/runtest.rs | 6 ++++++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 123d1ae55fb9..ccd4d103ddb7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1037,6 +1037,13 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { return false; } + // Single mode keeps debuginfo in the same object file, but in such a way that it it skipped + // by the linker - so it's expected that when codegen units are linked together that this + // debuginfo would be lost without keeping around the temps. + if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Single { + return true; + } + // If we're on OSX then the equivalent of split dwarf is turned on by // default. The final executable won't actually have any debug information // except it'll have pointers to elsewhere. Historically we've always run diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 78b5de7897d1..b99692e8ba5b 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -897,7 +897,12 @@ default_test!(Incremental { suite: "incremental" }); -default_test!(Debuginfo { path: "src/test/debuginfo", mode: "debuginfo", suite: "debuginfo" }); +default_test_with_compare_mode!(Debuginfo { + path: "src/test/debuginfo", + mode: "debuginfo", + suite: "debuginfo", + compare_mode: "split-dwarf" +}); host_test!(UiFullDeps { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" }); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 55d25fa7c52c..80fbb06b9469 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -127,6 +127,8 @@ pub enum CompareMode { Nll, Polonius, Chalk, + SplitDwarf, + SplitDwarfSingle, } impl CompareMode { @@ -135,6 +137,8 @@ impl CompareMode { CompareMode::Nll => "nll", CompareMode::Polonius => "polonius", CompareMode::Chalk => "chalk", + CompareMode::SplitDwarf => "split-dwarf", + CompareMode::SplitDwarfSingle => "split-dwarf-single", } } @@ -143,6 +147,8 @@ impl CompareMode { "nll" => CompareMode::Nll, "polonius" => CompareMode::Polonius, "chalk" => CompareMode::Chalk, + "split-dwarf" => CompareMode::SplitDwarf, + "split-dwarf-single" => CompareMode::SplitDwarfSingle, x => panic!("unknown --compare-mode option: {}", x), } } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 59f64e7df0f4..a1be0a19f685 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -852,6 +852,8 @@ impl Config { Some(CompareMode::Nll) => name == "compare-mode-nll", Some(CompareMode::Polonius) => name == "compare-mode-polonius", Some(CompareMode::Chalk) => name == "compare-mode-chalk", + Some(CompareMode::SplitDwarf) => name == "compare-mode-split-dwarf", + Some(CompareMode::SplitDwarfSingle) => name == "compare-mode-split-dwarf-single", None => false, } || (cfg!(debug_assertions) && name == "debug") || diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 7af0d91271b0..828c4e89f0b1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2017,6 +2017,12 @@ impl<'test> TestCx<'test> { Some(CompareMode::Chalk) => { rustc.args(&["-Zchalk"]); } + Some(CompareMode::SplitDwarf) => { + rustc.args(&["-Zsplit-dwarf=split"]); + } + Some(CompareMode::SplitDwarfSingle) => { + rustc.args(&["-Zsplit-dwarf=single"]); + } None => {} } From ee073b5ec54a13b393071298acc54e1fd28cfcdf Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 8 Nov 2020 17:17:37 +0000 Subject: [PATCH 337/719] cg_llvm: split dwarf filename and comp dir llvm-dwp concatenates `DW_AT_comp_dir` with `DW_AT_GNU_dwo_name` (only when `DW_AT_comp_dir` exists), which can result in it failing to find the DWARF object files. In earlier testing, `DW_AT_comp_dir` wasn't present in the final object and the current directory was the output directory. When running tests through compiletest, the working directory of the compilation is different from output directory and that resulted in `DW_AT_comp_dir` being in the object file (and set to the current working directory, rather than the output directory), and `DW_AT_GNU_dwo_name` being set to the full path (rather than just the filename), so llvm-dwp was failing. This commit changes the compilation directory provided to LLVM to match the output directory, where DWARF objects are output; and ensures that only the filename is used for `DW_AT_GNU_dwo_name`. Signed-off-by: David Wood --- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 +- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 10 ++++++---- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_session/src/config.rs | 13 ++++++++++++- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 834fc02c48ab..29415973ed07 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -734,7 +734,7 @@ pub unsafe fn optimize_thin_module( let module_name = &thin_module.shared.module_names[thin_module.idx]; let split_dwarf_file = cgcx .output_filenames - .split_dwarf_file(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap())); + .split_dwarf_filename(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap())); let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file }; let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index ef99c87053c7..3fda1e26dae9 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -95,7 +95,7 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm: pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine { let split_dwarf_file = tcx .output_filenames(LOCAL_CRATE) - .split_dwarf_file(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name)); + .split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name)); let config = TargetMachineFactoryConfig { split_dwarf_file }; target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))(config) .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise()) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index a9eff59b6aff..fa285f3488f8 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -993,12 +993,14 @@ pub fn compile_unit_metadata( let producer = format!("clang LLVM ({})", rustc_producer); let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); - let work_dir = tcx.sess.working_dir.0.to_string_lossy(); let flags = "\0"; + + let out_dir = &tcx.output_filenames(LOCAL_CRATE).out_directory; let split_name = tcx .output_filenames(LOCAL_CRATE) - .split_dwarf_file(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name)) + .split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name)) .unwrap_or_default(); + let out_dir = out_dir.to_str().unwrap(); let split_name = split_name.to_str().unwrap(); // FIXME(#60020): @@ -1024,8 +1026,8 @@ pub fn compile_unit_metadata( debug_context.builder, name_in_debuginfo.as_ptr().cast(), name_in_debuginfo.len(), - work_dir.as_ptr().cast(), - work_dir.len(), + out_dir.as_ptr().cast(), + out_dir.len(), llvm::ChecksumKind::None, ptr::null(), 0, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index a5f125d114d2..a58c2fbd8ab2 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -356,7 +356,7 @@ impl ModuleLlvm { let split_dwarf_file = cgcx .output_filenames - .split_dwarf_file(cgcx.split_dwarf_kind, Some(name.to_str().unwrap())); + .split_dwarf_filename(cgcx.split_dwarf_kind, Some(name.to_str().unwrap())); let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file }; let tm = match (cgcx.tm_factory)(tm_factory_config) { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b3d4c6e3ec73..c20b11656b22 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -617,9 +617,20 @@ impl OutputFilenames { path } + /// Returns the name of the Split DWARF file - this can differ depending on which Split DWARF + /// mode is being used, which is the logic that this function is intended to encapsulate. + pub fn split_dwarf_filename( + &self, + split_dwarf_kind: SplitDwarfKind, + cgu_name: Option<&str>, + ) -> Option { + self.split_dwarf_path(split_dwarf_kind, cgu_name) + .map(|path| path.strip_prefix(&self.out_directory).unwrap_or(&path).to_path_buf()) + } + /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF /// mode is being used, which is the logic that this function is intended to encapsulate. - pub fn split_dwarf_file( + pub fn split_dwarf_path( &self, split_dwarf_kind: SplitDwarfKind, cgu_name: Option<&str>, From cfc38d2d0892f0842dd50cd0bd889e9ae1ea7508 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Mon, 7 Dec 2020 12:34:27 +0100 Subject: [PATCH 338/719] Take into account negative impls in "trait item not found" suggestions --- .../rustc_typeck/src/check/method/suggest.rs | 108 +++++++++++++----- .../explicitly-unimplemented-error-message.rs | 53 +++++++++ ...licitly-unimplemented-error-message.stderr | 60 ++++++++++ 3 files changed, 193 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs create mode 100644 src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 7ed2933c08bb..0f6253493cf6 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -12,6 +12,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::hir::map as hir_map; +use rustc_middle::ty::fast_reject::simplify_type; use rustc_middle::ty::print::with_crate_prefix; use rustc_middle::ty::{ self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -1074,19 +1075,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { "items from traits can only be used if the trait is implemented and in scope" }); + let candidates_len = candidates.len(); let message = |action| { format!( "the following {traits_define} an item `{name}`, perhaps you need to {action} \ {one_of_them}:", traits_define = - if candidates.len() == 1 { "trait defines" } else { "traits define" }, + if candidates_len == 1 { "trait defines" } else { "traits define" }, action = action, - one_of_them = if candidates.len() == 1 { "it" } else { "one of them" }, + one_of_them = if candidates_len == 1 { "it" } else { "one of them" }, name = item_name, ) }; // Obtain the span for `param` and use it for a structured suggestion. - let mut suggested = false; if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_typeck_results) { @@ -1147,7 +1148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - suggested = true; + return; } Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., bounds, _), @@ -1167,45 +1168,96 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }), Applicability::MaybeIncorrect, ); - suggested = true; + return; } _ => {} } } } - if !suggested { - let action = if let Some(param) = param_type { - format!("restrict type parameter `{}` with", param) - } else { - // FIXME: it might only need to be imported into scope, not implemented. - "implement".to_string() - }; - let mut use_note = true; - if let [trait_info] = &candidates[..] { - if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) { - err.span_note( - self.tcx.sess.source_map().guess_head_span(span), - &format!( - "`{}` defines an item `{}`, perhaps you need to {} it", - self.tcx.def_path_str(trait_info.def_id), - item_name, - action - ), - ); - use_note = false + let (potential_candidates, explicitly_negative) = if param_type.is_some() { + // FIXME: Even though negative bounds are not implemented, we could maybe handle + // cases where a positive bound implies a negative impl. + (candidates, Vec::new()) + } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, true) { + let mut potential_candidates = Vec::new(); + let mut explicitly_negative = Vec::new(); + for candidate in candidates { + // Check if there's a negative impl of `candidate` for `rcvr_ty` + if self + .tcx + .all_impls(candidate.def_id) + .filter(|imp_did| { + self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative + }) + .any(|imp_did| { + let imp = self.tcx.impl_trait_ref(imp_did).unwrap(); + let imp_simp = simplify_type(self.tcx, imp.self_ty(), true); + imp_simp.map(|s| s == simp_rcvr_ty).unwrap_or(false) + }) + { + explicitly_negative.push(candidate); + } else { + potential_candidates.push(candidate); } } - if use_note { + (potential_candidates, explicitly_negative) + } else { + // We don't know enough about `recv_ty` to make proper suggestions. + (candidates, Vec::new()) + }; + + let action = if let Some(param) = param_type { + format!("restrict type parameter `{}` with", param) + } else { + // FIXME: it might only need to be imported into scope, not implemented. + "implement".to_string() + }; + match &potential_candidates[..] { + [] => {} + [trait_info] if trait_info.def_id.is_local() => { + let span = self.tcx.hir().span_if_local(trait_info.def_id).unwrap(); + err.span_note( + self.tcx.sess.source_map().guess_head_span(span), + &format!( + "`{}` defines an item `{}`, perhaps you need to {} it", + self.tcx.def_path_str(trait_info.def_id), + item_name, + action + ), + ); + } + trait_infos => { let mut msg = message(action); - for (i, trait_info) in candidates.iter().enumerate() { + for (i, trait_info) in trait_infos.iter().enumerate() { msg.push_str(&format!( "\ncandidate #{}: `{}`", i + 1, self.tcx.def_path_str(trait_info.def_id), )); } - err.note(&msg[..]); + err.note(&msg); + } + } + match &explicitly_negative[..] { + [] => {} + [trait_info] => { + let msg = format!( + "the trait `{}` defines an item `{}`, but is explicitely unimplemented", + self.tcx.def_path_str(trait_info.def_id), + item_name + ); + err.note(&msg); + } + trait_infos => { + let mut msg = format!( + "the following traits define an item `{}`, but are explicitely unimplemented:", + item_name + ); + for trait_info in trait_infos { + msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id))); + } + err.note(&msg); } } } diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs new file mode 100644 index 000000000000..3e336933937d --- /dev/null +++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs @@ -0,0 +1,53 @@ +// This tests issue #79683: note in the error message that the trait is +// explicitely unimplemented instead of suggesting to implement it. + +#![feature(negative_impls)] + +struct Qux; +//~^ NOTE method `clone` not found for this +//~^^ NOTE method `foo` not found for this + +impl !Clone for Qux {} + +trait Bar { + fn bar(&self); +} + +impl !Bar for u32 {} + +trait Foo { + fn foo(&self); +} +//~^^^ NOTE `Foo` defines an item `foo`, perhaps you need to implement it + +trait FooBar { + fn foo(&self); +} + +impl !Foo for Qux {} + +impl !FooBar for Qux {} + +impl !FooBar for u32 {} + +fn main() { + Qux.clone(); + //~^ ERROR no method named `clone` found for struct `Qux` + //~| NOTE method not found in `Qux` + //~| NOTE `Clone` defines an item `clone`, but is explicitely unimplemented + + 0_u32.bar(); + //~^ ERROR no method named `bar` found for type `u32` + //~| NOTE method not found in `u32` + //~| NOTE `Bar` defines an item `bar`, but is explicitely unimplemented + + Qux.foo(); + //~^ ERROR no method named `foo` found for struct `Qux` + //~| NOTE method not found in `Qux` + //~| NOTE the following traits define an item `foo`, but are explicitely unimplemented + + 0_u32.foo(); + //~^ ERROR no method named `foo` found for type `u32` + //~| NOTE method not found in `u32` + //~| NOTE `FooBar` defines an item `foo`, but is explicitely unimplemented +} diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr new file mode 100644 index 000000000000..d39daaba206d --- /dev/null +++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr @@ -0,0 +1,60 @@ +error[E0599]: no method named `clone` found for struct `Qux` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:34:9 + | +LL | struct Qux; + | ----------- method `clone` not found for this +... +LL | Qux.clone(); + | ^^^^^ method not found in `Qux` + | + ::: $SRC_DIR/core/src/clone.rs:LL:COL + | +LL | fn clone(&self) -> Self; + | ----- + | | + | the method is available for `Arc` here + | the method is available for `Rc` here + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the trait `Clone` defines an item `clone`, but is explicitely unimplemented + +error[E0599]: no method named `bar` found for type `u32` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:39:11 + | +LL | 0_u32.bar(); + | ^^^ method not found in `u32` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the trait `Bar` defines an item `bar`, but is explicitely unimplemented + +error[E0599]: no method named `foo` found for struct `Qux` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:44:9 + | +LL | struct Qux; + | ----------- method `foo` not found for this +... +LL | Qux.foo(); + | ^^^ method not found in `Qux` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `foo`, but are explicitely unimplemented: + Foo + FooBar + +error[E0599]: no method named `foo` found for type `u32` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:49:11 + | +LL | 0_u32.foo(); + | ^^^ method not found in `u32` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Foo` defines an item `foo`, perhaps you need to implement it + --> $DIR/explicitly-unimplemented-error-message.rs:18:1 + | +LL | trait Foo { + | ^^^^^^^^^ + = note: the trait `FooBar` defines an item `foo`, but is explicitely unimplemented + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. From ffa7a01a18589e335e5199fbeab427571ff0a8d2 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 15 Dec 2020 23:51:38 -0500 Subject: [PATCH 339/719] Add more timing info to rustdoc --- src/librustdoc/clean/utils.rs | 11 ++++--- src/librustdoc/passes/collect_trait_impls.rs | 34 +++++++++++--------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index f8743a4c42e9..54bb93fa4647 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -551,10 +551,13 @@ crate fn get_auto_trait_and_blanket_impls( ty: Ty<'tcx>, param_env_def_id: DefId, ) -> impl Iterator { - AutoTraitFinder::new(cx) - .get_auto_trait_impls(ty, param_env_def_id) - .into_iter() - .chain(BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id)) + let auto_impls = cx.sess().time("get_auto_trait_impls", || { + AutoTraitFinder::new(cx).get_auto_trait_impls(ty, param_env_def_id) + }); + let blanket_impls = cx.sess().time("get_blanket_impls", || { + BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id) + }); + auto_impls.into_iter().chain(blanket_impls) } crate fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 1e9bc67de04b..60fcbe748727 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -16,13 +16,13 @@ crate const COLLECT_TRAIT_IMPLS: Pass = Pass { crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { let mut synth = SyntheticImplCollector::new(cx); - let mut krate = synth.fold_crate(krate); + let mut krate = cx.sess().time("collect_synthetic_impls", || synth.fold_crate(krate)); let prims: FxHashSet = krate.primitives.iter().map(|p| p.1).collect(); let crate_items = { let mut coll = ItemCollector::new(); - krate = coll.fold_crate(krate); + krate = cx.sess().time("collect_items_for_trait_impls", || coll.fold_crate(krate)); coll.items }; @@ -39,16 +39,18 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { // Also try to inline primitive impls from other crates. for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() { if !def_id.is_local() { - inline::build_impl(cx, None, def_id, None, &mut new_items); + cx.sess().time("build_primitive_trait_impl", || { + inline::build_impl(cx, None, def_id, None, &mut new_items); - // FIXME(eddyb) is this `doc(hidden)` check needed? - if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) { - let self_ty = cx.tcx.type_of(def_id); - let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id); - let mut renderinfo = cx.renderinfo.borrow_mut(); + // FIXME(eddyb) is this `doc(hidden)` check needed? + if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) { + let self_ty = cx.tcx.type_of(def_id); + let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id); + let mut renderinfo = cx.renderinfo.borrow_mut(); - new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id))); - } + new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id))); + } + }) } } @@ -151,11 +153,13 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { if i.is_struct() || i.is_enum() || i.is_union() { // FIXME(eddyb) is this `doc(hidden)` check needed? if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) { - self.impls.extend(get_auto_trait_and_blanket_impls( - self.cx, - self.cx.tcx.type_of(i.def_id), - i.def_id, - )); + self.cx.sess().time("get_auto_trait_and_blanket_synthetic_impls", || { + self.impls.extend(get_auto_trait_and_blanket_impls( + self.cx, + self.cx.tcx.type_of(i.def_id), + i.def_id, + )); + }); } } From 68932060868cda5b14f8e382d28df09905572176 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 16 Dec 2020 09:10:40 -0800 Subject: [PATCH 340/719] Revert "Auto merge of #78790 - Gankra:rust-src-vendor, r=Mark-Simulacrum" This reverts commit 7afc5172305cdae588a0318ce545749cf4ed947d, reversing changes made to d4ea0b3e46a0303d5802b632e88ba1ba84d9d16f. --- src/bootstrap/dist.rs | 26 ++------------------------ src/bootstrap/lib.rs | 21 --------------------- 2 files changed, 2 insertions(+), 45 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 25905895116f..393715e5561e 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1043,30 +1043,6 @@ impl Step for Src { builder.copy(&builder.src.join(file), &dst_src.join(file)); } - // libtest includes std and everything else, so vendoring it - // creates exactly what's needed for `cargo -Zbuild-std` or any - // other analysis of the stdlib's source. Cargo also needs help - // finding the lock, so we copy it to libtest temporarily. - // - // Note that this requires std to only have one version of each - // crate. e.g. two versions of getopts won't be patchable. - let dst_libtest = dst_src.join("library/test"); - let dst_vendor = dst_src.join("vendor"); - let root_lock = dst_src.join("Cargo.lock"); - let temp_lock = dst_libtest.join("Cargo.lock"); - - // `cargo vendor` will delete everything from the lockfile that - // isn't used by libtest, so we need to not use any links! - builder.really_copy(&root_lock, &temp_lock); - - let mut cmd = Command::new(&builder.initial_cargo); - cmd.arg("vendor").arg(dst_vendor).current_dir(&dst_libtest); - builder.info("Dist src"); - let _time = timeit(builder); - builder.run(&mut cmd); - - builder.remove(&temp_lock); - // Create source tarball in rust-installer format let mut cmd = rust_installer(builder); cmd.arg("generate") @@ -1083,6 +1059,8 @@ impl Step for Src { .arg("--component-name=rust-src") .arg("--legacy-manifest-dirs=rustlib,cargo"); + builder.info("Dist src"); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 06ccd72186dd..ece9bdc7a649 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1182,27 +1182,6 @@ impl Build { paths } - /// Copies a file from `src` to `dst` and doesn't use links, so - /// that the copy can be modified without affecting the original. - pub fn really_copy(&self, src: &Path, dst: &Path) { - if self.config.dry_run { - return; - } - self.verbose_than(1, &format!("Copy {:?} to {:?}", src, dst)); - if src == dst { - return; - } - let _ = fs::remove_file(&dst); - let metadata = t!(src.symlink_metadata()); - if let Err(e) = fs::copy(src, dst) { - panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e) - } - t!(fs::set_permissions(dst, metadata.permissions())); - let atime = FileTime::from_last_access_time(&metadata); - let mtime = FileTime::from_last_modification_time(&metadata); - t!(filetime::set_file_times(dst, atime, mtime)); - } - /// Copies a file from `src` to `dst` pub fn copy(&self, src: &Path, dst: &Path) { if self.config.dry_run { From be2c8f2d436d777cbdac73f6dd238ea135048ff5 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 16 Dec 2020 18:32:29 +0100 Subject: [PATCH 341/719] Update zip for better codegen, see discussion --- library/core/src/array/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 02b771863e92..9de87922f54f 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -481,8 +481,8 @@ impl [T; N] { use crate::mem::MaybeUninit; let mut dst = MaybeUninit::uninit_array::(); - for ((lhs, rhs), dst) in IntoIter::new(self).zip(IntoIter::new(rhs)).zip(&mut dst) { - dst.write((lhs, rhs)); + for (i, (lhs, rhs)) in IntoIter::new(self).zip(IntoIter::new(rhs)).enumerate() { + dst[i].write((lhs, rhs)); } // FIXME: Convert to crate::mem::transmute once it works with generics. // unsafe { crate::mem::transmute::<[MaybeUninit; N], [U; N]>(dst) } From 1e1ca28f395b4c43cc2781676dafffd4f3269989 Mon Sep 17 00:00:00 2001 From: bstrie Date: Wed, 9 Dec 2020 18:26:42 -0500 Subject: [PATCH 342/719] Allow `since="TBD"` for rustc_deprecated --- compiler/rustc_middle/src/middle/stability.rs | 75 ++++++++++--------- compiler/rustc_passes/src/stability.rs | 44 ++++++----- src/librustdoc/html/render/mod.rs | 6 +- src/test/rustdoc/rustc_deprecated-future.rs | 12 ++- .../rustc_deprecation-in-future.rs | 9 ++- .../rustc_deprecation-in-future.stderr | 16 ++-- .../stability-attribute-sanity.rs | 6 +- .../stability-attribute-sanity.stderr | 12 ++- 8 files changed, 111 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 47c140e0b188..4f08057a7e32 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -132,37 +132,37 @@ pub fn report_unstable( /// Checks whether an item marked with `deprecated(since="X")` is currently /// deprecated (i.e., whether X is not greater than the current rustc version). pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool { - let since = if let Some(since) = since { - if is_since_rustc_version { - since - } else { - // We assume that the deprecation is in effect if it's not a - // rustc version. - return true; - } - } else { - // If since attribute is not set, then we're definitely in effect. - return true; - }; fn parse_version(ver: &str) -> Vec { // We ignore non-integer components of the version (e.g., "nightly"). ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect() } - if let Some(rustc) = option_env!("CFG_RELEASE") { - let since: Vec = parse_version(&since); - let rustc: Vec = parse_version(rustc); - // We simply treat invalid `since` attributes as relating to a previous - // Rust version, thus always displaying the warning. - if since.len() != 3 { - return true; - } - since <= rustc - } else { - // By default, a deprecation warning applies to - // the current version of the compiler. - true + if !is_since_rustc_version { + // The `since` field doesn't have semantic purpose in the stable `deprecated` + // attribute, only in `rustc_deprecated`. + return true; } + + if let Some(since) = since { + if since == "TBD" { + return false; + } + + if let Some(rustc) = option_env!("CFG_RELEASE") { + let since: Vec = parse_version(&since); + let rustc: Vec = parse_version(rustc); + // We simply treat invalid `since` attributes as relating to a previous + // Rust version, thus always displaying the warning. + if since.len() != 3 { + return true; + } + return since <= rustc; + } + }; + + // Assume deprecation is in effect if "since" field is missing + // or if we can't determine the current Rust version. + true } pub fn deprecation_suggestion( @@ -182,19 +182,24 @@ pub fn deprecation_suggestion( } pub fn deprecation_message(depr: &Deprecation, kind: &str, path: &str) -> (String, &'static Lint) { - let (message, lint) = if deprecation_in_effect( - depr.is_since_rustc_version, - depr.since.map(Symbol::as_str).as_deref(), - ) { + let since = depr.since.map(Symbol::as_str); + let (message, lint) = if deprecation_in_effect(depr.is_since_rustc_version, since.as_deref()) { (format!("use of deprecated {} `{}`", kind, path), DEPRECATED) } else { ( - format!( - "use of {} `{}` that will be deprecated in future version {}", - kind, - path, - depr.since.unwrap() - ), + if since.as_deref() == Some("TBD") { + format!( + "use of {} `{}` that will be deprecated in a future Rust version", + kind, path + ) + } else { + format!( + "use of {} `{}` that will be deprecated in future version {}", + kind, + path, + since.unwrap() + ) + }, DEPRECATED_IN_FUTURE, ) }; diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index f6bbbd80bf1e..3c2462aab26b 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -182,28 +182,32 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { for (dep_v, stab_v) in 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 => { - self.tcx.sess.span_err( - item_sp, - "An API can't be stabilized \ - after it is deprecated", - ); + match stab_v.parse::() { + Err(_) => { + self.tcx.sess.span_err(item_sp, "Invalid stability version found"); + break; + } + Ok(stab_vp) => match dep_v.parse::() { + Ok(dep_vp) => match dep_vp.cmp(&stab_vp) { + Ordering::Less => { + self.tcx.sess.span_err( + item_sp, + "An API can't be stabilized after it is deprecated", + ); + break; + } + Ordering::Equal => continue, + Ordering::Greater => break, + }, + Err(_) => { + if dep_v != "TBD" { + self.tcx + .sess + .span_err(item_sp, "Invalid deprecation version found"); + } break; } - Ordering::Equal => continue, - Ordering::Greater => break, - } - } else { - // Act like it isn't less because the question is now nonsensical, - // and this makes us not do anything else interesting. - self.tcx.sess.span_err( - item_sp, - "Invalid stability or deprecation \ - version found", - ); - break; + }, } } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 88c5e94c2767..00294878fe5f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2279,7 +2279,11 @@ fn short_item_info(item: &clean::Item, cx: &Context, parent: Option<&clean::Item let mut message = if let Some(since) = since { let since = &since.as_str(); if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) { - format!("Deprecating in {}", Escape(since)) + if *since == "TBD" { + format!("Deprecating in a future Rust version") + } else { + format!("Deprecating in {}", Escape(since)) + } } else { format!("Deprecated since {}", Escape(since)) } diff --git a/src/test/rustdoc/rustc_deprecated-future.rs b/src/test/rustdoc/rustc_deprecated-future.rs index 3133775706b8..95a767a8329a 100644 --- a/src/test/rustdoc/rustc_deprecated-future.rs +++ b/src/test/rustdoc/rustc_deprecated-future.rs @@ -4,8 +4,16 @@ // @has rustc_deprecated_future/index.html '//*[@class="stab deprecated"]' \ // 'Deprecation planned' -// @has rustc_deprecated_future/struct.S.html '//*[@class="stab deprecated"]' \ +// @has rustc_deprecated_future/struct.S1.html '//*[@class="stab deprecated"]' \ // 'Deprecating in 99.99.99: effectively never' #[rustc_deprecated(since = "99.99.99", reason = "effectively never")] #[stable(feature = "rustc_deprecated-future-test", since = "1.0.0")] -pub struct S; +pub struct S1; + +// @has rustc_deprecated_future/index.html '//*[@class="stab deprecated"]' \ +// 'Deprecation planned' +// @has rustc_deprecated_future/struct.S2.html '//*[@class="stab deprecated"]' \ +// 'Deprecating in a future Rust version: literally never' +#[rustc_deprecated(since = "TBD", reason = "literally never")] +#[stable(feature = "rustc_deprecated-future-test", since = "1.0.0")] +pub struct S2; diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.rs b/src/test/ui/deprecation/rustc_deprecation-in-future.rs index 6a619bcc49c2..11f7960b7578 100644 --- a/src/test/ui/deprecation/rustc_deprecation-in-future.rs +++ b/src/test/ui/deprecation/rustc_deprecation-in-future.rs @@ -8,8 +8,13 @@ #[rustc_deprecated(since = "99.99.99", reason = "effectively never")] #[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")] -pub struct S; +pub struct S1; + +#[rustc_deprecated(since = "TBD", reason = "literally never")] +#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")] +pub struct S2; fn main() { - let _ = S; //~ ERROR use of unit struct `S` that will be deprecated in future version 99.99.99: effectively never + let _ = S1; //~ ERROR use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never + let _ = S2; //~ ERROR use of unit struct `S2` that will be deprecated in a future Rust version: literally never } diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr b/src/test/ui/deprecation/rustc_deprecation-in-future.stderr index e4f50d10dadd..b5a7dd3c28da 100644 --- a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr +++ b/src/test/ui/deprecation/rustc_deprecation-in-future.stderr @@ -1,8 +1,8 @@ -error: use of unit struct `S` that will be deprecated in future version 99.99.99: effectively never - --> $DIR/rustc_deprecation-in-future.rs:14:13 +error: use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never + --> $DIR/rustc_deprecation-in-future.rs:18:13 | -LL | let _ = S; - | ^ +LL | let _ = S1; + | ^^ | note: the lint level is defined here --> $DIR/rustc_deprecation-in-future.rs:3:9 @@ -10,5 +10,11 @@ note: the lint level is defined here LL | #![deny(deprecated_in_future)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: use of unit struct `S2` that will be deprecated in a future Rust version: literally never + --> $DIR/rustc_deprecation-in-future.rs:19:13 + | +LL | let _ = S2; + | ^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.rs b/src/test/ui/stability-attribute/stability-attribute-sanity.rs index abd603b356ee..0c40f8ae1c67 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.rs +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.rs @@ -63,7 +63,11 @@ fn multiple3() { } #[rustc_const_unstable(feature = "c", issue = "none")] #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels pub const fn multiple4() { } -//~^ ERROR Invalid stability or deprecation version found +//~^ ERROR Invalid stability version found + +#[stable(feature = "a", since = "1.0.0")] +#[rustc_deprecated(since = "invalid", reason = "text")] +fn invalid_deprecation_version() {} //~ ERROR Invalid deprecation version found #[rustc_deprecated(since = "a", reason = "text")] fn deprecated_without_unstable_or_stable() { } diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index 97089f7df526..ee9a93359f03 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -96,19 +96,25 @@ error[E0544]: multiple stability levels LL | #[rustc_const_unstable(feature = "d", issue = "none")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Invalid stability or deprecation version found +error: Invalid stability version found --> $DIR/stability-attribute-sanity.rs:65:1 | LL | pub const fn multiple4() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: Invalid deprecation version found + --> $DIR/stability-attribute-sanity.rs:70:1 + | +LL | fn invalid_deprecation_version() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute - --> $DIR/stability-attribute-sanity.rs:68:1 + --> $DIR/stability-attribute-sanity.rs:72:1 | LL | #[rustc_deprecated(since = "a", reason = "text")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 18 previous errors +error: aborting due to 19 previous errors Some errors have detailed explanations: E0539, E0541, E0546, E0550. For more information about an error, try `rustc --explain E0539`. From 6132e21961be89d1b884dd03af0aef02347328ba Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 16 Dec 2020 19:16:36 +0000 Subject: [PATCH 343/719] bootstrap: include llvm-dwp in CI LLVM This commit includes the `llvm-dwp` tool in the CI LLVM (which rustc developers can download instead of building LLVM locally) - `llvm-dwp` is required by Split DWARF which landed in PR #77117. Signed-off-by: David Wood --- src/bootstrap/dist.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 25905895116f..b1bb97cf83ba 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2553,6 +2553,7 @@ impl Step for RustDev { install_bin("llvm-profdata"); install_bin("llvm-bcanalyzer"); install_bin("llvm-cov"); + install_bin("llvm-dwp"); builder.install(&builder.llvm_filecheck(target), &dst_bindir, 0o755); // Copy the include directory as well; needed mostly to build From ec078155f140de8bd838596ac0d5d786d988d493 Mon Sep 17 00:00:00 2001 From: Ondrej Perutka Date: Wed, 16 Dec 2020 20:34:21 +0100 Subject: [PATCH 344/719] Fix failing build of std on armv5te-unknown-linux-uclibceabi due to missing cmsg_len_zero --- library/std/src/sys/unix/ext/net/ancillary.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 2c91ba70dd0b..0964b6335aa7 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -360,7 +360,11 @@ impl<'a> AncillaryData<'a> { fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { unsafe { cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + if #[cfg(any( + target_os = "android", + all(target_os = "linux", target_env = "gnu"), + all(target_os = "linux", target_env = "uclibc"), + ))] { let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t; } else if #[cfg(any( target_os = "dragonfly", From baa5e47106cd3544f4eb06317eea1a174d6e2341 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 16 Dec 2020 21:12:10 +0100 Subject: [PATCH 345/719] Update doc comment Co-authored-by: Mara Bos --- library/core/src/array/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 9de87922f54f..6791f0e74442 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -464,8 +464,11 @@ impl [T; N] { } /// 'Zips up' two arrays into a single array of pairs. - /// `zip()` returns a new array where every element is a tuple where the first element comes from the first array, and the second element comes from the second array. - /// In other words, it zips two arrays together, into a single one. + /// + /// `zip()` returns a new array where every element is a tuple where the + /// first element comes from the first array, and the second element comes + /// from the second array. In other words, it zips two arrays together, + /// into a single one. /// /// # Examples /// From 50d221c9244c87f22a791af86cff8f3139523dbf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 16 Dec 2020 17:21:08 +0100 Subject: [PATCH 346/719] Replace String with Symbol where possible --- src/librustdoc/clean/auto_trait.rs | 11 ++- src/librustdoc/clean/inline.rs | 8 +-- src/librustdoc/clean/mod.rs | 67 +++++++++---------- src/librustdoc/clean/simplify.rs | 5 +- src/librustdoc/clean/types.rs | 20 +++--- src/librustdoc/clean/utils.rs | 39 ++++++----- src/librustdoc/html/format.rs | 13 ++-- src/librustdoc/html/render/cache.rs | 2 +- src/librustdoc/json/conversions.rs | 14 ++-- .../passes/collect_intra_doc_links.rs | 13 ++-- src/librustdoc/passes/doc_test_lints.rs | 23 ++++--- 11 files changed, 109 insertions(+), 106 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 7a61a169c2bd..72603f00697e 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -333,10 +333,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { match br { // We only care about named late bound regions, as we need to add them // to the 'for<>' section - ty::BrNamed(_, name) => Some(GenericParamDef { - name: name.to_string(), - kind: GenericParamDefKind::Lifetime, - }), + ty::BrNamed(_, name) => { + Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime }) + } _ => None, } }) @@ -569,7 +568,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } WherePredicate::EqPredicate { lhs, rhs } => { match lhs { - Type::QPath { name: ref left_name, ref self_type, ref trait_ } => { + Type::QPath { name: left_name, ref self_type, ref trait_ } => { let ty = &*self_type; match **trait_ { Type::ResolvedPath { @@ -580,7 +579,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } => { let mut new_trait_path = trait_path.clone(); - if self.is_fn_ty(tcx, trait_) && left_name == FN_OUTPUT_NAME { + if self.is_fn_ty(tcx, trait_) && left_name == sym::Output { ty_to_fn .entry(*ty.clone()) .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d358a7a369d8..7bb8e5e8cfcb 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -12,7 +12,7 @@ use rustc_metadata::creader::LoadedMacro; use rustc_middle::ty; use rustc_mir::const_eval::is_min_const_fn; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use crate::clean::{self, Attributes, GetDefId, ToSource, TypeKind}; @@ -583,7 +583,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: for pred in &mut g.where_predicates { match *pred { clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref mut bounds } - if *s == "Self" => + if *s == kw::SelfUpper => { bounds.retain(|bound| match *bound { clean::GenericBound::TraitBound( @@ -606,7 +606,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: name: ref _name, }, ref bounds, - } => !(bounds.is_empty() || *s == "Self" && did == trait_did), + } => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did), _ => true, }); g @@ -621,7 +621,7 @@ fn separate_supertrait_bounds( let mut ty_bounds = Vec::new(); g.where_predicates.retain(|pred| match *pred { clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds } - if *s == "Self" => + if *s == kw::SelfUpper => { ty_bounds.extend(bounds.iter().cloned()); false diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f5329bbb0cc4..2105ec0b0ba0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -48,8 +48,6 @@ crate use self::types::Type::*; crate use self::types::Visibility::{Inherited, Public}; crate use self::types::*; -const FN_OUTPUT_NAME: &str = "Output"; - crate trait Clean { fn clean(&self, cx: &DocContext<'_>) -> T; } @@ -329,10 +327,9 @@ impl Clean for (ty::PolyTraitRef<'_>, &[TypeBinding]) { .collect_referenced_late_bound_regions(&poly_trait_ref) .into_iter() .filter_map(|br| match br { - ty::BrNamed(_, name) => Some(GenericParamDef { - name: name.to_string(), - kind: GenericParamDefKind::Lifetime, - }), + ty::BrNamed(_, name) => { + Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime }) + } _ => None, }) .collect(); @@ -546,7 +543,7 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"), }; Type::QPath { - name: cx.tcx.associated_item(self.item_def_id).ident.name.clean(cx), + name: cx.tcx.associated_item(self.item_def_id).ident.name, self_type: box self.self_ty().clean(cx), trait_: box trait_, } @@ -556,14 +553,12 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { impl Clean for ty::GenericParamDef { fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { - ty::GenericParamDefKind::Lifetime => { - (self.name.to_string(), GenericParamDefKind::Lifetime) - } + ty::GenericParamDefKind::Lifetime => (self.name, GenericParamDefKind::Lifetime), ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { let default = if has_default { Some(cx.tcx.type_of(self.def_id).clean(cx)) } else { None }; ( - self.name.clean(cx), + self.name, GenericParamDefKind::Type { did: self.def_id, bounds: vec![], // These are filled in from the where-clauses. @@ -573,7 +568,7 @@ impl Clean for ty::GenericParamDef { ) } ty::GenericParamDefKind::Const { .. } => ( - self.name.clean(cx), + self.name, GenericParamDefKind::Const { did: self.def_id, ty: cx.tcx.type_of(self.def_id).clean(cx), @@ -599,14 +594,14 @@ impl Clean for hir::GenericParam<'_> { for bound in bounds { s.push_str(&format!(" + {}", bound.name.ident())); } - s + Symbol::intern(&s) } else { - self.name.ident().to_string() + self.name.ident().name }; (name, GenericParamDefKind::Lifetime) } hir::GenericParamKind::Type { ref default, synthetic } => ( - self.name.ident().name.clean(cx), + self.name.ident().name, GenericParamDefKind::Type { did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(), bounds: self.bounds.clean(cx), @@ -615,7 +610,7 @@ impl Clean for hir::GenericParam<'_> { }, ), hir::GenericParamKind::Const { ref ty } => ( - self.name.ident().name.clean(cx), + self.name.ident().name, GenericParamDefKind::Const { did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(), ty: ty.clean(cx), @@ -730,7 +725,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx .collect::>(); // param index -> [(DefId of trait, associated type name, type)] - let mut impl_trait_proj = FxHashMap::)>>::default(); + let mut impl_trait_proj = FxHashMap::)>>::default(); let where_predicates = preds .predicates @@ -778,11 +773,10 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx if let Some(((_, trait_did, name), rhs)) = proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))) { - impl_trait_proj.entry(param_idx).or_default().push(( - trait_did, - name.to_string(), - rhs, - )); + impl_trait_proj + .entry(param_idx) + .or_default() + .push((trait_did, name, rhs)); } return None; @@ -800,7 +794,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx if let crate::core::ImplTraitParam::ParamIndex(idx) = param { if let Some(proj) = impl_trait_proj.remove(&idx) { for (trait_did, name, rhs) in proj { - simplify::merge_bounds(cx, &mut bounds, trait_did, &name, &rhs.clean(cx)); + simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs.clean(cx)); } } } else { @@ -936,9 +930,9 @@ impl<'a> Clean for (&'a [hir::Ty<'a>], &'a [Ident]) { .iter() .enumerate() .map(|(i, ty)| { - let mut name = self.1.get(i).map(|ident| ident.to_string()).unwrap_or_default(); + let mut name = self.1.get(i).map(|ident| ident.name).unwrap_or(kw::Invalid); if name.is_empty() { - name = "_".to_string(); + name = kw::Underscore; } Argument { name, type_: ty.clean(cx) } }) @@ -995,7 +989,7 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { .iter() .map(|t| Argument { type_: t.clean(cx), - name: names.next().map_or_else(|| String::new(), |name| name.to_string()), + name: names.next().map(|i| i.name).unwrap_or(kw::Invalid), }) .collect(), }, @@ -1150,12 +1144,12 @@ impl Clean for ty::AssocItem { }; let self_arg_ty = sig.input(0).skip_binder(); if self_arg_ty == self_ty { - decl.inputs.values[0].type_ = Generic(String::from("Self")); + decl.inputs.values[0].type_ = Generic(kw::SelfUpper); } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { if ty == self_ty { match decl.inputs.values[0].type_ { BorrowedRef { ref mut type_, .. } => { - **type_ = Generic(String::from("Self")) + **type_ = Generic(kw::SelfUpper) } _ => unreachable!(), } @@ -1210,7 +1204,7 @@ impl Clean for ty::AssocItem { } } ty::AssocKind::Type => { - let my_name = self.ident.name.clean(cx); + let my_name = self.ident.name; if let ty::TraitContainer(_) = self.container { let bounds = cx.tcx.explicit_item_bounds(self.def_id); @@ -1235,7 +1229,7 @@ impl Clean for ty::AssocItem { _ => return None, } match **self_type { - Generic(ref s) if *s == "Self" => {} + Generic(ref s) if *s == kw::SelfUpper => {} _ => return None, } Some(bounds) @@ -1408,7 +1402,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &DocContext<'_>) -> Type { segments: trait_segments.clean(cx), }; Type::QPath { - name: p.segments.last().expect("segments were empty").ident.name.clean(cx), + name: p.segments.last().expect("segments were empty").ident.name, self_type: box qself.clean(cx), trait_: box resolve_type(cx, trait_path, hir_id), } @@ -1422,7 +1416,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &DocContext<'_>) -> Type { }; let trait_path = hir::Path { span, res, segments: &[] }; Type::QPath { - name: segment.ident.name.clean(cx), + name: segment.ident.name, self_type: box qself.clean(cx), trait_: box resolve_type(cx, trait_path.clean(cx), hir_id), } @@ -1625,7 +1619,7 @@ impl<'tcx> Clean for Ty<'tcx> { let mut bindings = vec![]; for pb in obj.projection_bounds() { bindings.push(TypeBinding { - name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx), + name: cx.tcx.associated_item(pb.item_def_id()).ident.name, kind: TypeBindingKind::Equality { ty: pb.skip_binder().ty.clean(cx) }, }); } @@ -1644,7 +1638,7 @@ impl<'tcx> Clean for Ty<'tcx> { if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) { ImplTrait(bounds) } else { - Generic(p.name.to_string()) + Generic(p.name) } } @@ -1702,8 +1696,7 @@ impl<'tcx> Clean for Ty<'tcx> { .tcx .associated_item(proj.projection_ty.item_def_id) .ident - .name - .clean(cx), + .name, kind: TypeBindingKind::Equality { ty: proj.ty.clean(cx), }, @@ -2339,7 +2332,7 @@ impl Clean for (&hir::MacroDef<'_>, Option) { impl Clean for hir::TypeBinding<'_> { fn clean(&self, cx: &DocContext<'_>) -> TypeBinding { - TypeBinding { name: self.ident.name.clean(cx), kind: self.kind.clean(cx) } + TypeBinding { name: self.ident.name, kind: self.kind.clean(cx) } } } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 121c9d2bc4cd..16aaa9cfd20e 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -15,6 +15,7 @@ use std::collections::BTreeMap; use rustc_hir::def_id::DefId; use rustc_middle::ty; +use rustc_span::Symbol; use crate::clean; use crate::clean::GenericArgs as PP; @@ -78,7 +79,7 @@ crate fn merge_bounds( cx: &clean::DocContext<'_>, bounds: &mut Vec, trait_did: DefId, - name: &str, + name: Symbol, rhs: &clean::Type, ) -> bool { !bounds.iter_mut().any(|b| { @@ -100,7 +101,7 @@ crate fn merge_bounds( match last.args { PP::AngleBracketed { ref mut bindings, .. } => { bindings.push(clean::TypeBinding { - name: name.to_string(), + name, kind: clean::TypeBindingKind::Equality { ty: rhs.clone() }, }); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index dbdcd68810b5..9bade5ad2ecf 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -949,7 +949,7 @@ impl GenericParamDefKind { #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct GenericParamDef { - crate name: String, + crate name: Symbol, crate kind: GenericParamDefKind, } @@ -1037,7 +1037,7 @@ crate struct Arguments { #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct Argument { crate type_: Type, - crate name: String, + crate name: Symbol, } #[derive(Clone, PartialEq, Debug)] @@ -1049,7 +1049,7 @@ crate enum SelfTy { impl Argument { crate fn to_self(&self) -> Option { - if self.name != "self" { + if self.name != kw::SelfLower { return None; } if self.type_.is_self_type() { @@ -1117,7 +1117,7 @@ crate enum Type { }, /// For parameterized types, so the consumer of the JSON don't go /// looking for types which don't exist anywhere. - Generic(String), + Generic(Symbol), /// Primitives are the fixed-size numeric types (plus int/usize/float), char, /// arrays, slices, and tuples. Primitive(PrimitiveType), @@ -1136,7 +1136,7 @@ crate enum Type { // `::Name` QPath { - name: String, + name: Symbol, self_type: Box, trait_: Box, }, @@ -1237,7 +1237,7 @@ impl Type { crate fn is_self_type(&self) -> bool { match *self { - Generic(ref name) => name == "Self", + Generic(name) => name == kw::SelfUpper, _ => false, } } @@ -1282,16 +1282,16 @@ impl Type { } } - crate fn projection(&self) -> Option<(&Type, DefId, &str)> { + crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> { let (self_, trait_, name) = match self { - QPath { ref self_type, ref trait_, ref name } => (self_type, trait_, name), + QPath { ref self_type, ref trait_, name } => (self_type, trait_, name), _ => return None, }; let trait_did = match **trait_ { ResolvedPath { did, .. } => did, _ => return None, }; - Some((&self_, trait_did, name)) + Some((&self_, trait_did, *name)) } } @@ -1816,7 +1816,7 @@ crate struct ProcMacro { /// `A: Send + Sync` in `Foo`). #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct TypeBinding { - crate name: String, + crate name: Symbol, crate kind: TypeBindingKind, } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index f8743a4c42e9..ec922b182e2b 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -170,13 +170,13 @@ crate fn get_real_types( cx: &DocContext<'_>, recurse: i32, ) -> FxHashSet<(Type, TypeKind)> { - let arg_s = arg.print().to_string(); let mut res = FxHashSet::default(); if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed return res; } if arg.is_full_generic() { + let arg_s = Symbol::intern(&arg.print().to_string()); if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g { &WherePredicate::BoundPredicate { ref ty, .. } => ty.def_id() == arg.def_id(), _ => false, @@ -375,13 +375,13 @@ impl ToSource for rustc_span::Span { } } -crate fn name_from_pat(p: &hir::Pat<'_>) -> String { +crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { use rustc_hir::*; debug!("trying to get a name from pattern: {:?}", p); - match p.kind { - PatKind::Wild => "_".to_string(), - PatKind::Binding(_, _, ident, _) => ident.to_string(), + Symbol::intern(&match p.kind { + PatKind::Wild => return kw::Underscore, + PatKind::Binding(_, _, ident, _) => return ident.name, PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), PatKind::Struct(ref name, ref fields, etc) => format!( "{} {{ {}{} }}", @@ -393,32 +393,37 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> String { .join(", "), if etc { ", .." } else { "" } ), - PatKind::Or(ref pats) => { - pats.iter().map(|p| name_from_pat(&**p)).collect::>().join(" | ") - } + PatKind::Or(ref pats) => pats + .iter() + .map(|p| name_from_pat(&**p).to_string()) + .collect::>() + .join(" | "), PatKind::Tuple(ref elts, _) => format!( "({})", - elts.iter().map(|p| name_from_pat(&**p)).collect::>().join(", ") + elts.iter() + .map(|p| name_from_pat(&**p).to_string()) + .collect::>() + .join(", ") ), - PatKind::Box(ref p) => name_from_pat(&**p), - PatKind::Ref(ref p, _) => name_from_pat(&**p), + PatKind::Box(ref p) => return name_from_pat(&**p), + PatKind::Ref(ref p, _) => return name_from_pat(&**p), PatKind::Lit(..) => { warn!( "tried to get argument name from PatKind::Lit, which is silly in function arguments" ); - "()".to_string() + return Symbol::intern("()"); } PatKind::Range(..) => panic!( "tried to get argument name from PatKind::Range, \ which is not allowed in function arguments" ), PatKind::Slice(ref begin, ref mid, ref end) => { - let begin = begin.iter().map(|p| name_from_pat(&**p)); + let begin = begin.iter().map(|p| name_from_pat(&**p).to_string()); let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter(); - let end = end.iter().map(|p| name_from_pat(&**p)); + let end = end.iter().map(|p| name_from_pat(&**p).to_string()); format!("[{}]", begin.chain(mid).chain(end).collect::>().join(", ")) } - } + }) } crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { @@ -534,10 +539,10 @@ crate fn resolve_type(cx: &DocContext<'_>, path: Path, id: hir::HirId) -> Type { let is_generic = match path.res { Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)), Res::SelfTy(..) if path.segments.len() == 1 => { - return Generic(kw::SelfUpper.to_string()); + return Generic(kw::SelfUpper); } Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { - return Generic(format!("{:#}", path.print())); + return Generic(Symbol::intern(&format!("{:#}", path.print()))); } Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true, _ => false, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 536c2e08fdef..c49c48922378 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -172,7 +172,7 @@ impl clean::GenericParamDef { display_fn(move |f| match self.kind { clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name), clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => { - f.write_str(&self.name)?; + f.write_str(&*self.name.as_str())?; if !bounds.is_empty() { if f.alternate() { @@ -193,13 +193,10 @@ impl clean::GenericParamDef { Ok(()) } clean::GenericParamDefKind::Const { ref ty, .. } => { - f.write_str("const ")?; - f.write_str(&self.name)?; - if f.alternate() { - write!(f, ": {:#}", ty.print()) + write!(f, "const {}: {:#}", self.name, ty.print()) } else { - write!(f, ": {}", ty.print()) + write!(f, "const {}: {}", self.name, ty.print()) } } }) @@ -638,7 +635,7 @@ crate fn anchor(did: DefId, text: &str) -> impl fmt::Display + '_ { fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> fmt::Result { match *t { - clean::Generic(ref name) => f.write_str(name), + clean::Generic(name) => write!(f, "{}", name), clean::ResolvedPath { did, ref param_names, ref path, is_generic } => { if param_names.is_some() { f.write_str("dyn ")?; @@ -1203,7 +1200,7 @@ impl clean::ImportSource { impl clean::TypeBinding { crate fn print(&self) -> impl fmt::Display + '_ { display_fn(move |f| { - f.write_str(&self.name)?; + f.write_str(&*self.name.as_str())?; match self.kind { clean::TypeBindingKind::Equality { ref ty } => { if f.alternate() { diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 91037bc160ab..80f54d8e161a 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -208,7 +208,7 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option }); Some(path_segment.name.clone()) } - clean::Generic(ref s) if accept_generic => Some(s.clone()), + clean::Generic(s) if accept_generic => Some(s.to_string()), clean::Primitive(ref p) => Some(format!("{:?}", p)), clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), // FIXME: add all from clean::Type. diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index b5babfd10fdf..809cfb9d7432 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -136,7 +136,7 @@ impl From for Constant { impl From for TypeBinding { fn from(binding: clean::TypeBinding) -> Self { - TypeBinding { name: binding.name, binding: binding.kind.into() } + TypeBinding { name: binding.name.to_string(), binding: binding.kind.into() } } } @@ -275,7 +275,7 @@ impl From for Generics { impl From for GenericParamDef { fn from(generic_param: clean::GenericParamDef) -> Self { - GenericParamDef { name: generic_param.name, kind: generic_param.kind.into() } + GenericParamDef { name: generic_param.name.to_string(), kind: generic_param.kind.into() } } } @@ -351,7 +351,7 @@ impl From for Type { .map(|v| v.into_iter().map(Into::into).collect()) .unwrap_or_default(), }, - Generic(s) => Type::Generic(s), + Generic(s) => Type::Generic(s.to_string()), Primitive(p) => Type::Primitive(p.as_str().to_string()), BareFunction(f) => Type::FunctionPointer(Box::new((*f).into())), Tuple(t) => Type::Tuple(t.into_iter().map(Into::into).collect()), @@ -370,7 +370,7 @@ impl From for Type { type_: Box::new((*type_).into()), }, QPath { name, self_type, trait_ } => Type::QualifiedPath { - name, + name: name.to_string(), self_type: Box::new((*self_type).into()), trait_: Box::new((*trait_).into()), }, @@ -394,7 +394,11 @@ impl From for FnDecl { fn from(decl: clean::FnDecl) -> Self { let clean::FnDecl { inputs, output, c_variadic, attrs: _ } = decl; FnDecl { - inputs: inputs.values.into_iter().map(|arg| (arg.name, arg.type_.into())).collect(), + inputs: inputs + .values + .into_iter() + .map(|arg| (arg.name.to_string(), arg.type_.into())) + .collect(), output: match output { clean::FnRetTy::Return(t) => Some(t.into()), clean::FnRetTy::DefaultReturn => None, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f9d81fb86353..ea5bf94689bc 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -753,11 +753,14 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx /// /// These are common and we should just resolve to the trait in that case. fn is_derive_trait_collision(ns: &PerNS>>) -> bool { - matches!(*ns, PerNS { - type_ns: Ok((Res::Def(DefKind::Trait, _), _)), - macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), - .. - }) + matches!( + *ns, + PerNS { + type_ns: Ok((Res::Def(DefKind::Trait, _), _)), + macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), + .. + } + ) } impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 299a73c8a011..1c1141e7c812 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -58,18 +58,19 @@ impl crate::doctest::Tester for Tests { } crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool { - if matches!(item.kind, + if matches!( + item.kind, clean::StructFieldItem(_) - | clean::VariantItem(_) - | clean::AssocConstItem(_, _) - | clean::AssocTypeItem(_, _) - | clean::TypedefItem(_, _) - | clean::StaticItem(_) - | clean::ConstantItem(_) - | clean::ExternCrateItem(_, _) - | clean::ImportItem(_) - | clean::PrimitiveItem(_) - | clean::KeywordItem(_) + | clean::VariantItem(_) + | clean::AssocConstItem(_, _) + | clean::AssocTypeItem(_, _) + | clean::TypedefItem(_, _) + | clean::StaticItem(_) + | clean::ConstantItem(_) + | clean::ExternCrateItem(_, _) + | clean::ImportItem(_) + | clean::PrimitiveItem(_) + | clean::KeywordItem(_) ) { return false; } From 60b4082d5feed36622340d40eb81d68010ccd1df Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 14 Dec 2020 20:03:19 -0800 Subject: [PATCH 347/719] Add more documentation to `Diagnostic` and `DiagnosticBuilder` --- compiler/rustc_errors/src/diagnostic.rs | 23 +++++++++-- .../rustc_errors/src/diagnostic_builder.rs | 38 +++++++++++++++---- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index decbf03b9de8..c3422c78ef6e 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -30,7 +30,8 @@ pub enum DiagnosticId { Lint { name: String, has_future_breakage: bool }, } -/// For example a note attached to an error. +/// A "sub"-diagnostic attached to a parent diagnostic. +/// For example, a note attached to an error. #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] pub struct SubDiagnostic { pub level: Level, @@ -124,6 +125,7 @@ impl Diagnostic { self.level = Level::Cancelled; } + /// Check if this diagnostic [was cancelled][Self::cancel()]. pub fn cancelled(&self) -> bool { self.level == Level::Cancelled } @@ -241,6 +243,7 @@ impl Diagnostic { self } + /// Add a note attached to this diagnostic. pub fn note(&mut self, msg: &str) -> &mut Self { self.sub(Level::Note, msg, MultiSpan::new(), None); self @@ -252,33 +255,40 @@ impl Diagnostic { } /// Prints the span with a note above it. + /// This is like [`Diagnostic::note()`], but it gets its own span. pub fn span_note>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Note, msg, sp.into(), None); self } + /// Add a warning attached to this diagnostic. pub fn warn(&mut self, msg: &str) -> &mut Self { self.sub(Level::Warning, msg, MultiSpan::new(), None); self } - /// Prints the span with a warn above it. + /// Prints the span with a warning above it. + /// This is like [`Diagnostic::warn()`], but it gets its own span. pub fn span_warn>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Warning, msg, sp.into(), None); self } + /// Add a help message attached to this diagnostic. pub fn help(&mut self, msg: &str) -> &mut Self { self.sub(Level::Help, msg, MultiSpan::new(), None); self } /// Prints the span with some help above it. + /// This is like [`Diagnostic::help()`], but it gets its own span. pub fn span_help>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Help, msg, sp.into(), None); self } + /// Show a suggestion that has multiple parts to it. + /// In other words, multiple changes need to be applied as part of this suggestion. pub fn multipart_suggestion( &mut self, msg: &str, @@ -299,6 +309,8 @@ impl Diagnostic { self } + /// Show multiple suggestions that have multiple parts. + /// See also [`Diagnostic::multipart_suggestion()`]. pub fn multipart_suggestions( &mut self, msg: &str, @@ -382,6 +394,7 @@ impl Diagnostic { self } + /// [`Diagnostic::span_suggestion()`] but you can set the [`SuggestionStyle`]. pub fn span_suggestion_with_style( &mut self, sp: Span, @@ -401,6 +414,7 @@ impl Diagnostic { self } + /// Always show the suggested change. pub fn span_suggestion_verbose( &mut self, sp: Span, @@ -419,6 +433,7 @@ impl Diagnostic { } /// Prints out a message with multiple suggested edits of the code. + /// See also [`Diagnostic::span_suggestion()`]. pub fn span_suggestions( &mut self, sp: Span, @@ -458,7 +473,7 @@ impl Diagnostic { self } - /// Prints out a message with for a suggestion without showing the suggested code. + /// Prints out a message for a suggestion without showing the suggested code. /// /// This is intended to be used for suggestions that are obvious in what the changes need to /// be from the message, showing the span label inline would be visually unpleasant @@ -481,7 +496,7 @@ impl Diagnostic { self } - /// Adds a suggestion to the json output, but otherwise remains silent/undisplayed in the cli. + /// Adds a suggestion to the JSON output that will not be shown in the CLI. /// /// This is intended to be used for suggestions that are *very* obvious in what the changes /// need to be from the message, but we still want other tools to be able to apply them. diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index c9259a1502c8..de6d7c3f5d87 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -30,6 +30,15 @@ struct DiagnosticBuilderInner<'a> { allow_suggestions: bool, } +/// This is a helper macro for [`forward!`] that allows automatically adding documentation +/// that uses tokens from [`forward!`]'s input. +macro_rules! forward_inner_docs { + ($e:expr => $i:item) => { + #[doc = $e] + $i + } +} + /// In general, the `DiagnosticBuilder` uses deref to allow access to /// the fields and methods of the embedded `diagnostic` in a /// transparent way. *However,* many of the methods are intended to @@ -45,10 +54,11 @@ macro_rules! forward { pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self ) => { $(#[$attrs])* + forward_inner_docs!(concat!("See [`Diagnostic::", stringify!($n), "()`].") => pub fn $n(&self, $($name: $ty),*) -> &Self { self.diagnostic.$n($($name),*); self - } + }); }; // Forward pattern for &mut self -> &mut Self @@ -57,10 +67,11 @@ macro_rules! forward { pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)?) -> &mut Self ) => { $(#[$attrs])* + forward_inner_docs!(concat!("See [`Diagnostic::", stringify!($n), "()`].") => pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { self.0.diagnostic.$n($($name),*); self - } + }); }; // Forward pattern for &mut self -> &mut Self, with S: Into @@ -74,10 +85,11 @@ macro_rules! forward { ) -> &mut Self ) => { $(#[$attrs])* + forward_inner_docs!(concat!("See [`Diagnostic::", stringify!($n), "()`].") => pub fn $n>(&mut self, $($name: $ty),*) -> &mut Self { self.0.diagnostic.$n($($name),*); self - } + }); }; } @@ -116,7 +128,7 @@ impl<'a> DiagnosticBuilder<'a> { /// Stashes diagnostic for possible later improvement in a different, /// later stage of the compiler. The diagnostic can be accessed with - /// the provided `span` and `key` through `.steal_diagnostic` on `Handler`. + /// the provided `span` and `key` through [`Handler::steal_diagnostic()`]. /// /// As with `buffer`, this is unless the handler has disabled such buffering. pub fn stash(self, span: Span, key: StashKey) { @@ -202,7 +214,7 @@ impl<'a> DiagnosticBuilder<'a> { } /// Labels all the given spans with the provided label. - /// See `span_label` for more information. + /// See [`Diagnostic::span_label()`] for more information. pub fn span_labels( &mut self, spans: impl IntoIterator, @@ -254,6 +266,7 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, ) -> &mut Self); + /// See [`Diagnostic::multipart_suggestion()`]. pub fn multipart_suggestion( &mut self, msg: &str, @@ -267,6 +280,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::multipart_suggestions()`]. pub fn multipart_suggestions( &mut self, msg: &str, @@ -280,6 +294,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::tool_only_multipart_suggestion()`]. pub fn tool_only_multipart_suggestion( &mut self, msg: &str, @@ -293,6 +308,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestion()`]. pub fn span_suggestion( &mut self, sp: Span, @@ -307,6 +323,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestions()`]. pub fn span_suggestions( &mut self, sp: Span, @@ -321,6 +338,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestion_short()`]. pub fn span_suggestion_short( &mut self, sp: Span, @@ -335,6 +353,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestion_verbose()`]. pub fn span_suggestion_verbose( &mut self, sp: Span, @@ -349,6 +368,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestion_hidden()`]. pub fn span_suggestion_hidden( &mut self, sp: Span, @@ -363,6 +383,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::tool_only_span_suggestion()`] for more information. pub fn tool_only_span_suggestion( &mut self, sp: Span, @@ -380,19 +401,22 @@ impl<'a> DiagnosticBuilder<'a> { forward!(pub fn set_span>(&mut self, sp: S) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); + /// Allow attaching suggestions this diagnostic. + /// If this is set to `false`, then any suggestions attached with the `span_suggestion_*` + /// methods after this is set to `false` will be ignored. pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self { self.0.allow_suggestions = allow; self } /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. + /// `struct_*` methods on [`Handler`]. crate fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { DiagnosticBuilder::new_with_code(handler, level, None, message) } /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. + /// `struct_*` methods on [`Handler`]. crate fn new_with_code( handler: &'a Handler, level: Level, From 10487cd7840590c897ead9172bf9c6b22ee6f0a6 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 14 Dec 2020 20:05:31 -0800 Subject: [PATCH 348/719] Fix typo in method name unsuccessfull -> unsuccessful --- compiler/rustc_errors/src/diagnostic.rs | 2 +- compiler/rustc_errors/src/diagnostic_builder.rs | 2 +- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index c3422c78ef6e..538e1a59ab8d 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -166,7 +166,7 @@ impl Diagnostic { self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") } - pub fn note_unsuccessfull_coercion( + pub fn note_unsuccessful_coercion( &mut self, expected: DiagnosticStyledString, found: DiagnosticStyledString, diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index de6d7c3f5d87..f165a60336a6 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -245,7 +245,7 @@ impl<'a> DiagnosticBuilder<'a> { found_extra: &dyn fmt::Display, ) -> &mut Self); - forward!(pub fn note_unsuccessfull_coercion( + forward!(pub fn note_unsuccessful_coercion( &mut self, expected: DiagnosticStyledString, found: DiagnosticStyledString, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 183fb314a00d..0100bd99344c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1622,7 +1622,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } (TypeError::ObjectUnsafeCoercion(_), _) => { - diag.note_unsuccessfull_coercion(found, expected); + diag.note_unsuccessful_coercion(found, expected); } (_, _) => { debug!( From f365de353ad3d48b5e9269ebc373f82d5aeb19d0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 16 Dec 2020 23:51:18 +0100 Subject: [PATCH 349/719] Add `popcount` and `popcnt` as doc aliases for `count_ones` methods. Integer types have a `count_ones` method that end up calling `intrinsics::ctpop`. On some architectures, that intrinsic is translated as a corresponding CPU instruction know as "popcount" or "popcnt". This PR makes it so that searching for those names in rustdoc shows those methods. CC https://blog.rust-lang.org/2020/11/19/Rust-1.48.html#adding-search-aliases --- library/core/src/num/int_macros.rs | 2 ++ library/core/src/num/uint_macros.rs | 2 ++ library/core/src/num/wrapping.rs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 4fa48427ec6e..2cde5d9995b6 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -92,6 +92,8 @@ $EndFeature, " "), #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] #[inline] pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 390c1b7e9e87..ae8fc18a8388 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -90,6 +90,8 @@ assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] #[inline] pub const fn count_ones(self) -> u32 { intrinsics::ctpop(self as $ActualT) as u32 diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 5324dfdeddde..77c9a93008c9 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -453,6 +453,8 @@ let n = Wrapping(0b01001100", stringify!($t), "); assert_eq!(n.count_ones(), 3); ```"), #[inline] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn count_ones(self) -> u32 { self.0.count_ones() From 8b3725973a696f8dd77e17127863ec56512322cb Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 17 Dec 2020 00:27:21 +0100 Subject: [PATCH 350/719] Added reference to tracking issue --- library/core/src/array/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 6791f0e74442..71548bec7aae 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -479,7 +479,7 @@ impl [T; N] { /// let z = x.zip(y); /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]); /// ``` - #[unstable(feature = "array_zip", issue = "none")] + #[unstable(feature = "array_zip", issue = "80094")] pub fn zip(self, rhs: [U; N]) -> [(T, U); N] { use crate::mem::MaybeUninit; From 1d6fac616767d84156e018e2a78582b7164241fb Mon Sep 17 00:00:00 2001 From: Naughty Date: Wed, 16 Dec 2020 20:48:03 -0300 Subject: [PATCH 351/719] Typo: std::fs::crate_dir -> std::fs::create_dir --- clippy_lints/src/create_dir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 4002fb655a5e..200b6a565cc4 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. /// - /// **Why is this bad?** Sometimes `std::fs::crate_dir` is mistakenly chosen over `std::fs::create_dir_all`. + /// **Why is this bad?** Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`. /// /// **Known problems:** None. /// From 2edd3016c8bab6f849ca3a907ecd800777e36846 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Wed, 16 Dec 2020 20:15:57 -0500 Subject: [PATCH 352/719] Bless NLL test --- src/test/ui/issues/issue-40000.nll.stderr | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/ui/issues/issue-40000.nll.stderr b/src/test/ui/issues/issue-40000.nll.stderr index f673fbae8b79..4e2bde06a52a 100644 --- a/src/test/ui/issues/issue-40000.nll.stderr +++ b/src/test/ui/issues/issue-40000.nll.stderr @@ -4,5 +4,11 @@ error: higher-ranked subtype error LL | foo(bar); | ^^^ -error: aborting due to previous error +error: higher-ranked subtype error + --> $DIR/issue-40000.rs:6:9 + | +LL | foo(bar); + | ^^^ + +error: aborting due to 2 previous errors From bec1c278b6649889d24e839a6aff19cefc44f3fa Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 16 Dec 2020 17:34:47 -0800 Subject: [PATCH 353/719] Remove docs for non-existent parameters in `rustc_expand` --- compiler/rustc_expand/src/mbe/macro_parser.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 92a8f2311267..c37f91256757 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -1,4 +1,4 @@ -//! This is an NFA-based parser, which calls out to the main rust parser for named non-terminals +//! This is an NFA-based parser, which calls out to the main Rust parser for named non-terminals //! (which it commits to fully when it hits one in a grammar). There's a set of current NFA threads //! and a set of next ones. Instead of NTs, we have a special case for Kleene star. The big-O, in //! pathological cases, is worse than traditional use of NFA or Earley parsing, but it's an easier @@ -422,7 +422,6 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { /// /// # Parameters /// -/// - `sess`: the parsing session into which errors are emitted. /// - `cur_items`: the set of current items to be processed. This should be empty by the end of a /// successful execution of this function. /// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in @@ -430,8 +429,6 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { /// - `eof_items`: the set of items that would be valid if this was the EOF. /// - `bb_items`: the set of items that are waiting for the black-box parser. /// - `token`: the current token of the parser. -/// - `span`: the `Span` in the source code corresponding to the token trees we are trying to match -/// against the matcher positions in `cur_items`. /// /// # Returns /// From c9fab5008479012ed944a8e542ed2a309ec2a385 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 16 Dec 2020 22:07:40 -0800 Subject: [PATCH 354/719] Remove redundant and unreliable coverage test results The `coverage-reports` tests still generate counters and JSON reports for inspection, but these files are no longer used in Makefile diffs, to reduce complexity and confusion from unreliable or unexpected test results, especially when maintaining them (i.e., generating `--bless`ed results). The associated `expected_` files for counters and JSON reports have been removed, leaving only the files actually used for testing: the `llvm-cov show` reports. --- .../coverage-reports/Makefile | 135 +++++--- .../expected_export_coverage.abort.json | 59 ---- .../expected_export_coverage.assert.json | 59 ---- .../expected_export_coverage.async.json | 59 ---- .../expected_export_coverage.closure.json | 59 ---- .../expected_export_coverage.conditions.json | 59 ---- .../expected_export_coverage.dead_code.json | 59 ---- .../expected_export_coverage.drop_trait.json | 59 ---- .../expected_export_coverage.generics.json | 59 ---- .../expected_export_coverage.if.json | 59 ---- .../expected_export_coverage.if_else.json | 59 ---- .../expected_export_coverage.inner_items.json | 59 ---- ...expected_export_coverage.lazy_boolean.json | 59 ---- ...cted_export_coverage.loop_break_value.json | 59 ---- ...pected_export_coverage.loops_branches.json | 59 ---- ...cted_export_coverage.match_or_pattern.json | 59 ---- ...expected_export_coverage.nested_loops.json | 59 ---- .../expected_export_coverage.overflow.json | 59 ---- ...expected_export_coverage.panic_unwind.json | 59 ---- .../expected_export_coverage.partial_eq.json | 59 ---- .../expected_export_coverage.simple_loop.json | 59 ---- ...expected_export_coverage.simple_match.json | 59 ---- ...pected_export_coverage.tight_inf_loop.json | 59 ---- ...cted_export_coverage.try_error_result.json | 59 ---- .../expected_export_coverage.uses_crate.json | 59 ---- .../expected_export_coverage.while.json | 59 ---- ...ected_export_coverage.while_early_ret.json | 59 ---- .../expected_export_coverage.yield.json | 59 ---- .../expected_show_coverage_counters.abort.txt | 67 ---- ...expected_show_coverage_counters.assert.txt | 57 ---- .../expected_show_coverage_counters.async.txt | 311 ------------------ ...xpected_show_coverage_counters.closure.txt | 153 --------- ...cted_show_coverage_counters.conditions.txt | 253 -------------- ...ected_show_coverage_counters.dead_code.txt | 47 --- ...cted_show_coverage_counters.drop_trait.txt | 18 - ...pected_show_coverage_counters.generics.txt | 44 --- .../expected_show_coverage_counters.if.txt | 17 - ...xpected_show_coverage_counters.if_else.txt | 30 -- ...ted_show_coverage_counters.inner_items.txt | 44 --- ...ed_show_coverage_counters.lazy_boolean.txt | 111 ------- ...how_coverage_counters.loop_break_value.txt | 6 - ..._show_coverage_counters.loops_branches.txt | 33 -- ...how_coverage_counters.match_or_pattern.txt | 98 ------ ...ed_show_coverage_counters.nested_loops.txt | 58 ---- ...pected_show_coverage_counters.overflow.txt | 52 --- ...ed_show_coverage_counters.panic_unwind.txt | 53 --- ...cted_show_coverage_counters.partial_eq.txt | 66 ---- ...ted_show_coverage_counters.simple_loop.txt | 29 -- ...ed_show_coverage_counters.simple_match.txt | 45 --- ..._show_coverage_counters.tight_inf_loop.txt | 10 - ...how_coverage_counters.try_error_result.txt | 63 ---- ...cted_show_coverage_counters.uses_crate.txt | 110 ------- .../expected_show_coverage_counters.while.txt | 18 - ...show_coverage_counters.while_early_ret.txt | 38 --- .../expected_show_coverage_counters.yield.txt | 94 ------ .../coverage-reports/prettify_json.py | 9 - 56 files changed, 86 insertions(+), 3576 deletions(-) delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.abort.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.closure.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.conditions.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.dead_code.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.drop_trait.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.generics.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if_else.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.inner_items.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.lazy_boolean.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loop_break_value.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loops_branches.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.nested_loops.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.partial_eq.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_loop.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_match.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.tight_inf_loop.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.try_error_result.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while_early_ret.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.yield.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.abort.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.closure.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.conditions.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.dead_code.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.drop_trait.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if_else.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.inner_items.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.lazy_boolean.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loop_break_value.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loops_branches.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.nested_loops.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.partial_eq.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_loop.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_match.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.tight_inf_loop.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.try_error_result.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while_early_ret.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.yield.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports/prettify_json.py diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index a5d6970009a3..5c24f909130c 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -9,11 +9,13 @@ BASEDIR=../coverage-reports SOURCEDIR=../coverage -# The `llvm-cov show` flag `--debug`, used to generate the `counters` output files, is only enabled -# if LLVM assertions are enabled. Requires Rust config `llvm/optimize` and not +# The `llvm-cov show` flag `--debug`, used to generate the `counters` output files, is only +# enabled if LLVM assertions are enabled. This requires Rust config `llvm/optimize` and not # `llvm/release_debuginfo`. Note that some CI builds disable debug assertions (by setting -# `NO_LLVM_ASSERTIONS=1`), so it is not OK to fail the test, but `bless`ed test results cannot be -# generated without debug assertions. +# `NO_LLVM_ASSERTIONS=1`), so the tests must still pass even if the `--debug` flag is +# not supported. (Note that `counters` files are only produced in the `$(TMPDIR)` +# directory, for inspection and debugging support. They are *not* copied to `expected_*` +# files when `--bless`ed.) LLVM_COV_DEBUG := $(shell \ "$(LLVM_BIN_DIR)"/llvm-cov show --debug 2>&1 | \ grep -q "Unknown command line argument '--debug'"; \ @@ -51,11 +53,10 @@ endif # Yes these `--ignore-filename-regex=` options are included in all invocations of `llvm-cov show` # for now, but it is effectively ignored for all tests that don't include this file anyway. # -# Note that it's also possible the `_counters..txt` and `.json` files may order -# results from multiple files inconsistently, which might also have to be accomodated if and when -# we allow `llvm-cov` to produce results for multiple files. (The path separators appear to be -# normalized to `/` in those files, thankfully.) But since we are ignoring results for all but one -# file, this workaround addresses those potential issues as well. +# (Note that it's also possible the `_counters..txt` and `.json` files (if generated) +# may order results from multiple files inconsistently, which might also have to be accomodated +# if and when we allow `llvm-cov` to produce results for multiple files. Note, the path separators +# appear to be normalized to `/` in those files, thankfully.) LLVM_COV_IGNORE_FILES=\ --ignore-filename-regex=uses_crate.rs @@ -77,9 +78,7 @@ endif .PHONY: clear_expected_if_blessed clear_expected_if_blessed: ifdef RUSTC_BLESS_TEST - rm -f expected_export_coverage.*.json - rm -f expected_show_coverage.*.txt - rm -f expected_show_coverage_counters.*.txt + rm -f expected_* endif -include clear_expected_if_blessed @@ -140,12 +139,8 @@ endif ifdef RUSTC_BLESS_TEST cp "$(TMPDIR)"/actual_show_coverage.$@.txt \ expected_show_coverage.$@.txt - cp "$(TMPDIR)"/actual_show_coverage_counters.$@.txt \ - expected_show_coverage_counters.$@.txt else - # Compare the show coverage output (`--bless` refreshes `typical` files) - # Note `llvm-cov show` output for some programs can vary, but can be ignored - # by inserting `// ignore-llvm-cov-show-diffs` at the top of the source file. + # Compare the show coverage output (`--bless` refreshes `typical` files). # # FIXME(richkadel): None of the Rust test source samples have the # `// ignore-llvm-cov-show-diffs` anymore. This directive exists to work around a limitation @@ -158,8 +153,10 @@ else # # This workaround only works if the coverage counts are identical across all reported # instantiations. If there is no way to ensure this, you may need to apply the - # `// ignore-llvm-cov-show-diffs` directive, and rely on the `.json` and counter - # files for validating results have not changed. + # `// ignore-llvm-cov-show-diffs` directive, and check for differences using the + # `.json` files to validate that results have not changed. (Until then, the JSON + # files are redundant, so there is no need to generate `expected_*.json` files or + # compare actual JSON results.) $(DIFF) --ignore-matching-lines='::<.*>.*:$$' \ expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ @@ -169,37 +166,77 @@ else ( >&2 echo 'diff failed, and not suppressed without `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs'; \ false \ ) - -ifdef DEBUG_FLAG - $(DIFF) expected_show_coverage_counters.$@.txt "$(TMPDIR)"/actual_show_coverage_counters.$@.txt || \ - ( grep -q '^\/\/ ignore-llvm-cov-show-diffs' $(SOURCEDIR)/$@.rs && \ - >&2 echo 'diff failed, but suppressed with `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs' \ - ) || \ - ( >&2 echo 'diff failed, and not suppressed without `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs'; \ - >&2 echo '(Ignore anyway until mangled function names in "counters" files are demangled.)' \ - ) - - # FIXME(richkadel): Apply the demangler to the `*_show_coverage_counters.*.txt` files, - # so the crate disambiguator differences will be stripped away. At that point, these files - # will be less likely to vary, and the last `echo` above (starting with "Ignore anyway") - # can be replaced with `false` to fail the test. endif -endif +#################################################################################################### - # Generate a coverage report in JSON, using `llvm-cov export`, and fail if - # there are differences from the expected output. - "$(LLVM_BIN_DIR)"/llvm-cov export \ - $(LLVM_COV_IGNORE_FILES) \ - --summary-only \ - --instr-profile="$(TMPDIR)"/$@.profdata \ - $(call BIN,"$(TMPDIR)"/$@) \ - | "$(PYTHON)" $(BASEDIR)/prettify_json.py \ - > "$(TMPDIR)"/actual_export_coverage.$@.json +# The following Makefile content was used to copy the generated `counters` files +# to `expected_` files (when `--bless`ed) and to compare them via `diff`; but for +# multiple reasons, these files cannot easily be used for test validation: +# +# * Output lines can be produced in non-deterministic order (depending on the +# target platform, and sometimes on unrelated codegen changes). +# * Some lines include demangled function names, making them more challenging +# to interpret and compare. +# +# The files are still generated (in `$(TMPDIR)`) to support developers wanting +# to inspect the counters, for debugging purposes. +# +# ifdef RUSTC_BLESS_TEST +# cp "$(TMPDIR)"/actual_show_coverage_counters.$@.txt \ +# expected_show_coverage_counters.$@.txt +# else +# +# ifdef DEBUG_FLAG +# $(DIFF) expected_show_coverage_counters.$@.txt "$(TMPDIR)"/actual_show_coverage_counters.$@.txt || \ +# ( grep -q '^\/\/ ignore-llvm-cov-show-diffs' $(SOURCEDIR)/$@.rs && \ +# >&2 echo 'diff failed, but suppressed with `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs' \ +# ) || \ +# ( >&2 echo 'diff failed, and not suppressed without `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs'; \ +# >&2 echo '(Ignore anyway until mangled function names in "counters" files are demangled.)' \ +# ) +# endif +# +# endif -ifdef RUSTC_BLESS_TEST - cp "$(TMPDIR)"/actual_export_coverage.$@.json expected_export_coverage.$@.json -else - # Check that exported JSON coverage data matches what we expect (`--bless` refreshes `expected`) - $(DIFF) expected_export_coverage.$@.json "$(TMPDIR)"/actual_export_coverage.$@.json -endif +#################################################################################################### + +# The following Makefile content, and short JSON script, were used to generate +# coverage reports in JSON when the `llvm-cov show` reports were less reliable for +# testing. At the present time, however, the `llvm-cov show` results, and methods +# for comparing them, are working for all tests, making the JSON reports redundant. +# +# If this changes in the future, the scripts are left here, commented out, but can +# be resurrected if desired. This could be used to compare *only* the JSON files; +# and in that case, the `llvm-cov show` reports can be ignored by inserting +# `// ignore-llvm-cov-show-diffs` at the top of the source file. +# +# # Generate a coverage report in JSON, using `llvm-cov export`, and fail if +# # there are differences from the expected output. +# "$(LLVM_BIN_DIR)"/llvm-cov export \ +# $(LLVM_COV_IGNORE_FILES) \ +# --summary-only \ +# --instr-profile="$(TMPDIR)"/$@.profdata \ +# $(call BIN,"$(TMPDIR)"/$@) \ +# | "$(PYTHON)" $(BASEDIR)/prettify_json.py \ +# > "$(TMPDIR)"/actual_export_coverage.$@.json +# +# ifdef RUSTC_BLESS_TEST +# cp "$(TMPDIR)"/actual_export_coverage.$@.json expected_export_coverage.$@.json +# else +# # Check that exported JSON coverage data matches what we expect (`--bless` refreshes `expected`) +# $(DIFF) expected_export_coverage.$@.json "$(TMPDIR)"/actual_export_coverage.$@.json +# endif +# +# # # If generating coverage reports in JSON, this Makefile is accompanied by +# # # a Python script, `prettify_json.py`, which is defined: +# # +# # #!/usr/bin/env python +# # +# # import sys +# # import json +# # +# # # Try to decode line in order to ensure it is a valid JSON document +# # for line in sys.stdin: +# # parsed = json.loads(line) +# # print (json.dumps(parsed, indent=2, separators=(',', ': '), sort_keys=True)) diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.abort.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.abort.json deleted file mode 100644 index db7dd0b15e96..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.abort.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/abort.rs", - "summary": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 17, - "percent": 89.47368421052632 - }, - "regions": { - "count": 17, - "covered": 16, - "notcovered": 1, - "percent": 94.11764705882352 - } - } - } - ], - "totals": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 17, - "percent": 89.47368421052632 - }, - "regions": { - "count": 17, - "covered": 16, - "notcovered": 1, - "percent": 94.11764705882352 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json deleted file mode 100644 index bb857ba3f3b3..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/assert.rs", - "summary": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 15, - "covered": 13, - "percent": 86.66666666666667 - }, - "regions": { - "count": 14, - "covered": 13, - "notcovered": 1, - "percent": 92.85714285714286 - } - } - } - ], - "totals": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 15, - "covered": 13, - "percent": 86.66666666666667 - }, - "regions": { - "count": 14, - "covered": 13, - "notcovered": 1, - "percent": 92.85714285714286 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json deleted file mode 100644 index 794a2e382535..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/async.rs", - "summary": { - "functions": { - "count": 17, - "covered": 16, - "percent": 94.11764705882352 - }, - "instantiations": { - "count": 17, - "covered": 16, - "percent": 94.11764705882352 - }, - "lines": { - "count": 105, - "covered": 77, - "percent": 73.33333333333333 - }, - "regions": { - "count": 78, - "covered": 36, - "notcovered": 42, - "percent": 46.15384615384615 - } - } - } - ], - "totals": { - "functions": { - "count": 17, - "covered": 16, - "percent": 94.11764705882352 - }, - "instantiations": { - "count": 17, - "covered": 16, - "percent": 94.11764705882352 - }, - "lines": { - "count": 105, - "covered": 77, - "percent": 73.33333333333333 - }, - "regions": { - "count": 78, - "covered": 36, - "notcovered": 42, - "percent": 46.15384615384615 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.closure.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.closure.json deleted file mode 100644 index 39e1dea66f96..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.closure.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/closure.rs", - "summary": { - "functions": { - "count": 6, - "covered": 4, - "percent": 66.66666666666666 - }, - "instantiations": { - "count": 6, - "covered": 4, - "percent": 66.66666666666666 - }, - "lines": { - "count": 161, - "covered": 131, - "percent": 81.36645962732919 - }, - "regions": { - "count": 42, - "covered": 22, - "notcovered": 20, - "percent": 52.38095238095239 - } - } - } - ], - "totals": { - "functions": { - "count": 6, - "covered": 4, - "percent": 66.66666666666666 - }, - "instantiations": { - "count": 6, - "covered": 4, - "percent": 66.66666666666666 - }, - "lines": { - "count": 161, - "covered": 131, - "percent": 81.36645962732919 - }, - "regions": { - "count": 42, - "covered": 22, - "notcovered": 20, - "percent": 52.38095238095239 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.conditions.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.conditions.json deleted file mode 100644 index 69356604856b..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.conditions.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/conditions.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 64, - "covered": 33, - "percent": 51.5625 - }, - "regions": { - "count": 64, - "covered": 21, - "notcovered": 43, - "percent": 32.8125 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 64, - "covered": 33, - "percent": 51.5625 - }, - "regions": { - "count": 64, - "covered": 21, - "notcovered": 43, - "percent": 32.8125 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.dead_code.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.dead_code.json deleted file mode 100644 index 6588ba90274a..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.dead_code.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/dead_code.rs", - "summary": { - "functions": { - "count": 1, - "covered": 0, - "percent": 0 - }, - "instantiations": { - "count": 1, - "covered": 0, - "percent": 0 - }, - "lines": { - "count": 33, - "covered": 11, - "percent": 33.33333333333333 - }, - "regions": { - "count": 12, - "covered": 3, - "notcovered": 9, - "percent": 25 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 0, - "percent": 0 - }, - "instantiations": { - "count": 1, - "covered": 0, - "percent": 0 - }, - "lines": { - "count": 33, - "covered": 11, - "percent": 33.33333333333333 - }, - "regions": { - "count": 12, - "covered": 3, - "notcovered": 9, - "percent": 25 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.drop_trait.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.drop_trait.json deleted file mode 100644 index e303d3802f51..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.drop_trait.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/drop_trait.rs", - "summary": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 12, - "covered": 12, - "percent": 100 - }, - "regions": { - "count": 4, - "covered": 4, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "totals": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 12, - "covered": 12, - "percent": 100 - }, - "regions": { - "count": 4, - "covered": 4, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.generics.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.generics.json deleted file mode 100644 index bfae69d7ac4d..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.generics.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/generics.rs", - "summary": { - "functions": { - "count": 3, - "covered": 3, - "percent": 100 - }, - "instantiations": { - "count": 5, - "covered": 5, - "percent": 100 - }, - "lines": { - "count": 18, - "covered": 18, - "percent": 100 - }, - "regions": { - "count": 5, - "covered": 5, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "totals": { - "functions": { - "count": 3, - "covered": 3, - "percent": 100 - }, - "instantiations": { - "count": 5, - "covered": 5, - "percent": 100 - }, - "lines": { - "count": 18, - "covered": 18, - "percent": 100 - }, - "regions": { - "count": 5, - "covered": 5, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if.json deleted file mode 100644 index 8f233f8bfc54..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/if.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 26, - "covered": 26, - "percent": 100 - }, - "regions": { - "count": 4, - "covered": 3, - "notcovered": 1, - "percent": 75 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 26, - "covered": 26, - "percent": 100 - }, - "regions": { - "count": 4, - "covered": 3, - "notcovered": 1, - "percent": 75 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if_else.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if_else.json deleted file mode 100644 index 5c0454e1ecbc..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if_else.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/if_else.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 32, - "covered": 23, - "percent": 71.875 - }, - "regions": { - "count": 7, - "covered": 5, - "notcovered": 2, - "percent": 71.42857142857143 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 32, - "covered": 23, - "percent": 71.875 - }, - "regions": { - "count": 7, - "covered": 5, - "notcovered": 2, - "percent": 71.42857142857143 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.inner_items.json deleted file mode 100644 index 07ef9a9ab334..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.inner_items.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/inner_items.rs", - "summary": { - "functions": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "instantiations": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "lines": { - "count": 29, - "covered": 29, - "percent": 100 - }, - "regions": { - "count": 11, - "covered": 9, - "notcovered": 2, - "percent": 81.81818181818183 - } - } - } - ], - "totals": { - "functions": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "instantiations": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "lines": { - "count": 29, - "covered": 29, - "percent": 100 - }, - "regions": { - "count": 11, - "covered": 9, - "notcovered": 2, - "percent": 81.81818181818183 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.lazy_boolean.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.lazy_boolean.json deleted file mode 100644 index c3a96b08e6a2..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.lazy_boolean.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/lazy_boolean.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 44, - "covered": 33, - "percent": 75 - }, - "regions": { - "count": 28, - "covered": 21, - "notcovered": 7, - "percent": 75 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 44, - "covered": 33, - "percent": 75 - }, - "regions": { - "count": 28, - "covered": 21, - "notcovered": 7, - "percent": 75 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loop_break_value.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loop_break_value.json deleted file mode 100644 index 6cb1465c8187..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loop_break_value.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/loop_break_value.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 11, - "covered": 11, - "percent": 100 - }, - "regions": { - "count": 1, - "covered": 1, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 11, - "covered": 11, - "percent": 100 - }, - "regions": { - "count": 1, - "covered": 1, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loops_branches.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loops_branches.json deleted file mode 100644 index 6d566f2b818c..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loops_branches.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/loops_branches.rs", - "summary": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 11, - "covered": 11, - "percent": 100 - }, - "regions": { - "count": 8, - "covered": 7, - "notcovered": 1, - "percent": 87.5 - } - } - } - ], - "totals": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 11, - "covered": 11, - "percent": 100 - }, - "regions": { - "count": 8, - "covered": 7, - "notcovered": 1, - "percent": 87.5 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json deleted file mode 100644 index 8559fc84aa93..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/match_or_pattern.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 37, - "covered": 33, - "percent": 89.1891891891892 - }, - "regions": { - "count": 25, - "covered": 17, - "notcovered": 8, - "percent": 68 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 37, - "covered": 33, - "percent": 89.1891891891892 - }, - "regions": { - "count": 25, - "covered": 17, - "notcovered": 8, - "percent": 68 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.nested_loops.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.nested_loops.json deleted file mode 100644 index bf3b5cb031b9..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.nested_loops.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/nested_loops.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 22, - "covered": 17, - "percent": 77.27272727272727 - }, - "regions": { - "count": 14, - "covered": 11, - "notcovered": 3, - "percent": 78.57142857142857 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 22, - "covered": 17, - "percent": 77.27272727272727 - }, - "regions": { - "count": 14, - "covered": 11, - "notcovered": 3, - "percent": 78.57142857142857 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json deleted file mode 100644 index 128f5888ed11..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/overflow.rs", - "summary": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 23, - "covered": 21, - "percent": 91.30434782608695 - }, - "regions": { - "count": 13, - "covered": 12, - "notcovered": 1, - "percent": 92.3076923076923 - } - } - } - ], - "totals": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 23, - "covered": 21, - "percent": 91.30434782608695 - }, - "regions": { - "count": 13, - "covered": 12, - "notcovered": 1, - "percent": 92.3076923076923 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json deleted file mode 100644 index 9c08dfd41a12..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/panic_unwind.rs", - "summary": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 17, - "percent": 89.47368421052632 - }, - "regions": { - "count": 13, - "covered": 12, - "notcovered": 1, - "percent": 92.3076923076923 - } - } - } - ], - "totals": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 17, - "percent": 89.47368421052632 - }, - "regions": { - "count": 13, - "covered": 12, - "notcovered": 1, - "percent": 92.3076923076923 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.partial_eq.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.partial_eq.json deleted file mode 100644 index 6a0d83a6d0e4..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.partial_eq.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/partial_eq.rs", - "summary": { - "functions": { - "count": 5, - "covered": 4, - "percent": 80 - }, - "instantiations": { - "count": 5, - "covered": 4, - "percent": 80 - }, - "lines": { - "count": 18, - "covered": 16, - "percent": 88.88888888888889 - }, - "regions": { - "count": 24, - "covered": 5, - "notcovered": 19, - "percent": 20.833333333333336 - } - } - } - ], - "totals": { - "functions": { - "count": 5, - "covered": 4, - "percent": 80 - }, - "instantiations": { - "count": 5, - "covered": 4, - "percent": 80 - }, - "lines": { - "count": 18, - "covered": 16, - "percent": 88.88888888888889 - }, - "regions": { - "count": 24, - "covered": 5, - "notcovered": 19, - "percent": 20.833333333333336 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_loop.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_loop.json deleted file mode 100644 index 4c849692a034..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_loop.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/simple_loop.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 25, - "covered": 25, - "percent": 100 - }, - "regions": { - "count": 7, - "covered": 6, - "notcovered": 1, - "percent": 85.71428571428571 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 25, - "covered": 25, - "percent": 100 - }, - "regions": { - "count": 7, - "covered": 6, - "notcovered": 1, - "percent": 85.71428571428571 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_match.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_match.json deleted file mode 100644 index 41bc4d57d59f..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_match.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/simple_match.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 27, - "covered": 27, - "percent": 100 - }, - "regions": { - "count": 11, - "covered": 10, - "notcovered": 1, - "percent": 90.9090909090909 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 27, - "covered": 27, - "percent": 100 - }, - "regions": { - "count": 11, - "covered": 10, - "notcovered": 1, - "percent": 90.9090909090909 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.tight_inf_loop.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.tight_inf_loop.json deleted file mode 100644 index 7f6c90b92d29..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.tight_inf_loop.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/tight_inf_loop.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "regions": { - "count": 2, - "covered": 2, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "regions": { - "count": 2, - "covered": 2, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.try_error_result.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.try_error_result.json deleted file mode 100644 index df4de9dc54bd..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.try_error_result.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/try_error_result.rs", - "summary": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 20, - "covered": 18, - "percent": 90 - }, - "regions": { - "count": 16, - "covered": 12, - "notcovered": 4, - "percent": 75 - } - } - } - ], - "totals": { - "functions": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "instantiations": { - "count": 2, - "covered": 2, - "percent": 100 - }, - "lines": { - "count": 20, - "covered": 18, - "percent": 90 - }, - "regions": { - "count": 16, - "covered": 12, - "notcovered": 4, - "percent": 75 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json deleted file mode 100644 index 35ddd58fc437..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/lib/used_crate.rs", - "summary": { - "functions": { - "count": 6, - "covered": 5, - "percent": 83.33333333333334 - }, - "instantiations": { - "count": 10, - "covered": 8, - "percent": 80 - }, - "lines": { - "count": 46, - "covered": 26, - "percent": 56.52173913043478 - }, - "regions": { - "count": 19, - "covered": 8, - "notcovered": 11, - "percent": 42.10526315789473 - } - } - } - ], - "totals": { - "functions": { - "count": 6, - "covered": 5, - "percent": 83.33333333333334 - }, - "instantiations": { - "count": 10, - "covered": 8, - "percent": 80 - }, - "lines": { - "count": 46, - "covered": 26, - "percent": 56.52173913043478 - }, - "regions": { - "count": 19, - "covered": 8, - "notcovered": 11, - "percent": 42.10526315789473 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while.json deleted file mode 100644 index 339c533ada6d..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/while.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 5, - "covered": 4, - "percent": 80 - }, - "regions": { - "count": 4, - "covered": 3, - "notcovered": 1, - "percent": 75 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 5, - "covered": 4, - "percent": 80 - }, - "regions": { - "count": 4, - "covered": 3, - "notcovered": 1, - "percent": 75 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while_early_ret.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while_early_ret.json deleted file mode 100644 index b7fe2a0fb47d..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while_early_ret.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/while_early_ret.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 17, - "percent": 89.47368421052632 - }, - "regions": { - "count": 9, - "covered": 7, - "notcovered": 2, - "percent": 77.77777777777779 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 17, - "percent": 89.47368421052632 - }, - "regions": { - "count": 9, - "covered": 7, - "notcovered": 2, - "percent": 77.77777777777779 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.yield.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.yield.json deleted file mode 100644 index 6fc41212bc09..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.yield.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/yield.rs", - "summary": { - "functions": { - "count": 3, - "covered": 3, - "percent": 100 - }, - "instantiations": { - "count": 3, - "covered": 3, - "percent": 100 - }, - "lines": { - "count": 26, - "covered": 19, - "percent": 73.07692307692307 - }, - "regions": { - "count": 23, - "covered": 17, - "notcovered": 6, - "percent": 73.91304347826086 - } - } - } - ], - "totals": { - "functions": { - "count": 3, - "covered": 3, - "percent": 100 - }, - "instantiations": { - "count": 3, - "covered": 3, - "percent": 100 - }, - "lines": { - "count": 26, - "covered": 19, - "percent": 73.07692307692307 - }, - "regions": { - "count": 23, - "covered": 17, - "notcovered": 6, - "percent": 73.91304347826086 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.abort.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.abort.txt deleted file mode 100644 index cbf7462eba5e..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.abort.txt +++ /dev/null @@ -1,67 +0,0 @@ -Counter in file 0 14:1 -> 15:27, #1 -Counter in file 0 16:11 -> 16:24, (#1 + (#2 + #3)) -Counter in file 0 17:12 -> 17:25, ((#1 + (#2 + #3)) - #4) -Counter in file 0 17:26 -> 19:10, #5 -Counter in file 0 19:10 -> 19:11, (((#1 + (#2 + #3)) - #4) - #5) -Counter in file 0 21:12 -> 21:25, (#5 + (((#1 + (#2 + #3)) - #4) - #5)) -Counter in file 0 21:26 -> 21:49, #6 -Counter in file 0 21:49 -> 21:50, ((#5 + (((#1 + (#2 + #3)) - #4) - #5)) - #6) -Counter in file 0 25:12 -> 25:25, (#6 + ((#5 + (((#1 + (#2 + #3)) - #4) - #5)) - #6)) -Counter in file 0 25:26 -> 25:49, #2 -Counter in file 0 25:49 -> 25:50, #3 -Counter in file 0 26:9 -> 26:23, (#2 + #3) -Counter in file 0 28:5 -> 29:2, #4 -Counter in file 0 5:1 -> 5:36, #1 -Counter in file 0 6:8 -> 6:20, (#1 + 0) -Counter in file 0 7:9 -> 8:37, #2 -Counter in file 0 9:12 -> 12:2, (#1 - #2) -Emitting segments for file: ../coverage/abort.rs -Combined regions: - 5:1 -> 5:36 (count=12) - 6:8 -> 6:20 (count=12) - 7:9 -> 8:37 (count=0) - 9:12 -> 12:2 (count=12) - 14:1 -> 15:27 (count=1) - 16:11 -> 16:24 (count=11) - 17:12 -> 17:25 (count=10) - 17:26 -> 19:10 (count=4) - 19:10 -> 19:11 (count=6) - 21:12 -> 21:25 (count=10) - 21:26 -> 21:49 (count=4) - 21:49 -> 21:50 (count=6) - 25:12 -> 25:25 (count=10) - 25:26 -> 25:49 (count=4) - 25:49 -> 25:50 (count=6) - 26:9 -> 26:23 (count=10) - 28:5 -> 29:2 (count=1) -Segment at 5:1 (count = 12), RegionEntry -Segment at 5:36 (count = 0), Skipped -Segment at 6:8 (count = 12), RegionEntry -Segment at 6:20 (count = 0), Skipped -Segment at 7:9 (count = 0), RegionEntry -Segment at 8:37 (count = 0), Skipped -Segment at 9:12 (count = 12), RegionEntry -Segment at 12:2 (count = 0), Skipped -Segment at 14:1 (count = 1), RegionEntry -Segment at 15:27 (count = 0), Skipped -Segment at 16:11 (count = 11), RegionEntry -Segment at 16:24 (count = 0), Skipped -Segment at 17:12 (count = 10), RegionEntry -Segment at 17:25 (count = 0), Skipped -Segment at 17:26 (count = 4), RegionEntry -Segment at 19:10 (count = 6), RegionEntry -Segment at 19:11 (count = 0), Skipped -Segment at 21:12 (count = 10), RegionEntry -Segment at 21:25 (count = 0), Skipped -Segment at 21:26 (count = 4), RegionEntry -Segment at 21:49 (count = 6), RegionEntry -Segment at 21:50 (count = 0), Skipped -Segment at 25:12 (count = 10), RegionEntry -Segment at 25:25 (count = 0), Skipped -Segment at 25:26 (count = 4), RegionEntry -Segment at 25:49 (count = 6), RegionEntry -Segment at 25:50 (count = 0), Skipped -Segment at 26:9 (count = 10), RegionEntry -Segment at 26:23 (count = 0), Skipped -Segment at 28:5 (count = 1), RegionEntry -Segment at 29:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt deleted file mode 100644 index 0866a9a59a11..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt +++ /dev/null @@ -1,57 +0,0 @@ -Counter in file 0 9:1 -> 10:27, #1 -Counter in file 0 11:11 -> 11:24, (#1 + (#2 + (#3 + #4))) -Counter in file 0 12:12 -> 12:26, ((#1 + (#2 + (#3 + #4))) - #5) -Counter in file 0 12:27 -> 14:10, #2 -Counter in file 0 14:19 -> 14:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) -Counter in file 0 14:33 -> 16:10, #3 -Counter in file 0 16:10 -> 16:11, #4 -Counter in file 0 17:9 -> 17:23, (#2 + (#3 + #4)) -Counter in file 0 19:5 -> 20:2, #5 -Counter in file 0 4:1 -> 4:41, #1 -Counter in file 0 5:5 -> 5:48, (#1 + 0) -Counter in file 0 6:16 -> 6:21, (#1 + 0) -Counter in file 0 6:37 -> 6:61, #2 -Counter in file 0 7:1 -> 7:2, (#1 - #2) -Emitting segments for file: ../coverage/assert.rs -Combined regions: - 4:1 -> 4:41 (count=4) - 5:5 -> 5:48 (count=4) - 6:16 -> 6:21 (count=4) - 6:37 -> 6:61 (count=1) - 7:1 -> 7:2 (count=3) - 9:1 -> 10:27 (count=1) - 11:11 -> 11:24 (count=11) - 12:12 -> 12:26 (count=11) - 12:27 -> 14:10 (count=1) - 14:19 -> 14:32 (count=10) - 14:33 -> 16:10 (count=3) - 16:10 -> 16:11 (count=6) - 17:9 -> 17:23 (count=10) - 19:5 -> 20:2 (count=0) -Segment at 4:1 (count = 4), RegionEntry -Segment at 4:41 (count = 0), Skipped -Segment at 5:5 (count = 4), RegionEntry -Segment at 5:48 (count = 0), Skipped -Segment at 6:16 (count = 4), RegionEntry -Segment at 6:21 (count = 0), Skipped -Segment at 6:37 (count = 1), RegionEntry -Segment at 6:61 (count = 0), Skipped -Segment at 7:1 (count = 3), RegionEntry -Segment at 7:2 (count = 0), Skipped -Segment at 9:1 (count = 1), RegionEntry -Segment at 10:27 (count = 0), Skipped -Segment at 11:11 (count = 11), RegionEntry -Segment at 11:24 (count = 0), Skipped -Segment at 12:12 (count = 11), RegionEntry -Segment at 12:26 (count = 0), Skipped -Segment at 12:27 (count = 1), RegionEntry -Segment at 14:10 (count = 0), Skipped -Segment at 14:19 (count = 10), RegionEntry -Segment at 14:32 (count = 0), Skipped -Segment at 14:33 (count = 3), RegionEntry -Segment at 16:10 (count = 6), RegionEntry -Segment at 16:11 (count = 0), Skipped -Segment at 17:9 (count = 10), RegionEntry -Segment at 17:23 (count = 0), Skipped -Segment at 19:5 (count = 0), RegionEntry -Segment at 20:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt deleted file mode 100644 index 4df0bac8c866..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt +++ /dev/null @@ -1,311 +0,0 @@ -Counter in file 0 13:1 -> 13:20, #1 -Counter in file 0 15:1 -> 15:20, 0 -Counter in file 0 15:20 -> 15:21, 0 -Counter in file 0 19:1 -> 19:30, 0 -Counter in file 0 19:30 -> 19:31, 0 -Counter in file 0 21:23 -> 22:12, 0 -Counter in file 0 23:9 -> 23:10, 0 -Counter in file 0 23:14 -> 23:17, 0 -Counter in file 0 23:27 -> 23:28, 0 -Counter in file 0 23:32 -> 23:34, 0 -Counter in file 0 24:9 -> 24:10, 0 -Counter in file 0 24:14 -> 24:17, 0 -Counter in file 0 24:27 -> 24:28, 0 -Counter in file 0 24:32 -> 24:34, 0 -Counter in file 0 25:14 -> 25:16, 0 -Counter in file 0 27:1 -> 27:2, 0 -Counter in file 0 29:22 -> 32:12, 0 -Counter in file 0 33:9 -> 33:10, 0 -Counter in file 0 33:14 -> 33:19, 0 -Counter in file 0 33:26 -> 33:27, 0 -Counter in file 0 33:32 -> 33:34, 0 -Counter in file 0 34:14 -> 34:16, 0 -Counter in file 0 36:1 -> 36:2, 0 -Counter in file 0 75:1 -> 76:12, 0 -Counter in file 0 77:14 -> 77:16, 0 -Counter in file 0 78:14 -> 78:16, 0 -Counter in file 0 79:14 -> 79:16, 0 -Counter in file 0 81:1 -> 81:2, 0 -Counter in file 0 91:25 -> 91:34, 0 -Counter in file 0 5:1 -> 5:25, #1 -Counter in file 0 21:1 -> 21:23, #1 -Counter in file 0 17:20 -> 17:21, #1 -Counter in file 0 67:5 -> 67:23, #1 -Counter in file 0 38:1 -> 38:19, #1 -Counter in file 0 38:19 -> 42:12, #1 -Counter in file 0 43:9 -> 43:10, #3 -Counter in file 0 43:14 -> 43:18, (#1 + 0) -Counter in file 0 43:28 -> 43:33, #2 -Counter in file 0 43:39 -> 43:42, (#3 + 0) -Counter in file 0 44:9 -> 44:10, #6 -Counter in file 0 44:14 -> 44:17, #4 -Counter in file 0 44:27 -> 44:32, #8 -Counter in file 0 44:36 -> 44:38, (#6 + 0) -Counter in file 0 45:14 -> 45:16, #7 -Counter in file 0 47:1 -> 47:2, (#5 + (#6 + #7)) -Counter in file 0 13:20 -> 13:21, #1 -Counter in file 0 29:1 -> 29:22, #1 -Counter in file 0 93:1 -> 101:2, #1 -Counter in file 0 91:1 -> 91:25, #1 -Counter in file 0 5:25 -> 6:14, #1 -Counter in file 0 7:9 -> 7:10, #2 -Counter in file 0 9:9 -> 9:10, (#1 - #2) -Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) -Counter in file 0 51:5 -> 52:18, #1 -Counter in file 0 53:13 -> 53:14, #2 -Counter in file 0 63:13 -> 63:14, (#1 - #2) -Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2)) -Counter in file 0 49:1 -> 68:12, #1 -Counter in file 0 69:9 -> 69:10, #2 -Counter in file 0 69:14 -> 69:27, (#1 + 0) -Counter in file 0 69:31 -> 69:39, (#2 + 0) -Counter in file 0 70:9 -> 70:10, #3 -Counter in file 0 70:14 -> 70:26, #5 -Counter in file 0 70:30 -> 70:32, (#3 + 0) -Counter in file 0 71:14 -> 71:16, #4 -Counter in file 0 73:1 -> 73:2, (#2 + (#3 + #4)) -Counter in file 0 83:1 -> 84:12, #1 -Counter in file 0 85:14 -> 85:16, (#1 - (#3 + #2)) -Counter in file 0 86:14 -> 86:16, #2 -Counter in file 0 87:14 -> 87:16, #3 -Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2)))) -Counter in file 0 17:1 -> 17:20, #1 -Counter in file 0 66:5 -> 66:23, #1 -Counter in file 0 17:9 -> 17:10, #1 -Counter in file 0 17:9 -> 17:10, #1 -Counter in file 0 117:17 -> 117:19, #1 -Counter in file 0 17:9 -> 17:10, #1 -Counter in file 0 110:5 -> 120:54, #1 -Counter in file 0 123:32 -> 123:35, ((#1 + #2) - #2) -Counter in file 0 123:39 -> 123:73, (#1 + #2) -Counter in file 0 124:23 -> 124:26, (((#1 + #2) - #2) + 0) -Counter in file 0 125:14 -> 125:15, #2 -Counter in file 0 127:5 -> 127:6, (((#1 + #2) - #2) + 0) -Emitting segments for file: ../coverage/async.rs -Combined regions: - 5:1 -> 5:25 (count=1) - 5:25 -> 6:14 (count=1) - 7:9 -> 7:10 (count=1) - 9:9 -> 9:10 (count=0) - 11:1 -> 11:2 (count=1) - 13:1 -> 13:20 (count=0) - 15:1 -> 15:20 (count=0) - 15:20 -> 15:21 (count=0) - 17:1 -> 17:20 (count=1) - 17:20 -> 17:21 (count=1) - 19:1 -> 19:30 (count=0) - 19:30 -> 19:31 (count=0) - 21:1 -> 21:23 (count=1) - 21:23 -> 22:12 (count=0) - 23:9 -> 23:10 (count=0) - 23:14 -> 23:17 (count=0) - 23:27 -> 23:28 (count=0) - 23:32 -> 23:34 (count=0) - 24:9 -> 24:10 (count=0) - 24:14 -> 24:17 (count=0) - 24:27 -> 24:28 (count=0) - 24:32 -> 24:34 (count=0) - 25:14 -> 25:16 (count=0) - 27:1 -> 27:2 (count=0) - 29:1 -> 29:22 (count=1) - 29:22 -> 32:12 (count=0) - 33:9 -> 33:10 (count=0) - 33:14 -> 33:19 (count=0) - 33:26 -> 33:27 (count=0) - 33:32 -> 33:34 (count=0) - 34:14 -> 34:16 (count=0) - 36:1 -> 36:2 (count=0) - 38:1 -> 38:19 (count=1) - 38:19 -> 42:12 (count=1) - 43:9 -> 43:10 (count=0) - 43:14 -> 43:18 (count=1) - 43:28 -> 43:33 (count=1) - 43:39 -> 43:42 (count=0) - 44:9 -> 44:10 (count=0) - 44:14 -> 44:17 (count=1) - 44:27 -> 44:32 (count=1) - 44:36 -> 44:38 (count=0) - 45:14 -> 45:16 (count=1) - 47:1 -> 47:2 (count=1) - 49:1 -> 68:12 (count=1) - 51:5 -> 52:18 (count=1) - 53:13 -> 53:14 (count=0) - 63:13 -> 63:14 (count=1) - 65:5 -> 65:6 (count=1) - 67:5 -> 67:23 (count=1) - 69:9 -> 69:10 (count=0) - 69:14 -> 69:27 (count=1) - 69:31 -> 69:39 (count=0) - 70:9 -> 70:10 (count=0) - 70:14 -> 70:26 (count=1) - 70:30 -> 70:32 (count=0) - 71:14 -> 71:16 (count=1) - 73:1 -> 73:2 (count=1) - 75:1 -> 76:12 (count=0) - 77:14 -> 77:16 (count=0) - 78:14 -> 78:16 (count=0) - 79:14 -> 79:16 (count=0) - 81:1 -> 81:2 (count=0) - 83:1 -> 84:12 (count=1) - 85:14 -> 85:16 (count=0) - 86:14 -> 86:16 (count=0) - 87:14 -> 87:16 (count=1) - 89:1 -> 89:2 (count=1) - 91:1 -> 91:25 (count=1) - 91:25 -> 91:34 (count=0) - 93:1 -> 101:2 (count=1) - 110:5 -> 120:54 (count=1) - 117:17 -> 117:19 (count=1) - 123:32 -> 123:35 (count=1) - 123:39 -> 123:73 (count=1) - 124:23 -> 124:26 (count=1) - 125:14 -> 125:15 (count=0) - 127:5 -> 127:6 (count=1) -Segment at 5:1 (count = 1), RegionEntry -Segment at 5:25 (count = 1), RegionEntry -Segment at 6:14 (count = 0), Skipped -Segment at 7:9 (count = 1), RegionEntry -Segment at 7:10 (count = 0), Skipped -Segment at 9:9 (count = 0), RegionEntry -Segment at 9:10 (count = 0), Skipped -Segment at 11:1 (count = 1), RegionEntry -Segment at 11:2 (count = 0), Skipped -Segment at 13:1 (count = 0), RegionEntry -Segment at 13:20 (count = 0), Skipped -Segment at 15:1 (count = 0), RegionEntry -Segment at 15:20 (count = 0), RegionEntry -Segment at 15:21 (count = 0), Skipped -Segment at 17:1 (count = 1), RegionEntry -Segment at 17:20 (count = 1), RegionEntry -Segment at 17:21 (count = 0), Skipped -Segment at 19:1 (count = 0), RegionEntry -Segment at 19:30 (count = 0), RegionEntry -Segment at 19:31 (count = 0), Skipped -Segment at 21:1 (count = 1), RegionEntry -Segment at 21:23 (count = 0), RegionEntry -Segment at 22:12 (count = 0), Skipped -Segment at 23:9 (count = 0), RegionEntry -Segment at 23:10 (count = 0), Skipped -Segment at 23:14 (count = 0), RegionEntry -Segment at 23:17 (count = 0), Skipped -Segment at 23:27 (count = 0), RegionEntry -Segment at 23:28 (count = 0), Skipped -Segment at 23:32 (count = 0), RegionEntry -Segment at 23:34 (count = 0), Skipped -Segment at 24:9 (count = 0), RegionEntry -Segment at 24:10 (count = 0), Skipped -Segment at 24:14 (count = 0), RegionEntry -Segment at 24:17 (count = 0), Skipped -Segment at 24:27 (count = 0), RegionEntry -Segment at 24:28 (count = 0), Skipped -Segment at 24:32 (count = 0), RegionEntry -Segment at 24:34 (count = 0), Skipped -Segment at 25:14 (count = 0), RegionEntry -Segment at 25:16 (count = 0), Skipped -Segment at 27:1 (count = 0), RegionEntry -Segment at 27:2 (count = 0), Skipped -Segment at 29:1 (count = 1), RegionEntry -Segment at 29:22 (count = 0), RegionEntry -Segment at 32:12 (count = 0), Skipped -Segment at 33:9 (count = 0), RegionEntry -Segment at 33:10 (count = 0), Skipped -Segment at 33:14 (count = 0), RegionEntry -Segment at 33:19 (count = 0), Skipped -Segment at 33:26 (count = 0), RegionEntry -Segment at 33:27 (count = 0), Skipped -Segment at 33:32 (count = 0), RegionEntry -Segment at 33:34 (count = 0), Skipped -Segment at 34:14 (count = 0), RegionEntry -Segment at 34:16 (count = 0), Skipped -Segment at 36:1 (count = 0), RegionEntry -Segment at 36:2 (count = 0), Skipped -Segment at 38:1 (count = 1), RegionEntry -Segment at 38:19 (count = 1), RegionEntry -Segment at 42:12 (count = 0), Skipped -Segment at 43:9 (count = 0), RegionEntry -Segment at 43:10 (count = 0), Skipped -Segment at 43:14 (count = 1), RegionEntry -Segment at 43:18 (count = 0), Skipped -Segment at 43:28 (count = 1), RegionEntry -Segment at 43:33 (count = 0), Skipped -Segment at 43:39 (count = 0), RegionEntry -Segment at 43:42 (count = 0), Skipped -Segment at 44:9 (count = 0), RegionEntry -Segment at 44:10 (count = 0), Skipped -Segment at 44:14 (count = 1), RegionEntry -Segment at 44:17 (count = 0), Skipped -Segment at 44:27 (count = 1), RegionEntry -Segment at 44:32 (count = 0), Skipped -Segment at 44:36 (count = 0), RegionEntry -Segment at 44:38 (count = 0), Skipped -Segment at 45:14 (count = 1), RegionEntry -Segment at 45:16 (count = 0), Skipped -Segment at 47:1 (count = 1), RegionEntry -Segment at 47:2 (count = 0), Skipped -Segment at 49:1 (count = 1), RegionEntry -Segment at 51:5 (count = 1), RegionEntry -Segment at 52:18 (count = 1) -Segment at 53:13 (count = 0), RegionEntry -Segment at 53:14 (count = 1) -Segment at 63:13 (count = 1), RegionEntry -Segment at 63:14 (count = 1) -Segment at 65:5 (count = 1), RegionEntry -Segment at 65:6 (count = 1) -Segment at 67:5 (count = 1), RegionEntry -Segment at 67:23 (count = 1) -Segment at 68:12 (count = 0), Skipped -Segment at 69:9 (count = 0), RegionEntry -Segment at 69:10 (count = 0), Skipped -Segment at 69:14 (count = 1), RegionEntry -Segment at 69:27 (count = 0), Skipped -Segment at 69:31 (count = 0), RegionEntry -Segment at 69:39 (count = 0), Skipped -Segment at 70:9 (count = 0), RegionEntry -Segment at 70:10 (count = 0), Skipped -Segment at 70:14 (count = 1), RegionEntry -Segment at 70:26 (count = 0), Skipped -Segment at 70:30 (count = 0), RegionEntry -Segment at 70:32 (count = 0), Skipped -Segment at 71:14 (count = 1), RegionEntry -Segment at 71:16 (count = 0), Skipped -Segment at 73:1 (count = 1), RegionEntry -Segment at 73:2 (count = 0), Skipped -Segment at 75:1 (count = 0), RegionEntry -Segment at 76:12 (count = 0), Skipped -Segment at 77:14 (count = 0), RegionEntry -Segment at 77:16 (count = 0), Skipped -Segment at 78:14 (count = 0), RegionEntry -Segment at 78:16 (count = 0), Skipped -Segment at 79:14 (count = 0), RegionEntry -Segment at 79:16 (count = 0), Skipped -Segment at 81:1 (count = 0), RegionEntry -Segment at 81:2 (count = 0), Skipped -Segment at 83:1 (count = 1), RegionEntry -Segment at 84:12 (count = 0), Skipped -Segment at 85:14 (count = 0), RegionEntry -Segment at 85:16 (count = 0), Skipped -Segment at 86:14 (count = 0), RegionEntry -Segment at 86:16 (count = 0), Skipped -Segment at 87:14 (count = 1), RegionEntry -Segment at 87:16 (count = 0), Skipped -Segment at 89:1 (count = 1), RegionEntry -Segment at 89:2 (count = 0), Skipped -Segment at 91:1 (count = 1), RegionEntry -Segment at 91:25 (count = 0), RegionEntry -Segment at 91:34 (count = 0), Skipped -Segment at 93:1 (count = 1), RegionEntry -Segment at 101:2 (count = 0), Skipped -Segment at 110:5 (count = 1), RegionEntry -Segment at 117:17 (count = 1), RegionEntry -Segment at 117:19 (count = 1) -Segment at 120:54 (count = 0), Skipped -Segment at 123:32 (count = 1), RegionEntry -Segment at 123:35 (count = 0), Skipped -Segment at 123:39 (count = 1), RegionEntry -Segment at 123:73 (count = 0), Skipped -Segment at 124:23 (count = 1), RegionEntry -Segment at 124:26 (count = 0), Skipped -Segment at 125:14 (count = 0), RegionEntry -Segment at 125:15 (count = 0), Skipped -Segment at 127:5 (count = 1), RegionEntry -Segment at 127:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.closure.txt deleted file mode 100644 index 1aacac0ed251..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.closure.txt +++ /dev/null @@ -1,153 +0,0 @@ -Counter in file 0 98:5 -> 100:20, #1 -Counter in file 0 100:21 -> 102:10, #2 -Counter in file 0 102:10 -> 102:11, (#1 - #2) -Counter in file 0 103:9 -> 104:6, (#2 + (#1 - #2)) -Counter in file 0 123:5 -> 124:20, 0 -Counter in file 0 124:21 -> 126:10, 0 -Counter in file 0 126:10 -> 126:11, 0 -Counter in file 0 127:9 -> 128:6, 0 -Counter in file 0 131:53 -> 131:67, 0 -Counter in file 0 141:59 -> 141:85, 0 -Counter in file 0 143:56 -> 145:6, 0 -Counter in file 0 149:7 -> 149:33, 0 -Counter in file 0 153:7 -> 153:33, 0 -Counter in file 0 3:1 -> 18:13, #1 -Counter in file 0 25:14 -> 33:9, (#1 + 0) -Counter in file 0 40:6 -> 60:13, (#1 + 0) -Counter in file 0 67:14 -> 75:9, (#1 + 0) -Counter in file 0 82:6 -> 97:9, (#1 + 0) -Counter in file 0 104:6 -> 120:9, (#1 + 0) -Counter in file 0 128:6 -> 131:33, (#1 + 0) -Counter in file 0 131:67 -> 136:33, (#1 + 0) -Counter in file 0 136:75 -> 141:39, (#1 + 0) -Counter in file 0 141:85 -> 143:36, (#1 + 0) -Counter in file 0 145:6 -> 147:36, (#1 + 0) -Counter in file 0 149:33 -> 151:43, (#1 + 0) -Counter in file 0 153:33 -> 155:2, (#1 + 0) -Counter in file 0 61:13 -> 63:28, #1 -Counter in file 0 63:29 -> 65:18, #2 -Counter in file 0 65:18 -> 65:19, (#1 - #2) -Counter in file 0 66:17 -> 67:14, (#2 + (#1 - #2)) -Counter in file 0 76:5 -> 78:20, #1 -Counter in file 0 78:21 -> 80:10, #2 -Counter in file 0 80:10 -> 80:11, (#1 - #2) -Counter in file 0 81:9 -> 82:6, (#2 + (#1 - #2)) -Counter in file 0 34:5 -> 36:20, #1 -Counter in file 0 36:21 -> 38:10, #2 -Counter in file 0 38:10 -> 38:11, (#1 - #2) -Counter in file 0 39:9 -> 40:6, (#2 + (#1 - #2)) -Counter in file 0 19:13 -> 21:28, #1 -Counter in file 0 21:29 -> 23:18, #2 -Counter in file 0 23:18 -> 23:19, (#1 - #2) -Counter in file 0 24:17 -> 25:14, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/closure.rs -Combined regions: - 3:1 -> 18:13 (count=1) - 19:13 -> 21:28 (count=0) - 21:29 -> 23:18 (count=0) - 23:18 -> 23:19 (count=0) - 24:17 -> 25:14 (count=0) - 25:14 -> 33:9 (count=1) - 34:5 -> 36:20 (count=0) - 36:21 -> 38:10 (count=0) - 38:10 -> 38:11 (count=0) - 39:9 -> 40:6 (count=0) - 40:6 -> 60:13 (count=1) - 61:13 -> 63:28 (count=1) - 63:29 -> 65:18 (count=0) - 65:18 -> 65:19 (count=1) - 66:17 -> 67:14 (count=1) - 67:14 -> 75:9 (count=1) - 76:5 -> 78:20 (count=1) - 78:21 -> 80:10 (count=0) - 80:10 -> 80:11 (count=1) - 81:9 -> 82:6 (count=1) - 82:6 -> 97:9 (count=1) - 98:5 -> 100:20 (count=5) - 100:21 -> 102:10 (count=0) - 102:10 -> 102:11 (count=5) - 103:9 -> 104:6 (count=5) - 104:6 -> 120:9 (count=1) - 123:5 -> 124:20 (count=0) - 124:21 -> 126:10 (count=0) - 126:10 -> 126:11 (count=0) - 127:9 -> 128:6 (count=0) - 128:6 -> 131:33 (count=1) - 131:53 -> 131:67 (count=0) - 131:67 -> 136:33 (count=1) - 136:75 -> 141:39 (count=1) - 141:59 -> 141:85 (count=0) - 141:85 -> 143:36 (count=1) - 143:56 -> 145:6 (count=0) - 145:6 -> 147:36 (count=1) - 149:7 -> 149:33 (count=0) - 149:33 -> 151:43 (count=1) - 153:7 -> 153:33 (count=0) - 153:33 -> 155:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 18:13 (count = 0), Skipped -Segment at 19:13 (count = 0), RegionEntry -Segment at 21:28 (count = 0), Skipped -Segment at 21:29 (count = 0), RegionEntry -Segment at 23:18 (count = 0), RegionEntry -Segment at 23:19 (count = 0), Skipped -Segment at 24:17 (count = 0), RegionEntry -Segment at 25:14 (count = 1), RegionEntry -Segment at 33:9 (count = 0), Skipped -Segment at 34:5 (count = 0), RegionEntry -Segment at 36:20 (count = 0), Skipped -Segment at 36:21 (count = 0), RegionEntry -Segment at 38:10 (count = 0), RegionEntry -Segment at 38:11 (count = 0), Skipped -Segment at 39:9 (count = 0), RegionEntry -Segment at 40:6 (count = 1), RegionEntry -Segment at 60:13 (count = 0), Skipped -Segment at 61:13 (count = 1), RegionEntry -Segment at 63:28 (count = 0), Skipped -Segment at 63:29 (count = 0), RegionEntry -Segment at 65:18 (count = 1), RegionEntry -Segment at 65:19 (count = 0), Skipped -Segment at 66:17 (count = 1), RegionEntry -Segment at 67:14 (count = 1), RegionEntry -Segment at 75:9 (count = 0), Skipped -Segment at 76:5 (count = 1), RegionEntry -Segment at 78:20 (count = 0), Skipped -Segment at 78:21 (count = 0), RegionEntry -Segment at 80:10 (count = 1), RegionEntry -Segment at 80:11 (count = 0), Skipped -Segment at 81:9 (count = 1), RegionEntry -Segment at 82:6 (count = 1), RegionEntry -Segment at 97:9 (count = 0), Skipped -Segment at 98:5 (count = 5), RegionEntry -Segment at 100:20 (count = 0), Skipped -Segment at 100:21 (count = 0), RegionEntry -Segment at 102:10 (count = 5), RegionEntry -Segment at 102:11 (count = 0), Skipped -Segment at 103:9 (count = 5), RegionEntry -Segment at 104:6 (count = 1), RegionEntry -Segment at 120:9 (count = 0), Skipped -Segment at 123:5 (count = 0), RegionEntry -Segment at 124:20 (count = 0), Skipped -Segment at 124:21 (count = 0), RegionEntry -Segment at 126:10 (count = 0), RegionEntry -Segment at 126:11 (count = 0), Skipped -Segment at 127:9 (count = 0), RegionEntry -Segment at 128:6 (count = 1), RegionEntry -Segment at 131:33 (count = 0), Skipped -Segment at 131:53 (count = 0), RegionEntry -Segment at 131:67 (count = 1), RegionEntry -Segment at 136:33 (count = 0), Skipped -Segment at 136:75 (count = 1), RegionEntry -Segment at 141:39 (count = 0), Skipped -Segment at 141:59 (count = 0), RegionEntry -Segment at 141:85 (count = 1), RegionEntry -Segment at 143:36 (count = 0), Skipped -Segment at 143:56 (count = 0), RegionEntry -Segment at 145:6 (count = 1), RegionEntry -Segment at 147:36 (count = 0), Skipped -Segment at 149:7 (count = 0), RegionEntry -Segment at 149:33 (count = 1), RegionEntry -Segment at 151:43 (count = 0), Skipped -Segment at 153:7 (count = 0), RegionEntry -Segment at 153:33 (count = 1), RegionEntry -Segment at 155:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.conditions.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.conditions.txt deleted file mode 100644 index 3a9c6a9b92e9..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.conditions.txt +++ /dev/null @@ -1,253 +0,0 @@ -Counter in file 0 3:1 -> 3:11, #1 -Counter in file 0 4:9 -> 5:12, (#1 + 0) -Counter in file 0 5:13 -> 7:6, #2 -Counter in file 0 10:9 -> 10:10, (#3 + (#12 + #13)) -Counter in file 0 10:16 -> 10:29, (#2 + 0) -Counter in file 0 11:9 -> 12:10, #3 -Counter in file 0 13:15 -> 13:28, ((#2 + 0) - #3) -Counter in file 0 14:12 -> 14:25, #4 -Counter in file 0 14:29 -> 14:42, (#4 - #15) -Counter in file 0 14:46 -> 14:60, #21 -Counter in file 0 14:61 -> 16:10, #12 -Counter in file 0 16:10 -> 16:11, #13 -Counter in file 0 17:9 -> 18:18, (#12 + #13) -Counter in file 0 20:9 -> 20:15, (((#2 + 0) - #3) - #4) -Counter in file 0 23:9 -> 24:12, ((#3 + (#12 + #13)) + 0) -Counter in file 0 24:13 -> 26:6, #14 -Counter in file 0 28:8 -> 28:21, (#14 + 0) -Counter in file 0 28:22 -> 30:6, #16 -Counter in file 0 30:15 -> 30:28, ((#14 + 0) - #16) -Counter in file 0 31:12 -> 31:25, (((#14 + 0) - #16) - #11) -Counter in file 0 31:29 -> 31:42, ((((#14 + 0) - #16) - #11) - #23) -Counter in file 0 31:46 -> 31:60, #31 -Counter in file 0 31:61 -> 33:10, #18 -Counter in file 0 33:10 -> 33:11, #19 -Counter in file 0 34:9 -> 34:23, (#18 + #19) -Counter in file 0 36:9 -> 36:15, #11 -Counter in file 0 39:8 -> 39:12, (#16 + (#18 + #19)) -Counter in file 0 40:13 -> 41:16, #20 -Counter in file 0 41:17 -> 43:10, #24 -Counter in file 0 45:12 -> 45:25, (#24 + 0) -Counter in file 0 45:26 -> 47:10, #25 -Counter in file 0 48:17 -> 48:30, ((#24 + 0) - #25) -Counter in file 0 49:16 -> 49:29, (((#24 + 0) - #25) - #10) -Counter in file 0 49:33 -> 49:46, ((((#24 + 0) - #25) - #10) - #35) -Counter in file 0 49:50 -> 49:64, #40 -Counter in file 0 49:65 -> 51:14, #26 -Counter in file 0 51:14 -> 51:15, #27 -Counter in file 0 52:13 -> 52:27, (#26 + #27) -Counter in file 0 54:13 -> 54:19, #10 -Counter in file 0 59:9 -> 60:12, ((#25 + (#26 + #27)) + 0) -Counter in file 0 60:13 -> 62:6, #28 -Counter in file 0 64:9 -> 64:10, (#30 + (#33 + #34)) -Counter in file 0 64:16 -> 64:29, (#28 + 0) -Counter in file 0 64:30 -> 66:6, #30 -Counter in file 0 66:15 -> 66:28, ((#28 + 0) - #30) -Counter in file 0 67:12 -> 67:25, (((#28 + 0) - #30) - #9) -Counter in file 0 67:29 -> 67:42, ((((#28 + 0) - #30) - #9) - #36) -Counter in file 0 67:46 -> 67:60, #42 -Counter in file 0 67:61 -> 69:10, #33 -Counter in file 0 69:10 -> 69:11, #34 -Counter in file 0 70:9 -> 70:23, (#33 + #34) -Counter in file 0 72:13 -> 74:15, #9 -Counter in file 0 77:9 -> 77:10, (#5 + (#6 + #7)) -Counter in file 0 77:16 -> 77:29, ((#30 + (#33 + #34)) + 0) -Counter in file 0 77:30 -> 79:6, #5 -Counter in file 0 79:15 -> 79:28, ((#30 + (#33 + #34)) - #5) -Counter in file 0 80:12 -> 80:25, (((#30 + (#33 + #34)) - #5) - #8) -Counter in file 0 80:29 -> 80:42, ((((#30 + (#33 + #34)) - #5) - #8) - #39) -Counter in file 0 80:46 -> 80:60, #45 -Counter in file 0 80:61 -> 82:10, #6 -Counter in file 0 82:10 -> 82:11, #7 -Counter in file 0 83:9 -> 83:23, (#6 + #7) -Counter in file 0 85:9 -> 85:15, #8 -Counter in file 0 87:1 -> 87:2, ((#5 + (#6 + #7)) + (((#8 + #9) + (#10 + #11)) + (((#2 + 0) - #3) - #4))) -Emitting segments for file: ../coverage/conditions.rs -Combined regions: - 3:1 -> 3:11 (count=1) - 4:9 -> 5:12 (count=1) - 5:13 -> 7:6 (count=1) - 10:9 -> 10:10 (count=1) - 10:16 -> 10:29 (count=1) - 11:9 -> 12:10 (count=1) - 13:15 -> 13:28 (count=0) - 14:12 -> 14:25 (count=0) - 14:29 -> 14:42 (count=0) - 14:46 -> 14:60 (count=0) - 14:61 -> 16:10 (count=0) - 16:10 -> 16:11 (count=0) - 17:9 -> 18:18 (count=0) - 20:9 -> 20:15 (count=0) - 23:9 -> 24:12 (count=1) - 24:13 -> 26:6 (count=1) - 28:8 -> 28:21 (count=1) - 28:22 -> 30:6 (count=1) - 30:15 -> 30:28 (count=0) - 31:12 -> 31:25 (count=0) - 31:29 -> 31:42 (count=0) - 31:46 -> 31:60 (count=0) - 31:61 -> 33:10 (count=0) - 33:10 -> 33:11 (count=0) - 34:9 -> 34:23 (count=0) - 36:9 -> 36:15 (count=0) - 39:8 -> 39:12 (count=1) - 40:13 -> 41:16 (count=1) - 41:17 -> 43:10 (count=1) - 45:12 -> 45:25 (count=1) - 45:26 -> 47:10 (count=1) - 48:17 -> 48:30 (count=0) - 49:16 -> 49:29 (count=0) - 49:33 -> 49:46 (count=0) - 49:50 -> 49:64 (count=0) - 49:65 -> 51:14 (count=0) - 51:14 -> 51:15 (count=0) - 52:13 -> 52:27 (count=0) - 54:13 -> 54:19 (count=0) - 59:9 -> 60:12 (count=1) - 60:13 -> 62:6 (count=1) - 64:9 -> 64:10 (count=0) - 64:16 -> 64:29 (count=1) - 64:30 -> 66:6 (count=0) - 66:15 -> 66:28 (count=1) - 67:12 -> 67:25 (count=0) - 67:29 -> 67:42 (count=0) - 67:46 -> 67:60 (count=0) - 67:61 -> 69:10 (count=0) - 69:10 -> 69:11 (count=0) - 70:9 -> 70:23 (count=0) - 72:13 -> 74:15 (count=1) - 77:9 -> 77:10 (count=0) - 77:16 -> 77:29 (count=0) - 77:30 -> 79:6 (count=0) - 79:15 -> 79:28 (count=0) - 80:12 -> 80:25 (count=0) - 80:29 -> 80:42 (count=0) - 80:46 -> 80:60 (count=0) - 80:61 -> 82:10 (count=0) - 82:10 -> 82:11 (count=0) - 83:9 -> 83:23 (count=0) - 85:9 -> 85:15 (count=0) - 87:1 -> 87:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 3:11 (count = 0), Skipped -Segment at 4:9 (count = 1), RegionEntry -Segment at 5:12 (count = 0), Skipped -Segment at 5:13 (count = 1), RegionEntry -Segment at 7:6 (count = 0), Skipped -Segment at 10:9 (count = 1), RegionEntry -Segment at 10:10 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 10:29 (count = 0), Skipped -Segment at 11:9 (count = 1), RegionEntry -Segment at 12:10 (count = 0), Skipped -Segment at 13:15 (count = 0), RegionEntry -Segment at 13:28 (count = 0), Skipped -Segment at 14:12 (count = 0), RegionEntry -Segment at 14:25 (count = 0), Skipped -Segment at 14:29 (count = 0), RegionEntry -Segment at 14:42 (count = 0), Skipped -Segment at 14:46 (count = 0), RegionEntry -Segment at 14:60 (count = 0), Skipped -Segment at 14:61 (count = 0), RegionEntry -Segment at 16:10 (count = 0), RegionEntry -Segment at 16:11 (count = 0), Skipped -Segment at 17:9 (count = 0), RegionEntry -Segment at 18:18 (count = 0), Skipped -Segment at 20:9 (count = 0), RegionEntry -Segment at 20:15 (count = 0), Skipped -Segment at 23:9 (count = 1), RegionEntry -Segment at 24:12 (count = 0), Skipped -Segment at 24:13 (count = 1), RegionEntry -Segment at 26:6 (count = 0), Skipped -Segment at 28:8 (count = 1), RegionEntry -Segment at 28:21 (count = 0), Skipped -Segment at 28:22 (count = 1), RegionEntry -Segment at 30:6 (count = 0), Skipped -Segment at 30:15 (count = 0), RegionEntry -Segment at 30:28 (count = 0), Skipped -Segment at 31:12 (count = 0), RegionEntry -Segment at 31:25 (count = 0), Skipped -Segment at 31:29 (count = 0), RegionEntry -Segment at 31:42 (count = 0), Skipped -Segment at 31:46 (count = 0), RegionEntry -Segment at 31:60 (count = 0), Skipped -Segment at 31:61 (count = 0), RegionEntry -Segment at 33:10 (count = 0), RegionEntry -Segment at 33:11 (count = 0), Skipped -Segment at 34:9 (count = 0), RegionEntry -Segment at 34:23 (count = 0), Skipped -Segment at 36:9 (count = 0), RegionEntry -Segment at 36:15 (count = 0), Skipped -Segment at 39:8 (count = 1), RegionEntry -Segment at 39:12 (count = 0), Skipped -Segment at 40:13 (count = 1), RegionEntry -Segment at 41:16 (count = 0), Skipped -Segment at 41:17 (count = 1), RegionEntry -Segment at 43:10 (count = 0), Skipped -Segment at 45:12 (count = 1), RegionEntry -Segment at 45:25 (count = 0), Skipped -Segment at 45:26 (count = 1), RegionEntry -Segment at 47:10 (count = 0), Skipped -Segment at 48:17 (count = 0), RegionEntry -Segment at 48:30 (count = 0), Skipped -Segment at 49:16 (count = 0), RegionEntry -Segment at 49:29 (count = 0), Skipped -Segment at 49:33 (count = 0), RegionEntry -Segment at 49:46 (count = 0), Skipped -Segment at 49:50 (count = 0), RegionEntry -Segment at 49:64 (count = 0), Skipped -Segment at 49:65 (count = 0), RegionEntry -Segment at 51:14 (count = 0), RegionEntry -Segment at 51:15 (count = 0), Skipped -Segment at 52:13 (count = 0), RegionEntry -Segment at 52:27 (count = 0), Skipped -Segment at 54:13 (count = 0), RegionEntry -Segment at 54:19 (count = 0), Skipped -Segment at 59:9 (count = 1), RegionEntry -Segment at 60:12 (count = 0), Skipped -Segment at 60:13 (count = 1), RegionEntry -Segment at 62:6 (count = 0), Skipped -Segment at 64:9 (count = 0), RegionEntry -Segment at 64:10 (count = 0), Skipped -Segment at 64:16 (count = 1), RegionEntry -Segment at 64:29 (count = 0), Skipped -Segment at 64:30 (count = 0), RegionEntry -Segment at 66:6 (count = 0), Skipped -Segment at 66:15 (count = 1), RegionEntry -Segment at 66:28 (count = 0), Skipped -Segment at 67:12 (count = 0), RegionEntry -Segment at 67:25 (count = 0), Skipped -Segment at 67:29 (count = 0), RegionEntry -Segment at 67:42 (count = 0), Skipped -Segment at 67:46 (count = 0), RegionEntry -Segment at 67:60 (count = 0), Skipped -Segment at 67:61 (count = 0), RegionEntry -Segment at 69:10 (count = 0), RegionEntry -Segment at 69:11 (count = 0), Skipped -Segment at 70:9 (count = 0), RegionEntry -Segment at 70:23 (count = 0), Skipped -Segment at 72:13 (count = 1), RegionEntry -Segment at 74:15 (count = 0), Skipped -Segment at 77:9 (count = 0), RegionEntry -Segment at 77:10 (count = 0), Skipped -Segment at 77:16 (count = 0), RegionEntry -Segment at 77:29 (count = 0), Skipped -Segment at 77:30 (count = 0), RegionEntry -Segment at 79:6 (count = 0), Skipped -Segment at 79:15 (count = 0), RegionEntry -Segment at 79:28 (count = 0), Skipped -Segment at 80:12 (count = 0), RegionEntry -Segment at 80:25 (count = 0), Skipped -Segment at 80:29 (count = 0), RegionEntry -Segment at 80:42 (count = 0), Skipped -Segment at 80:46 (count = 0), RegionEntry -Segment at 80:60 (count = 0), Skipped -Segment at 80:61 (count = 0), RegionEntry -Segment at 82:10 (count = 0), RegionEntry -Segment at 82:11 (count = 0), Skipped -Segment at 83:9 (count = 0), RegionEntry -Segment at 83:23 (count = 0), Skipped -Segment at 85:9 (count = 0), RegionEntry -Segment at 85:15 (count = 0), Skipped -Segment at 87:1 (count = 1), RegionEntry -Segment at 87:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.dead_code.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.dead_code.txt deleted file mode 100644 index a2187d477c82..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.dead_code.txt +++ /dev/null @@ -1,47 +0,0 @@ -Counter in file 0 3:1 -> 10:15, 0 -Counter in file 0 10:16 -> 12:6, 0 -Counter in file 0 12:6 -> 12:7, 0 -Counter in file 0 13:1 -> 13:2, 0 -Counter in file 0 15:1 -> 22:15, 0 -Counter in file 0 22:16 -> 24:6, 0 -Counter in file 0 24:6 -> 24:7, 0 -Counter in file 0 25:1 -> 25:2, 0 -Counter in file 0 27:1 -> 34:15, #1 -Counter in file 0 34:16 -> 36:6, #2 -Counter in file 0 36:6 -> 36:7, (#1 - #2) -Counter in file 0 37:1 -> 37:2, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/dead_code.rs -Combined regions: - 3:1 -> 10:15 (count=0) - 10:16 -> 12:6 (count=0) - 12:6 -> 12:7 (count=0) - 13:1 -> 13:2 (count=0) - 15:1 -> 22:15 (count=0) - 22:16 -> 24:6 (count=0) - 24:6 -> 24:7 (count=0) - 25:1 -> 25:2 (count=0) - 27:1 -> 34:15 (count=1) - 34:16 -> 36:6 (count=1) - 36:6 -> 36:7 (count=0) - 37:1 -> 37:2 (count=1) -Segment at 3:1 (count = 0), RegionEntry -Segment at 10:15 (count = 0), Skipped -Segment at 10:16 (count = 0), RegionEntry -Segment at 12:6 (count = 0), RegionEntry -Segment at 12:7 (count = 0), Skipped -Segment at 13:1 (count = 0), RegionEntry -Segment at 13:2 (count = 0), Skipped -Segment at 15:1 (count = 0), RegionEntry -Segment at 22:15 (count = 0), Skipped -Segment at 22:16 (count = 0), RegionEntry -Segment at 24:6 (count = 0), RegionEntry -Segment at 24:7 (count = 0), Skipped -Segment at 25:1 (count = 0), RegionEntry -Segment at 25:2 (count = 0), Skipped -Segment at 27:1 (count = 1), RegionEntry -Segment at 34:15 (count = 0), Skipped -Segment at 34:16 (count = 1), RegionEntry -Segment at 36:6 (count = 0), RegionEntry -Segment at 36:7 (count = 0), Skipped -Segment at 37:1 (count = 1), RegionEntry -Segment at 37:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.drop_trait.txt deleted file mode 100644 index 66c51e3a2982..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.drop_trait.txt +++ /dev/null @@ -1,18 +0,0 @@ -Counter in file 0 9:5 -> 11:6, #1 -Counter in file 0 14:1 -> 19:12, #1 -Counter in file 0 20:9 -> 21:22, #2 -Counter in file 0 27:1 -> 27:2, (#2 + 0) -Emitting segments for file: ../coverage/drop_trait.rs -Combined regions: - 9:5 -> 11:6 (count=2) - 14:1 -> 19:12 (count=1) - 20:9 -> 21:22 (count=1) - 27:1 -> 27:2 (count=1) -Segment at 9:5 (count = 2), RegionEntry -Segment at 11:6 (count = 0), Skipped -Segment at 14:1 (count = 1), RegionEntry -Segment at 19:12 (count = 0), Skipped -Segment at 20:9 (count = 1), RegionEntry -Segment at 21:22 (count = 0), Skipped -Segment at 27:1 (count = 1), RegionEntry -Segment at 27:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt deleted file mode 100644 index e2cbf6f709e6..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt +++ /dev/null @@ -1,44 +0,0 @@ -Counter in file 0 17:5 -> 19:6, #1 -Counter in file 0 17:5 -> 19:6, #1 -Counter in file 0 22:1 -> 30:12, #1 -Counter in file 0 31:9 -> 32:22, #2 -Counter in file 0 42:1 -> 42:2, (#2 + 0) -Counter in file 0 10:5 -> 12:6, #1 -Counter in file 0 10:5 -> 12:6, #1 -Emitting segments for file: ../coverage/generics.rs -Combined regions: - 10:5 -> 12:6 (count=3) - 17:5 -> 19:6 (count=2) - 22:1 -> 30:12 (count=1) - 31:9 -> 32:22 (count=1) - 42:1 -> 42:2 (count=1) -Segment at 10:5 (count = 3), RegionEntry -Segment at 12:6 (count = 0), Skipped -Segment at 17:5 (count = 2), RegionEntry -Segment at 19:6 (count = 0), Skipped -Segment at 22:1 (count = 1), RegionEntry -Segment at 30:12 (count = 0), Skipped -Segment at 31:9 (count = 1), RegionEntry -Segment at 32:22 (count = 0), Skipped -Segment at 42:1 (count = 1), RegionEntry -Segment at 42:2 (count = 0), Skipped -Emitting segments for function: _RNvMCs4fqI2P2rA04_8genericsINtB2_8FireworkdE12set_strengthB2_ -Combined regions: - 10:5 -> 12:6 (count=2) -Segment at 10:5 (count = 2), RegionEntry -Segment at 12:6 (count = 0), Skipped -Emitting segments for function: _RNvMCs4fqI2P2rA04_8genericsINtB2_8FireworklE12set_strengthB2_ -Combined regions: - 10:5 -> 12:6 (count=1) -Segment at 10:5 (count = 1), RegionEntry -Segment at 12:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworklENtNtNtCs3rFBWs28XFJ_4core3ops4drop4Drop4dropB4_ -Combined regions: - 17:5 -> 19:6 (count=1) -Segment at 17:5 (count = 1), RegionEntry -Segment at 19:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworkdENtNtNtCs3rFBWs28XFJ_4core3ops4drop4Drop4dropB4_ -Combined regions: - 17:5 -> 19:6 (count=1) -Segment at 17:5 (count = 1), RegionEntry -Segment at 19:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if.txt deleted file mode 100644 index 2e802a462ea2..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if.txt +++ /dev/null @@ -1,17 +0,0 @@ -Counter in file 0 3:1 -> 21:16, #1 -Counter in file 0 22:5 -> 27:6, #2 -Counter in file 0 27:6 -> 27:7, (#1 - #2) -Counter in file 0 28:1 -> 28:2, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/if.rs -Combined regions: - 3:1 -> 21:16 (count=1) - 22:5 -> 27:6 (count=1) - 27:6 -> 27:7 (count=0) - 28:1 -> 28:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 21:16 (count = 0), Skipped -Segment at 22:5 (count = 1), RegionEntry -Segment at 27:6 (count = 0), RegionEntry -Segment at 27:7 (count = 0), Skipped -Segment at 28:1 (count = 1), RegionEntry -Segment at 28:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if_else.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if_else.txt deleted file mode 100644 index 03b35b0f0099..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if_else.txt +++ /dev/null @@ -1,30 +0,0 @@ -Counter in file 0 3:1 -> 11:16, #1 -Counter in file 0 12:5 -> 17:6, #2 -Counter in file 0 20:9 -> 22:16, (#1 - #2) -Counter in file 0 26:9 -> 26:16, (#2 + (#1 - #2)) -Counter in file 0 27:5 -> 32:6, #3 -Counter in file 0 34:5 -> 39:6, ((#2 + (#1 - #2)) - #3) -Counter in file 0 40:1 -> 40:2, (#3 + ((#2 + (#1 - #2)) - #3)) -Emitting segments for file: ../coverage/if_else.rs -Combined regions: - 3:1 -> 11:16 (count=1) - 12:5 -> 17:6 (count=1) - 20:9 -> 22:16 (count=0) - 26:9 -> 26:16 (count=1) - 27:5 -> 32:6 (count=1) - 34:5 -> 39:6 (count=0) - 40:1 -> 40:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 11:16 (count = 0), Skipped -Segment at 12:5 (count = 1), RegionEntry -Segment at 17:6 (count = 0), Skipped -Segment at 20:9 (count = 0), RegionEntry -Segment at 22:16 (count = 0), Skipped -Segment at 26:9 (count = 1), RegionEntry -Segment at 26:16 (count = 0), Skipped -Segment at 27:5 (count = 1), RegionEntry -Segment at 32:6 (count = 0), Skipped -Segment at 34:5 (count = 0), RegionEntry -Segment at 39:6 (count = 0), Skipped -Segment at 40:1 (count = 1), RegionEntry -Segment at 40:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.inner_items.txt deleted file mode 100644 index 5dc704d6149f..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.inner_items.txt +++ /dev/null @@ -1,44 +0,0 @@ -Counter in file 0 18:5 -> 22:6, #1 -Counter in file 0 3:1 -> 3:11, #1 -Counter in file 0 7:9 -> 10:15, (#1 + 0) -Counter in file 0 10:16 -> 12:6, #2 -Counter in file 0 12:6 -> 12:7, (#1 - #2) -Counter in file 0 48:8 -> 48:15, (#2 + (#1 - #2)) -Counter in file 0 48:16 -> 50:6, #3 -Counter in file 0 50:6 -> 50:7, ((#2 + (#1 - #2)) - #3) -Counter in file 0 52:9 -> 57:2, (#3 + ((#2 + (#1 - #2)) - #3)) -Counter in file 0 33:9 -> 36:10, #1 -Counter in file 0 40:9 -> 43:10, #1 -Emitting segments for file: ../coverage/inner_items.rs -Combined regions: - 3:1 -> 3:11 (count=1) - 7:9 -> 10:15 (count=1) - 10:16 -> 12:6 (count=1) - 12:6 -> 12:7 (count=0) - 18:5 -> 22:6 (count=3) - 33:9 -> 36:10 (count=1) - 40:9 -> 43:10 (count=1) - 48:8 -> 48:15 (count=1) - 48:16 -> 50:6 (count=1) - 50:6 -> 50:7 (count=0) - 52:9 -> 57:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 3:11 (count = 0), Skipped -Segment at 7:9 (count = 1), RegionEntry -Segment at 10:15 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 12:6 (count = 0), RegionEntry -Segment at 12:7 (count = 0), Skipped -Segment at 18:5 (count = 3), RegionEntry -Segment at 22:6 (count = 0), Skipped -Segment at 33:9 (count = 1), RegionEntry -Segment at 36:10 (count = 0), Skipped -Segment at 40:9 (count = 1), RegionEntry -Segment at 43:10 (count = 0), Skipped -Segment at 48:8 (count = 1), RegionEntry -Segment at 48:15 (count = 0), Skipped -Segment at 48:16 (count = 1), RegionEntry -Segment at 50:6 (count = 0), RegionEntry -Segment at 50:7 (count = 0), Skipped -Segment at 52:9 (count = 1), RegionEntry -Segment at 57:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.lazy_boolean.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.lazy_boolean.txt deleted file mode 100644 index d5667fb861e2..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.lazy_boolean.txt +++ /dev/null @@ -1,111 +0,0 @@ -Counter in file 0 3:1 -> 10:15, #1 -Counter in file 0 10:16 -> 14:6, #2 -Counter in file 0 14:6 -> 14:7, (#1 - #2) -Counter in file 0 16:9 -> 16:17, ((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) -Counter in file 0 18:13 -> 18:18, (#2 + (#1 - #2)) -Counter in file 0 20:13 -> 20:18, ((#2 + (#1 - #2)) - #3) -Counter in file 0 23:9 -> 23:17, ((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) -Counter in file 0 25:13 -> 25:18, (((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) + 0) -Counter in file 0 27:13 -> 27:18, (((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) -Counter in file 0 29:9 -> 29:17, (#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) -Counter in file 0 29:20 -> 29:25, (((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) + 0) -Counter in file 0 29:29 -> 29:34, #7 -Counter in file 0 30:9 -> 30:17, (#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) -Counter in file 0 30:20 -> 30:25, ((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) + 0) -Counter in file 0 30:29 -> 30:34, #9 -Counter in file 0 33:9 -> 34:16, ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) + 0) -Counter in file 0 35:5 -> 38:6, #11 -Counter in file 0 38:6 -> 38:7, ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11) -Counter in file 0 41:9 -> 41:16, (#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) -Counter in file 0 42:5 -> 45:6, #12 -Counter in file 0 47:5 -> 50:6, ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12) -Counter in file 0 52:8 -> 52:16, (#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) -Counter in file 0 52:17 -> 54:6, #13 -Counter in file 0 54:6 -> 54:7, ((#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) - #13) -Counter in file 0 56:8 -> 56:15, (#13 + ((#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) - #13)) -Counter in file 0 56:16 -> 58:6, #14 -Counter in file 0 58:12 -> 60:6, ((#13 + ((#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) - #13)) - #14) -Counter in file 0 61:1 -> 61:2, (#14 + ((#13 + ((#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) - #13)) - #14)) -Emitting segments for file: ../coverage/lazy_boolean.rs -Combined regions: - 3:1 -> 10:15 (count=1) - 10:16 -> 14:6 (count=1) - 14:6 -> 14:7 (count=0) - 16:9 -> 16:17 (count=1) - 18:13 -> 18:18 (count=1) - 20:13 -> 20:18 (count=0) - 23:9 -> 23:17 (count=1) - 25:13 -> 25:18 (count=1) - 27:13 -> 27:18 (count=1) - 29:9 -> 29:17 (count=1) - 29:20 -> 29:25 (count=1) - 29:29 -> 29:34 (count=1) - 30:9 -> 30:17 (count=1) - 30:20 -> 30:25 (count=1) - 30:29 -> 30:34 (count=0) - 33:9 -> 34:16 (count=1) - 35:5 -> 38:6 (count=0) - 38:6 -> 38:7 (count=1) - 41:9 -> 41:16 (count=1) - 42:5 -> 45:6 (count=1) - 47:5 -> 50:6 (count=0) - 52:8 -> 52:16 (count=1) - 52:17 -> 54:6 (count=0) - 54:6 -> 54:7 (count=1) - 56:8 -> 56:15 (count=1) - 56:16 -> 58:6 (count=1) - 58:12 -> 60:6 (count=0) - 61:1 -> 61:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 10:15 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 14:6 (count = 0), RegionEntry -Segment at 14:7 (count = 0), Skipped -Segment at 16:9 (count = 1), RegionEntry -Segment at 16:17 (count = 0), Skipped -Segment at 18:13 (count = 1), RegionEntry -Segment at 18:18 (count = 0), Skipped -Segment at 20:13 (count = 0), RegionEntry -Segment at 20:18 (count = 0), Skipped -Segment at 23:9 (count = 1), RegionEntry -Segment at 23:17 (count = 0), Skipped -Segment at 25:13 (count = 1), RegionEntry -Segment at 25:18 (count = 0), Skipped -Segment at 27:13 (count = 1), RegionEntry -Segment at 27:18 (count = 0), Skipped -Segment at 29:9 (count = 1), RegionEntry -Segment at 29:17 (count = 0), Skipped -Segment at 29:20 (count = 1), RegionEntry -Segment at 29:25 (count = 0), Skipped -Segment at 29:29 (count = 1), RegionEntry -Segment at 29:34 (count = 0), Skipped -Segment at 30:9 (count = 1), RegionEntry -Segment at 30:17 (count = 0), Skipped -Segment at 30:20 (count = 1), RegionEntry -Segment at 30:25 (count = 0), Skipped -Segment at 30:29 (count = 0), RegionEntry -Segment at 30:34 (count = 0), Skipped -Segment at 33:9 (count = 1), RegionEntry -Segment at 34:16 (count = 0), Skipped -Segment at 35:5 (count = 0), RegionEntry -Segment at 38:6 (count = 1), RegionEntry -Segment at 38:7 (count = 0), Skipped -Segment at 41:9 (count = 1), RegionEntry -Segment at 41:16 (count = 0), Skipped -Segment at 42:5 (count = 1), RegionEntry -Segment at 45:6 (count = 0), Skipped -Segment at 47:5 (count = 0), RegionEntry -Segment at 50:6 (count = 0), Skipped -Segment at 52:8 (count = 1), RegionEntry -Segment at 52:16 (count = 0), Skipped -Segment at 52:17 (count = 0), RegionEntry -Segment at 54:6 (count = 1), RegionEntry -Segment at 54:7 (count = 0), Skipped -Segment at 56:8 (count = 1), RegionEntry -Segment at 56:15 (count = 0), Skipped -Segment at 56:16 (count = 1), RegionEntry -Segment at 58:6 (count = 0), Skipped -Segment at 58:12 (count = 0), RegionEntry -Segment at 60:6 (count = 0), Skipped -Segment at 61:1 (count = 1), RegionEntry -Segment at 61:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loop_break_value.txt deleted file mode 100644 index 17bd5c2ff318..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loop_break_value.txt +++ /dev/null @@ -1,6 +0,0 @@ -Counter in file 0 3:1 -> 13:2, #1 -Emitting segments for file: ../coverage/loop_break_value.rs -Combined regions: - 3:1 -> 13:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 13:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loops_branches.txt deleted file mode 100644 index d1da50b1529e..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loops_branches.txt +++ /dev/null @@ -1,33 +0,0 @@ -Counter in file 0 9:5 -> 10:16, #1 -Counter in file 0 11:16 -> 11:21, #2 -Counter in file 0 14:14 -> 14:15, (#2 - #5) -Counter in file 0 15:13 -> 15:31, ((0 - #6) + (#2 - #5)) -Counter in file 0 15:31 -> 15:32, #4 -Counter in file 0 18:9 -> 18:15, (#3 + 0) -Counter in file 0 19:5 -> 19:6, (#4 + (#3 + 0)) -Counter in file 0 22:1 -> 25:2, #1 -Emitting segments for file: ../coverage/loops_branches.rs -Combined regions: - 9:5 -> 10:16 (count=1) - 11:16 -> 11:21 (count=1) - 14:14 -> 14:15 (count=1) - 15:13 -> 15:31 (count=1) - 15:31 -> 15:32 (count=0) - 18:9 -> 18:15 (count=1) - 19:5 -> 19:6 (count=1) - 22:1 -> 25:2 (count=1) -Segment at 9:5 (count = 1), RegionEntry -Segment at 10:16 (count = 0), Skipped -Segment at 11:16 (count = 1), RegionEntry -Segment at 11:21 (count = 0), Skipped -Segment at 14:14 (count = 1), RegionEntry -Segment at 14:15 (count = 0), Skipped -Segment at 15:13 (count = 1), RegionEntry -Segment at 15:31 (count = 0), RegionEntry -Segment at 15:32 (count = 0), Skipped -Segment at 18:9 (count = 1), RegionEntry -Segment at 18:15 (count = 0), Skipped -Segment at 19:5 (count = 1), RegionEntry -Segment at 19:6 (count = 0), Skipped -Segment at 22:1 (count = 1), RegionEntry -Segment at 25:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt deleted file mode 100644 index fc12612ce7d7..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt +++ /dev/null @@ -1,98 +0,0 @@ -Counter in file 0 3:1 -> 11:15, #1 -Counter in file 0 11:16 -> 14:6, #2 -Counter in file 0 14:6 -> 14:7, (#1 - #2) -Counter in file 0 15:11 -> 15:17, (#2 + (#1 - #2)) -Counter in file 0 18:27 -> 18:29, #5 -Counter in file 0 19:14 -> 19:16, (#3 + #4) -Counter in file 0 21:8 -> 21:15, ((#3 + #4) + #5) -Counter in file 0 21:16 -> 24:6, #6 -Counter in file 0 24:6 -> 24:7, (((#3 + #4) + #5) - #6) -Counter in file 0 25:11 -> 25:17, (#6 + (((#3 + #4) + #5) - #6)) -Counter in file 0 26:27 -> 26:29, #9 -Counter in file 0 27:14 -> 27:16, (#7 + #8) -Counter in file 0 29:8 -> 29:15, ((#7 + #8) + #9) -Counter in file 0 29:16 -> 32:6, #10 -Counter in file 0 32:6 -> 32:7, (((#7 + #8) + #9) - #10) -Counter in file 0 33:11 -> 33:17, (#10 + (((#7 + #8) + #9) - #10)) -Counter in file 0 34:27 -> 34:29, #13 -Counter in file 0 35:14 -> 35:16, (#11 + #12) -Counter in file 0 37:8 -> 37:15, ((#11 + #12) + #13) -Counter in file 0 37:16 -> 40:6, #14 -Counter in file 0 40:6 -> 40:7, (((#11 + #12) + #13) - #14) -Counter in file 0 41:11 -> 41:17, (#14 + (((#11 + #12) + #13) - #14)) -Counter in file 0 42:27 -> 42:29, #17 -Counter in file 0 43:14 -> 43:16, (#15 + #16) -Counter in file 0 45:1 -> 45:2, ((#15 + #16) + #17) -Emitting segments for file: ../coverage/match_or_pattern.rs -Combined regions: - 3:1 -> 11:15 (count=1) - 11:16 -> 14:6 (count=1) - 14:6 -> 14:7 (count=0) - 15:11 -> 15:17 (count=1) - 18:27 -> 18:29 (count=0) - 19:14 -> 19:16 (count=1) - 21:8 -> 21:15 (count=1) - 21:16 -> 24:6 (count=1) - 24:6 -> 24:7 (count=0) - 25:11 -> 25:17 (count=1) - 26:27 -> 26:29 (count=0) - 27:14 -> 27:16 (count=1) - 29:8 -> 29:15 (count=1) - 29:16 -> 32:6 (count=1) - 32:6 -> 32:7 (count=0) - 33:11 -> 33:17 (count=1) - 34:27 -> 34:29 (count=0) - 35:14 -> 35:16 (count=1) - 37:8 -> 37:15 (count=1) - 37:16 -> 40:6 (count=1) - 40:6 -> 40:7 (count=0) - 41:11 -> 41:17 (count=1) - 42:27 -> 42:29 (count=1) - 43:14 -> 43:16 (count=0) - 45:1 -> 45:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 11:15 (count = 0), Skipped -Segment at 11:16 (count = 1), RegionEntry -Segment at 14:6 (count = 0), RegionEntry -Segment at 14:7 (count = 0), Skipped -Segment at 15:11 (count = 1), RegionEntry -Segment at 15:17 (count = 0), Skipped -Segment at 18:27 (count = 0), RegionEntry -Segment at 18:29 (count = 0), Skipped -Segment at 19:14 (count = 1), RegionEntry -Segment at 19:16 (count = 0), Skipped -Segment at 21:8 (count = 1), RegionEntry -Segment at 21:15 (count = 0), Skipped -Segment at 21:16 (count = 1), RegionEntry -Segment at 24:6 (count = 0), RegionEntry -Segment at 24:7 (count = 0), Skipped -Segment at 25:11 (count = 1), RegionEntry -Segment at 25:17 (count = 0), Skipped -Segment at 26:27 (count = 0), RegionEntry -Segment at 26:29 (count = 0), Skipped -Segment at 27:14 (count = 1), RegionEntry -Segment at 27:16 (count = 0), Skipped -Segment at 29:8 (count = 1), RegionEntry -Segment at 29:15 (count = 0), Skipped -Segment at 29:16 (count = 1), RegionEntry -Segment at 32:6 (count = 0), RegionEntry -Segment at 32:7 (count = 0), Skipped -Segment at 33:11 (count = 1), RegionEntry -Segment at 33:17 (count = 0), Skipped -Segment at 34:27 (count = 0), RegionEntry -Segment at 34:29 (count = 0), Skipped -Segment at 35:14 (count = 1), RegionEntry -Segment at 35:16 (count = 0), Skipped -Segment at 37:8 (count = 1), RegionEntry -Segment at 37:15 (count = 0), Skipped -Segment at 37:16 (count = 1), RegionEntry -Segment at 40:6 (count = 0), RegionEntry -Segment at 40:7 (count = 0), Skipped -Segment at 41:11 (count = 1), RegionEntry -Segment at 41:17 (count = 0), Skipped -Segment at 42:27 (count = 1), RegionEntry -Segment at 42:29 (count = 0), Skipped -Segment at 43:14 (count = 0), RegionEntry -Segment at 43:16 (count = 0), Skipped -Segment at 45:1 (count = 1), RegionEntry -Segment at 45:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.nested_loops.txt deleted file mode 100644 index f30dd9e37164..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.nested_loops.txt +++ /dev/null @@ -1,58 +0,0 @@ -Counter in file 0 1:1 -> 3:27, #1 -Counter in file 0 5:19 -> 5:32, (#1 + (#2 + #3)) -Counter in file 0 6:13 -> 7:24, ((#1 + (#2 + #3)) - #4) -Counter in file 0 8:13 -> 8:14, ((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) -Counter in file 0 8:18 -> 8:23, (((#1 + (#2 + #3)) - #4) + (#6 + #7)) -Counter in file 0 9:16 -> 9:22, (((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) + 0) -Counter in file 0 10:17 -> 10:22, #2 -Counter in file 0 11:14 -> 14:22, (((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) -Counter in file 0 15:17 -> 16:27, ((((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) - #7) -Counter in file 0 17:21 -> 17:33, #5 -Counter in file 0 18:24 -> 20:18, #6 -Counter in file 0 21:14 -> 21:15, #7 -Counter in file 0 23:9 -> 23:23, (#2 + #3) -Counter in file 0 25:1 -> 25:2, (#5 + #4) -Emitting segments for file: ../coverage/nested_loops.rs -Combined regions: - 1:1 -> 3:27 (count=1) - 5:19 -> 5:32 (count=1) - 6:13 -> 7:24 (count=1) - 8:13 -> 8:14 (count=3) - 8:18 -> 8:23 (count=3) - 9:16 -> 9:22 (count=3) - 10:17 -> 10:22 (count=0) - 11:14 -> 14:22 (count=3) - 15:17 -> 16:27 (count=1) - 17:21 -> 17:33 (count=1) - 18:24 -> 20:18 (count=0) - 21:14 -> 21:15 (count=2) - 23:9 -> 23:23 (count=0) - 25:1 -> 25:2 (count=1) -Segment at 1:1 (count = 1), RegionEntry -Segment at 3:27 (count = 0), Skipped -Segment at 5:19 (count = 1), RegionEntry -Segment at 5:32 (count = 0), Skipped -Segment at 6:13 (count = 1), RegionEntry -Segment at 7:24 (count = 0), Skipped -Segment at 8:13 (count = 3), RegionEntry -Segment at 8:14 (count = 0), Skipped -Segment at 8:18 (count = 3), RegionEntry -Segment at 8:23 (count = 0), Skipped -Segment at 9:16 (count = 3), RegionEntry -Segment at 9:22 (count = 0), Skipped -Segment at 10:17 (count = 0), RegionEntry -Segment at 10:22 (count = 0), Skipped -Segment at 11:14 (count = 3), RegionEntry -Segment at 14:22 (count = 0), Skipped -Segment at 15:17 (count = 1), RegionEntry -Segment at 16:27 (count = 0), Skipped -Segment at 17:21 (count = 1), RegionEntry -Segment at 17:33 (count = 0), Skipped -Segment at 18:24 (count = 0), RegionEntry -Segment at 20:18 (count = 0), Skipped -Segment at 21:14 (count = 2), RegionEntry -Segment at 21:15 (count = 0), Skipped -Segment at 23:9 (count = 0), RegionEntry -Segment at 23:23 (count = 0), Skipped -Segment at 25:1 (count = 1), RegionEntry -Segment at 25:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt deleted file mode 100644 index 380bb7cf1701..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt +++ /dev/null @@ -1,52 +0,0 @@ -Counter in file 0 15:1 -> 16:27, #1 -Counter in file 0 17:11 -> 17:24, (#1 + (#2 + (#3 + #4))) -Counter in file 0 18:12 -> 18:26, ((#1 + (#2 + (#3 + #4))) - #5) -Counter in file 0 18:27 -> 21:10, #2 -Counter in file 0 21:19 -> 21:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) -Counter in file 0 21:33 -> 24:10, #3 -Counter in file 0 24:10 -> 24:11, #4 -Counter in file 0 25:9 -> 25:23, (#2 + (#3 + #4)) -Counter in file 0 27:5 -> 28:2, #5 -Counter in file 0 4:1 -> 5:18, #1 -Counter in file 0 5:19 -> 7:6, #2 -Counter in file 0 7:6 -> 7:7, (#1 - #2) -Counter in file 0 8:9 -> 13:2, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/overflow.rs -Combined regions: - 4:1 -> 5:18 (count=4) - 5:19 -> 7:6 (count=1) - 7:6 -> 7:7 (count=3) - 8:9 -> 13:2 (count=4) - 15:1 -> 16:27 (count=1) - 17:11 -> 17:24 (count=11) - 18:12 -> 18:26 (count=11) - 18:27 -> 21:10 (count=1) - 21:19 -> 21:32 (count=10) - 21:33 -> 24:10 (count=3) - 24:10 -> 24:11 (count=6) - 25:9 -> 25:23 (count=10) - 27:5 -> 28:2 (count=0) -Segment at 4:1 (count = 4), RegionEntry -Segment at 5:18 (count = 0), Skipped -Segment at 5:19 (count = 1), RegionEntry -Segment at 7:6 (count = 3), RegionEntry -Segment at 7:7 (count = 0), Skipped -Segment at 8:9 (count = 4), RegionEntry -Segment at 13:2 (count = 0), Skipped -Segment at 15:1 (count = 1), RegionEntry -Segment at 16:27 (count = 0), Skipped -Segment at 17:11 (count = 11), RegionEntry -Segment at 17:24 (count = 0), Skipped -Segment at 18:12 (count = 11), RegionEntry -Segment at 18:26 (count = 0), Skipped -Segment at 18:27 (count = 1), RegionEntry -Segment at 21:10 (count = 0), Skipped -Segment at 21:19 (count = 10), RegionEntry -Segment at 21:32 (count = 0), Skipped -Segment at 21:33 (count = 3), RegionEntry -Segment at 24:10 (count = 6), RegionEntry -Segment at 24:11 (count = 0), Skipped -Segment at 25:9 (count = 10), RegionEntry -Segment at 25:23 (count = 0), Skipped -Segment at 27:5 (count = 0), RegionEntry -Segment at 28:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt deleted file mode 100644 index b3f61ad325d1..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt +++ /dev/null @@ -1,53 +0,0 @@ -Counter in file 0 13:1 -> 14:27, #1 -Counter in file 0 15:11 -> 15:24, (#1 + (#2 + (#3 + #4))) -Counter in file 0 16:12 -> 16:26, ((#1 + (#2 + (#3 + #4))) - #5) -Counter in file 0 16:27 -> 18:10, #2 -Counter in file 0 18:19 -> 18:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) -Counter in file 0 18:33 -> 20:10, #3 -Counter in file 0 20:10 -> 20:11, #4 -Counter in file 0 21:9 -> 21:23, (#2 + (#3 + #4)) -Counter in file 0 23:5 -> 24:2, #5 -Counter in file 0 4:1 -> 4:36, #1 -Counter in file 0 5:8 -> 5:20, (#1 + 0) -Counter in file 0 6:9 -> 7:26, #2 -Counter in file 0 8:12 -> 11:2, (#1 - #2) -Emitting segments for file: ../coverage/panic_unwind.rs -Combined regions: - 4:1 -> 4:36 (count=4) - 5:8 -> 5:20 (count=4) - 6:9 -> 7:26 (count=1) - 8:12 -> 11:2 (count=3) - 13:1 -> 14:27 (count=1) - 15:11 -> 15:24 (count=11) - 16:12 -> 16:26 (count=11) - 16:27 -> 18:10 (count=1) - 18:19 -> 18:32 (count=10) - 18:33 -> 20:10 (count=3) - 20:10 -> 20:11 (count=6) - 21:9 -> 21:23 (count=10) - 23:5 -> 24:2 (count=0) -Segment at 4:1 (count = 4), RegionEntry -Segment at 4:36 (count = 0), Skipped -Segment at 5:8 (count = 4), RegionEntry -Segment at 5:20 (count = 0), Skipped -Segment at 6:9 (count = 1), RegionEntry -Segment at 7:26 (count = 0), Skipped -Segment at 8:12 (count = 3), RegionEntry -Segment at 11:2 (count = 0), Skipped -Segment at 13:1 (count = 1), RegionEntry -Segment at 14:27 (count = 0), Skipped -Segment at 15:11 (count = 11), RegionEntry -Segment at 15:24 (count = 0), Skipped -Segment at 16:12 (count = 11), RegionEntry -Segment at 16:26 (count = 0), Skipped -Segment at 16:27 (count = 1), RegionEntry -Segment at 18:10 (count = 0), Skipped -Segment at 18:19 (count = 10), RegionEntry -Segment at 18:32 (count = 0), Skipped -Segment at 18:33 (count = 3), RegionEntry -Segment at 20:10 (count = 6), RegionEntry -Segment at 20:11 (count = 0), Skipped -Segment at 21:9 (count = 10), RegionEntry -Segment at 21:23 (count = 0), Skipped -Segment at 23:5 (count = 0), RegionEntry -Segment at 24:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.partial_eq.txt deleted file mode 100644 index fa5c12bb6f8e..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.partial_eq.txt +++ /dev/null @@ -1,66 +0,0 @@ -Counter in file 0 4:10 -> 4:15, 0 -Counter in file 0 4:24 -> 4:25, 0 -Counter in file 0 4:24 -> 4:25, 0 -Counter in file 0 4:32 -> 4:33, 0 -Counter in file 0 4:32 -> 4:33, 0 -Counter in file 0 4:35 -> 4:36, 0 -Counter in file 0 4:39 -> 4:40, 0 -Counter in file 0 4:39 -> 4:40, 0 -Counter in file 0 4:39 -> 4:40, 0 -Counter in file 0 4:39 -> 4:40, 0 -Counter in file 0 4:48 -> 4:49, 0 -Counter in file 0 4:51 -> 4:52, 0 -Counter in file 0 4:53 -> 4:54, 0 -Counter in file 0 7:5 -> 7:6, #1 -Counter in file 0 7:5 -> 7:6, 0 -Counter in file 0 7:5 -> 7:6, 0 -Counter in file 0 7:5 -> 7:6, 0 -Counter in file 0 8:5 -> 8:17, 0 -Counter in file 0 8:5 -> 8:17, 0 -Counter in file 0 8:5 -> 8:17, 0 -Counter in file 0 21:1 -> 26:2, #1 -Counter in file 0 4:17 -> 4:22, #1 -Counter in file 0 12:5 -> 18:6, #1 -Counter in file 0 4:39 -> 4:40, #1 -Counter in file 0 8:5 -> 8:17, #1 -Emitting segments for file: ../coverage/partial_eq.rs -Combined regions: - 4:10 -> 4:15 (count=0) - 4:17 -> 4:22 (count=2) - 4:24 -> 4:25 (count=0) - 4:32 -> 4:33 (count=0) - 4:35 -> 4:36 (count=0) - 4:39 -> 4:40 (count=1) - 4:48 -> 4:49 (count=0) - 4:51 -> 4:52 (count=0) - 4:53 -> 4:54 (count=0) - 7:5 -> 7:6 (count=1) - 8:5 -> 8:17 (count=0) - 12:5 -> 18:6 (count=2) - 21:1 -> 26:2 (count=1) -Segment at 4:10 (count = 0), RegionEntry -Segment at 4:15 (count = 0), Skipped -Segment at 4:17 (count = 2), RegionEntry -Segment at 4:22 (count = 0), Skipped -Segment at 4:24 (count = 0), RegionEntry -Segment at 4:25 (count = 0), Skipped -Segment at 4:32 (count = 0), RegionEntry -Segment at 4:33 (count = 0), Skipped -Segment at 4:35 (count = 0), RegionEntry -Segment at 4:36 (count = 0), Skipped -Segment at 4:39 (count = 1), RegionEntry -Segment at 4:40 (count = 0), Skipped -Segment at 4:48 (count = 0), RegionEntry -Segment at 4:49 (count = 0), Skipped -Segment at 4:51 (count = 0), RegionEntry -Segment at 4:52 (count = 0), Skipped -Segment at 4:53 (count = 0), RegionEntry -Segment at 4:54 (count = 0), Skipped -Segment at 7:5 (count = 1), RegionEntry -Segment at 7:6 (count = 0), Skipped -Segment at 8:5 (count = 0), RegionEntry -Segment at 8:17 (count = 0), Skipped -Segment at 12:5 (count = 2), RegionEntry -Segment at 18:6 (count = 0), Skipped -Segment at 21:1 (count = 1), RegionEntry -Segment at 26:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_loop.txt deleted file mode 100644 index c0b09486dfba..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_loop.txt +++ /dev/null @@ -1,29 +0,0 @@ -Counter in file 0 3:1 -> 12:16, #1 -Counter in file 0 13:5 -> 18:6, #2 -Counter in file 0 18:6 -> 18:7, (#1 - #2) -Counter in file 0 23:13 -> 25:14, ((#2 + (#1 - #2)) + #3) -Counter in file 0 27:13 -> 27:18, (((#2 + (#1 - #2)) + #3) - #3) -Counter in file 0 29:10 -> 32:10, #3 -Counter in file 0 35:1 -> 35:2, ((((#2 + (#1 - #2)) + #3) - #3) + 0) -Emitting segments for file: ../coverage/simple_loop.rs -Combined regions: - 3:1 -> 12:16 (count=1) - 13:5 -> 18:6 (count=1) - 18:6 -> 18:7 (count=0) - 23:13 -> 25:14 (count=11) - 27:13 -> 27:18 (count=1) - 29:10 -> 32:10 (count=10) - 35:1 -> 35:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 12:16 (count = 0), Skipped -Segment at 13:5 (count = 1), RegionEntry -Segment at 18:6 (count = 0), RegionEntry -Segment at 18:7 (count = 0), Skipped -Segment at 23:13 (count = 11), RegionEntry -Segment at 25:14 (count = 0), Skipped -Segment at 27:13 (count = 1), RegionEntry -Segment at 27:18 (count = 0), Skipped -Segment at 29:10 (count = 10), RegionEntry -Segment at 32:10 (count = 0), Skipped -Segment at 35:1 (count = 1), RegionEntry -Segment at 35:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_match.txt deleted file mode 100644 index c01630bd87bc..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_match.txt +++ /dev/null @@ -1,45 +0,0 @@ -Counter in file 0 3:1 -> 10:15, #1 -Counter in file 0 10:16 -> 12:6, #2 -Counter in file 0 12:6 -> 12:7, (#1 - #2) -Counter in file 0 15:9 -> 15:10, (((#2 + (#1 - #2)) + (#3 + #4)) - #5) -Counter in file 0 17:9 -> 17:13, ((#2 + (#1 - #2)) + (#3 + #4)) -Counter in file 0 22:13 -> 22:22, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) + 0) -Counter in file 0 24:13 -> 24:14, #3 -Counter in file 0 26:17 -> 28:18, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) + 0) -Counter in file 0 30:13 -> 37:14, (#3 + 0) -Counter in file 0 40:13 -> 40:15, #4 -Counter in file 0 43:1 -> 43:2, #5 -Emitting segments for file: ../coverage/simple_match.rs -Combined regions: - 3:1 -> 10:15 (count=1) - 10:16 -> 12:6 (count=1) - 12:6 -> 12:7 (count=0) - 15:9 -> 15:10 (count=2) - 17:9 -> 17:13 (count=3) - 22:13 -> 22:22 (count=2) - 24:13 -> 24:14 (count=1) - 26:17 -> 28:18 (count=2) - 30:13 -> 37:14 (count=1) - 40:13 -> 40:15 (count=1) - 43:1 -> 43:2 (count=1) -Segment at 3:1 (count = 1), RegionEntry -Segment at 10:15 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 12:6 (count = 0), RegionEntry -Segment at 12:7 (count = 0), Skipped -Segment at 15:9 (count = 2), RegionEntry -Segment at 15:10 (count = 0), Skipped -Segment at 17:9 (count = 3), RegionEntry -Segment at 17:13 (count = 0), Skipped -Segment at 22:13 (count = 2), RegionEntry -Segment at 22:22 (count = 0), Skipped -Segment at 24:13 (count = 1), RegionEntry -Segment at 24:14 (count = 0), Skipped -Segment at 26:17 (count = 2), RegionEntry -Segment at 28:18 (count = 0), Skipped -Segment at 30:13 (count = 1), RegionEntry -Segment at 37:14 (count = 0), Skipped -Segment at 40:13 (count = 1), RegionEntry -Segment at 40:15 (count = 0), Skipped -Segment at 43:1 (count = 1), RegionEntry -Segment at 43:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.tight_inf_loop.txt deleted file mode 100644 index a6cd42988085..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.tight_inf_loop.txt +++ /dev/null @@ -1,10 +0,0 @@ -Counter in file 0 1:1 -> 2:13, #1 -Counter in file 0 4:6 -> 5:2, (#1 - #2) -Emitting segments for file: ../coverage/tight_inf_loop.rs -Combined regions: - 1:1 -> 2:13 (count=1) - 4:6 -> 5:2 (count=1) -Segment at 1:1 (count = 1), RegionEntry -Segment at 2:13 (count = 0), Skipped -Segment at 4:6 (count = 1), RegionEntry -Segment at 5:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.try_error_result.txt deleted file mode 100644 index 2b7962df2f9f..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.try_error_result.txt +++ /dev/null @@ -1,63 +0,0 @@ -Counter in file 0 12:1 -> 14:23, #1 -Counter in file 0 17:9 -> 17:10, ((#1 + (#2 + #3)) - #4) -Counter in file 0 19:9 -> 19:14, (#1 + (#2 + #3)) -Counter in file 0 21:9 -> 25:26, (((#1 + (#2 + #3)) - #4) + 0) -Counter in file 0 27:13 -> 27:41, #8 -Counter in file 0 27:41 -> 27:42, #5 -Counter in file 0 28:13 -> 28:42, (#8 - #5) -Counter in file 0 28:42 -> 28:43, #6 -Counter in file 0 32:13 -> 32:42, (((#1 + (#2 + #3)) - #4) - #8) -Counter in file 0 32:42 -> 32:43, #7 -Counter in file 0 35:5 -> 35:11, #4 -Counter in file 0 36:1 -> 36:2, ((#5 + (#6 + #7)) + #4) -Counter in file 0 4:1 -> 5:20, #1 -Counter in file 0 6:9 -> 6:16, #2 -Counter in file 0 8:9 -> 8:15, (#1 - #2) -Counter in file 0 10:1 -> 10:2, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/try_error_result.rs -Combined regions: - 4:1 -> 5:20 (count=6) - 6:9 -> 6:16 (count=1) - 8:9 -> 8:15 (count=5) - 10:1 -> 10:2 (count=6) - 12:1 -> 14:23 (count=1) - 17:9 -> 17:10 (count=6) - 19:9 -> 19:14 (count=6) - 21:9 -> 25:26 (count=6) - 27:13 -> 27:41 (count=1) - 27:41 -> 27:42 (count=1) - 28:13 -> 28:42 (count=0) - 28:42 -> 28:43 (count=0) - 32:13 -> 32:42 (count=5) - 32:42 -> 32:43 (count=0) - 35:5 -> 35:11 (count=0) - 36:1 -> 36:2 (count=1) -Segment at 4:1 (count = 6), RegionEntry -Segment at 5:20 (count = 0), Skipped -Segment at 6:9 (count = 1), RegionEntry -Segment at 6:16 (count = 0), Skipped -Segment at 8:9 (count = 5), RegionEntry -Segment at 8:15 (count = 0), Skipped -Segment at 10:1 (count = 6), RegionEntry -Segment at 10:2 (count = 0), Skipped -Segment at 12:1 (count = 1), RegionEntry -Segment at 14:23 (count = 0), Skipped -Segment at 17:9 (count = 6), RegionEntry -Segment at 17:10 (count = 0), Skipped -Segment at 19:9 (count = 6), RegionEntry -Segment at 19:14 (count = 0), Skipped -Segment at 21:9 (count = 6), RegionEntry -Segment at 25:26 (count = 0), Skipped -Segment at 27:13 (count = 1), RegionEntry -Segment at 27:41 (count = 1), RegionEntry -Segment at 27:42 (count = 0), Skipped -Segment at 28:13 (count = 0), RegionEntry -Segment at 28:42 (count = 0), RegionEntry -Segment at 28:43 (count = 0), Skipped -Segment at 32:13 (count = 5), RegionEntry -Segment at 32:42 (count = 0), RegionEntry -Segment at 32:43 (count = 0), Skipped -Segment at 35:5 (count = 0), RegionEntry -Segment at 35:11 (count = 0), Skipped -Segment at 36:1 (count = 1), RegionEntry -Segment at 36:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt deleted file mode 100644 index b0319cd9e189..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt +++ /dev/null @@ -1,110 +0,0 @@ -Counter in file 0 17:1 -> 19:2, #1 -Counter in file 0 25:1 -> 27:2, #1 -Counter in file 0 17:1 -> 19:2, #1 -Counter in file 0 5:1 -> 12:2, #1 -Counter in file 0 17:1 -> 19:2, 0 -Counter in file 0 33:1 -> 35:2, 0 -Counter in file 0 45:1 -> 48:16, 0 -Counter in file 0 48:17 -> 50:6, 0 -Counter in file 0 50:6 -> 50:7, 0 -Counter in file 0 51:1 -> 51:2, 0 -Counter in file 0 53:1 -> 61:2, #1 -Counter in file 0 25:1 -> 27:2, #1 -Counter in file 0 29:1 -> 31:2, #1 -Counter in file 0 21:1 -> 23:2, #1 -Counter in file 0 5:1 -> 5:24, #1 -Counter in file 0 9:9 -> 11:15, (#1 + 0) -Counter in file 0 11:16 -> 13:6, #2 -Counter in file 0 13:6 -> 13:7, (#1 - #2) -Counter in file 0 14:5 -> 15:2, (#2 + (#1 - #2)) -Counter in file 0 21:1 -> 23:2, #1 -Counter in file 0 37:1 -> 40:16, #1 -Counter in file 0 40:17 -> 42:6, #2 -Counter in file 0 42:6 -> 42:7, (#1 - #2) -Counter in file 0 43:1 -> 43:2, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/lib/used_crate.rs -Combined regions: - 5:1 -> 5:24 (count=1) - 9:9 -> 11:15 (count=1) - 11:16 -> 13:6 (count=1) - 13:6 -> 13:7 (count=0) - 14:5 -> 15:2 (count=1) - 17:1 -> 19:2 (count=2) - 21:1 -> 23:2 (count=2) - 25:1 -> 27:2 (count=2) - 29:1 -> 31:2 (count=2) - 33:1 -> 35:2 (count=0) - 37:1 -> 40:16 (count=0) - 40:17 -> 42:6 (count=0) - 42:6 -> 42:7 (count=0) - 43:1 -> 43:2 (count=0) - 45:1 -> 48:16 (count=0) - 48:17 -> 50:6 (count=0) - 50:6 -> 50:7 (count=0) - 51:1 -> 51:2 (count=0) - 53:1 -> 61:2 (count=1) -Segment at 5:1 (count = 1), RegionEntry -Segment at 5:24 (count = 0), Skipped -Segment at 9:9 (count = 1), RegionEntry -Segment at 11:15 (count = 0), Skipped -Segment at 11:16 (count = 1), RegionEntry -Segment at 13:6 (count = 0), RegionEntry -Segment at 13:7 (count = 0), Skipped -Segment at 14:5 (count = 1), RegionEntry -Segment at 15:2 (count = 0), Skipped -Segment at 17:1 (count = 2), RegionEntry -Segment at 19:2 (count = 0), Skipped -Segment at 21:1 (count = 2), RegionEntry -Segment at 23:2 (count = 0), Skipped -Segment at 25:1 (count = 2), RegionEntry -Segment at 27:2 (count = 0), Skipped -Segment at 29:1 (count = 2), RegionEntry -Segment at 31:2 (count = 0), Skipped -Segment at 33:1 (count = 0), RegionEntry -Segment at 35:2 (count = 0), Skipped -Segment at 37:1 (count = 0), RegionEntry -Segment at 40:16 (count = 0), Skipped -Segment at 40:17 (count = 0), RegionEntry -Segment at 42:6 (count = 0), RegionEntry -Segment at 42:7 (count = 0), Skipped -Segment at 43:1 (count = 0), RegionEntry -Segment at 43:2 (count = 0), Skipped -Segment at 45:1 (count = 0), RegionEntry -Segment at 48:16 (count = 0), Skipped -Segment at 48:17 (count = 0), RegionEntry -Segment at 50:6 (count = 0), RegionEntry -Segment at 50:7 (count = 0), Skipped -Segment at 51:1 (count = 0), RegionEntry -Segment at 51:2 (count = 0), Skipped -Segment at 53:1 (count = 1), RegionEntry -Segment at 61:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionReECs4fqI2P2rA04_10uses_crate -Combined regions: - 17:1 -> 19:2 (count=1) -Segment at 17:1 (count = 1), RegionEntry -Segment at 19:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionRINtNtCs3QflaznQylx_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate -Combined regions: - 17:1 -> 19:2 (count=1) -Segment at 17:1 (count = 1), RegionEntry -Segment at 19:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEEB2_ -Combined regions: - 21:1 -> 23:2 (count=1) -Segment at 21:1 (count = 1), RegionEntry -Segment at 23:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionReEB2_ -Combined regions: - 21:1 -> 23:2 (count=1) -Segment at 21:1 (count = 1), RegionEntry -Segment at 23:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate -Combined regions: - 25:1 -> 27:2 (count=1) -Segment at 25:1 (count = 1), RegionEntry -Segment at 27:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionReEB2_ -Combined regions: - 25:1 -> 27:2 (count=1) -Segment at 25:1 (count = 1), RegionEntry -Segment at 27:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while.txt deleted file mode 100644 index 90629ac84cdf..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while.txt +++ /dev/null @@ -1,18 +0,0 @@ -Counter in file 0 1:1 -> 2:16, #1 -Counter in file 0 3:11 -> 3:20, (#1 + #2) -Counter in file 0 3:21 -> 4:6, #2 -Counter in file 0 5:1 -> 5:2, ((#1 + #2) - #2) -Emitting segments for file: ../coverage/while.rs -Combined regions: - 1:1 -> 2:16 (count=1) - 3:11 -> 3:20 (count=1) - 3:21 -> 4:6 (count=0) - 5:1 -> 5:2 (count=1) -Segment at 1:1 (count = 1), RegionEntry -Segment at 2:16 (count = 0), Skipped -Segment at 3:11 (count = 1), RegionEntry -Segment at 3:20 (count = 0), Skipped -Segment at 3:21 (count = 0), RegionEntry -Segment at 4:6 (count = 0), Skipped -Segment at 5:1 (count = 1), RegionEntry -Segment at 5:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while_early_ret.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while_early_ret.txt deleted file mode 100644 index 12f444945a18..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while_early_ret.txt +++ /dev/null @@ -1,38 +0,0 @@ -Counter in file 0 4:1 -> 5:27, #1 -Counter in file 0 7:9 -> 9:10, (#1 + #2) -Counter in file 0 12:13 -> 14:14, ((#1 + #2) - #3) -Counter in file 0 18:21 -> 20:22, (((#1 + #2) - #3) - #2) -Counter in file 0 22:21 -> 22:27, #4 -Counter in file 0 26:21 -> 26:27, #5 -Counter in file 0 29:10 -> 32:10, #2 -Counter in file 0 35:5 -> 35:11, #3 -Counter in file 0 36:1 -> 36:2, ((#4 + #5) + #3) -Emitting segments for file: ../coverage/while_early_ret.rs -Combined regions: - 4:1 -> 5:27 (count=1) - 7:9 -> 9:10 (count=7) - 12:13 -> 14:14 (count=7) - 18:21 -> 20:22 (count=1) - 22:21 -> 22:27 (count=0) - 26:21 -> 26:27 (count=1) - 29:10 -> 32:10 (count=6) - 35:5 -> 35:11 (count=0) - 36:1 -> 36:2 (count=1) -Segment at 4:1 (count = 1), RegionEntry -Segment at 5:27 (count = 0), Skipped -Segment at 7:9 (count = 7), RegionEntry -Segment at 9:10 (count = 0), Skipped -Segment at 12:13 (count = 7), RegionEntry -Segment at 14:14 (count = 0), Skipped -Segment at 18:21 (count = 1), RegionEntry -Segment at 20:22 (count = 0), Skipped -Segment at 22:21 (count = 0), RegionEntry -Segment at 22:27 (count = 0), Skipped -Segment at 26:21 (count = 1), RegionEntry -Segment at 26:27 (count = 0), Skipped -Segment at 29:10 (count = 6), RegionEntry -Segment at 32:10 (count = 0), Skipped -Segment at 35:5 (count = 0), RegionEntry -Segment at 35:11 (count = 0), Skipped -Segment at 36:1 (count = 1), RegionEntry -Segment at 36:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.yield.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.yield.txt deleted file mode 100644 index 6ed3e465611e..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.yield.txt +++ /dev/null @@ -1,94 +0,0 @@ -Counter in file 0 7:1 -> 7:11, #1 -Counter in file 0 8:9 -> 8:22, (#1 + 0) -Counter in file 0 13:11 -> 14:35, (#1 + 0) -Counter in file 0 14:39 -> 14:41, #4 -Counter in file 0 15:14 -> 15:52, (#2 + #3) -Counter in file 0 17:11 -> 17:46, (#4 + 0) -Counter in file 0 18:34 -> 18:39, (#4 - #5) -Counter in file 0 18:44 -> 18:46, ((#4 - #5) - #6) -Counter in file 0 19:14 -> 19:52, (#5 + #6) -Counter in file 0 22:9 -> 22:22, (((#4 - #5) - #6) + 0) -Counter in file 0 29:11 -> 30:35, (((#4 - #5) - #6) + 0) -Counter in file 0 30:39 -> 30:41, #9 -Counter in file 0 31:14 -> 31:52, (#7 + #8) -Counter in file 0 33:11 -> 34:35, (#9 + 0) -Counter in file 0 34:39 -> 34:41, #12 -Counter in file 0 35:14 -> 35:52, (#10 + #11) -Counter in file 0 37:1 -> 37:2, (#12 + 0) -Counter in file 0 8:28 -> 9:16, #1 -Counter in file 0 10:16 -> 11:6, #2 -Counter in file 0 22:28 -> 23:16, #1 -Counter in file 0 24:9 -> 24:16, #2 -Counter in file 0 25:9 -> 25:16, #3 -Counter in file 0 26:16 -> 27:6, #4 -Emitting segments for file: ../coverage/yield.rs -Combined regions: - 7:1 -> 7:11 (count=1) - 8:9 -> 8:22 (count=1) - 8:28 -> 9:16 (count=1) - 10:16 -> 11:6 (count=1) - 13:11 -> 14:35 (count=1) - 14:39 -> 14:41 (count=1) - 15:14 -> 15:52 (count=0) - 17:11 -> 17:46 (count=1) - 18:34 -> 18:39 (count=1) - 18:44 -> 18:46 (count=1) - 19:14 -> 19:52 (count=0) - 22:9 -> 22:22 (count=1) - 22:28 -> 23:16 (count=1) - 24:9 -> 24:16 (count=1) - 25:9 -> 25:16 (count=0) - 26:16 -> 27:6 (count=0) - 29:11 -> 30:35 (count=1) - 30:39 -> 30:41 (count=1) - 31:14 -> 31:52 (count=0) - 33:11 -> 34:35 (count=1) - 34:39 -> 34:41 (count=1) - 35:14 -> 35:52 (count=0) - 37:1 -> 37:2 (count=1) -Segment at 7:1 (count = 1), RegionEntry -Segment at 7:11 (count = 0), Skipped -Segment at 8:9 (count = 1), RegionEntry -Segment at 8:22 (count = 0), Skipped -Segment at 8:28 (count = 1), RegionEntry -Segment at 9:16 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 11:6 (count = 0), Skipped -Segment at 13:11 (count = 1), RegionEntry -Segment at 14:35 (count = 0), Skipped -Segment at 14:39 (count = 1), RegionEntry -Segment at 14:41 (count = 0), Skipped -Segment at 15:14 (count = 0), RegionEntry -Segment at 15:52 (count = 0), Skipped -Segment at 17:11 (count = 1), RegionEntry -Segment at 17:46 (count = 0), Skipped -Segment at 18:34 (count = 1), RegionEntry -Segment at 18:39 (count = 0), Skipped -Segment at 18:44 (count = 1), RegionEntry -Segment at 18:46 (count = 0), Skipped -Segment at 19:14 (count = 0), RegionEntry -Segment at 19:52 (count = 0), Skipped -Segment at 22:9 (count = 1), RegionEntry -Segment at 22:22 (count = 0), Skipped -Segment at 22:28 (count = 1), RegionEntry -Segment at 23:16 (count = 0), Skipped -Segment at 24:9 (count = 1), RegionEntry -Segment at 24:16 (count = 0), Skipped -Segment at 25:9 (count = 0), RegionEntry -Segment at 25:16 (count = 0), Skipped -Segment at 26:16 (count = 0), RegionEntry -Segment at 27:6 (count = 0), Skipped -Segment at 29:11 (count = 1), RegionEntry -Segment at 30:35 (count = 0), Skipped -Segment at 30:39 (count = 1), RegionEntry -Segment at 30:41 (count = 0), Skipped -Segment at 31:14 (count = 0), RegionEntry -Segment at 31:52 (count = 0), Skipped -Segment at 33:11 (count = 1), RegionEntry -Segment at 34:35 (count = 0), Skipped -Segment at 34:39 (count = 1), RegionEntry -Segment at 34:41 (count = 0), Skipped -Segment at 35:14 (count = 0), RegionEntry -Segment at 35:52 (count = 0), Skipped -Segment at 37:1 (count = 1), RegionEntry -Segment at 37:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/prettify_json.py b/src/test/run-make-fulldeps/coverage-reports/prettify_json.py deleted file mode 100644 index ed9279841f70..000000000000 --- a/src/test/run-make-fulldeps/coverage-reports/prettify_json.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python - -import sys -import json - -# Try to decode line in order to ensure it is a valid JSON document -for line in sys.stdin: - parsed = json.loads(line) - print (json.dumps(parsed, indent=2, separators=(',', ': '), sort_keys=True)) From 2c0dccb7f2affb0013b00ebeb35ad12fcffa99a6 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 3 Dec 2020 14:11:35 +0100 Subject: [PATCH 355/719] Move some code out of CodegenBackend::{codegen_crate,link} --- compiler/rustc_codegen_llvm/src/lib.rs | 24 +++++++++++------------- compiler/rustc_codegen_ssa/src/base.rs | 21 --------------------- compiler/rustc_interface/src/passes.rs | 14 ++++++++++++++ compiler/rustc_interface/src/queries.rs | 1 + 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index a58c2fbd8ab2..f33464f83dad 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -298,21 +298,19 @@ impl CodegenBackend for LlvmCodegenBackend { codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorReported> { + use crate::back::archive::LlvmArchiveBuilder; + use rustc_codegen_ssa::back::link::link_binary; + // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - sess.time("link_crate", || { - use crate::back::archive::LlvmArchiveBuilder; - use rustc_codegen_ssa::back::link::link_binary; - - let target_cpu = crate::llvm_util::target_cpu(sess); - link_binary::>( - sess, - &codegen_results, - outputs, - &codegen_results.crate_name.as_str(), - target_cpu, - ); - }); + let target_cpu = crate::llvm_util::target_cpu(sess); + link_binary::>( + sess, + &codegen_results, + outputs, + &codegen_results.crate_name.as_str(), + target_cpu, + ); Ok(()) } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 21138f967a27..048a353e5fcb 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -46,7 +46,6 @@ use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, EntryFnType}; use rustc_session::utils::NativeLibKind; use rustc_session::Session; -use rustc_symbol_mangling::test as symbol_names_test; use rustc_target::abi::{Align, LayoutOf, VariantIdx}; use std::cmp; @@ -486,8 +485,6 @@ pub fn codegen_crate( ongoing_codegen.codegen_finished(tcx); - finalize_tcx(tcx); - ongoing_codegen.check_for_errors(tcx.sess); return ongoing_codegen; @@ -688,14 +685,8 @@ pub fn codegen_crate( total_codegen_time.into_inner(), ); - rustc_incremental::assert_module_sources::assert_module_sources(tcx); - - symbol_names_test::report_symbol_names(tcx); - ongoing_codegen.check_for_errors(tcx.sess); - finalize_tcx(tcx); - ongoing_codegen.into_inner() } @@ -746,18 +737,6 @@ impl Drop for AbortCodegenOnDrop { } } -fn finalize_tcx(tcx: TyCtxt<'_>) { - tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx)); - tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx)); - - // We assume that no queries are run past here. If there are new queries - // after this point, they'll show up as "" in self-profiling data. - { - let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings"); - tcx.alloc_self_profile_query_strings(); - } -} - impl CrateInfo { pub fn new(tcx: TyCtxt<'_>) -> CrateInfo { let mut info = CrateInfo { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c13d26c79d73..3f30b7e69e4f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -996,6 +996,20 @@ pub fn start_codegen<'tcx>( codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) }); + rustc_incremental::assert_module_sources::assert_module_sources(tcx); + + rustc_symbol_mangling::test::report_symbol_names(tcx); + + tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx)); + tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx)); + + // We assume that no queries are run past here. If there are new queries + // after this point, they'll show up as "" in self-profiling data. + { + let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings"); + tcx.alloc_self_profile_query_strings(); + } + info!("Post-codegen\n{:?}", tcx.debug_stats()); if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 4c340b3fc1f5..c671751bf906 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -399,6 +399,7 @@ impl Linker { return Ok(()); } + let _timer = sess.prof.verbose_generic_activity("link_crate"); self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs) } } From 3a3a23ffc5742885187c84e7db320610c8b352fb Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 17 Dec 2020 10:05:39 +0100 Subject: [PATCH 356/719] Fix tests --- compiler/rustc_interface/src/passes.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 3f30b7e69e4f..8b9bf17f3f4c 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -996,9 +996,12 @@ pub fn start_codegen<'tcx>( codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) }); - rustc_incremental::assert_module_sources::assert_module_sources(tcx); - - rustc_symbol_mangling::test::report_symbol_names(tcx); + // Don't run these test assertions when not doing codegen. Compiletest tries to build + // build-fail tests in check mode first and expects it to not give an error in that case. + if tcx.sess.opts.output_types.should_codegen() { + rustc_incremental::assert_module_sources::assert_module_sources(tcx); + rustc_symbol_mangling::test::report_symbol_names(tcx); + } tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx)); tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx)); From 62eab830c859bc4d3d53032e5b7288c7ea6f0c56 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 17 Dec 2020 10:29:58 +0000 Subject: [PATCH 357/719] bootstrap: update ci-llvm stamp after #80087 Unfortunately, #80087 forgot to update the ci-llvm stamp, so the updated ci-llvm tarball with `llvm-dwp` wasn't downloaded by users. This commit updates the ci-llvm stamp to resolve that problem. Signed-off-by: David Wood --- src/bootstrap/download-ci-llvm-stamp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index d857618eefa8..b29ecd65401d 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/78131 +Last change is for: https://github.com/rust-lang/rust/pull/80087 From 7b9ee11a4c1d4fde0ecb0e45e0ebf674e5c775a8 Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Mon, 14 Dec 2020 21:13:40 +0900 Subject: [PATCH 358/719] Enhance error message when misspelled label to value in break expression Apply suggestions from code review Co-authored-by: lcnr --- .../rustc_resolve/src/late/diagnostics.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6ce299a94170..68f59baffce1 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -542,6 +542,26 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_label(base_span, fallback_label); } } + if let Some(err_code) = &err.code { + if err_code == &rustc_errors::error_code!(E0425) { + for label_rib in &self.label_ribs { + for (label_ident, _) in &label_rib.bindings { + if format!("'{}", ident) == label_ident.to_string() { + let msg = "a label with a similar name exists"; + // FIXME: consider only emitting this suggestion if a label would be valid here + // which is pretty much only the case for `break` expressions. + err.span_suggestion( + span, + &msg, + label_ident.name.to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + (err, candidates) } From e9ca2909ad49b9a15c7da29cc4350dda4aeefb10 Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Mon, 14 Dec 2020 21:14:17 +0900 Subject: [PATCH 359/719] Add test case for break expr with misspelled value Update src/test/ui/loops/loop-break-value.rs Co-authored-by: Ivan Tham --- src/test/ui/label/label_misspelled.rs | 18 +++++++++ src/test/ui/label/label_misspelled.stderr | 47 +++++++++++++++++++++++ src/test/ui/loops/loop-break-value.rs | 6 +++ src/test/ui/loops/loop-break-value.stderr | 24 +++++++++++- 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/label/label_misspelled.rs create mode 100644 src/test/ui/label/label_misspelled.stderr diff --git a/src/test/ui/label/label_misspelled.rs b/src/test/ui/label/label_misspelled.rs new file mode 100644 index 000000000000..ebfd5642c9fa --- /dev/null +++ b/src/test/ui/label/label_misspelled.rs @@ -0,0 +1,18 @@ +fn main() { + 'LOOP: loop { + LOOP; + //~^ ERROR cannot find value `LOOP` in this scope + }; + 'while_loop: while true { //~ WARN denote infinite loops with + while_loop; + //~^ ERROR cannot find value `while_loop` in this scope + }; + 'while_let: while let Some(_) = Some(()) { + while_let; + //~^ ERROR cannot find value `while_let` in this scope + } + 'for_loop: for _ in 0..3 { + for_loop; + //~^ ERROR cannot find value `for_loop` in this scope + }; +} diff --git a/src/test/ui/label/label_misspelled.stderr b/src/test/ui/label/label_misspelled.stderr new file mode 100644 index 000000000000..1368ca4126cd --- /dev/null +++ b/src/test/ui/label/label_misspelled.stderr @@ -0,0 +1,47 @@ +error[E0425]: cannot find value `LOOP` in this scope + --> $DIR/label_misspelled.rs:3:9 + | +LL | LOOP; + | ^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'LOOP` + +error[E0425]: cannot find value `while_loop` in this scope + --> $DIR/label_misspelled.rs:7:9 + | +LL | while_loop; + | ^^^^^^^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'while_loop` + +error[E0425]: cannot find value `while_let` in this scope + --> $DIR/label_misspelled.rs:11:9 + | +LL | while_let; + | ^^^^^^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'while_let` + +error[E0425]: cannot find value `for_loop` in this scope + --> $DIR/label_misspelled.rs:15:9 + | +LL | for_loop; + | ^^^^^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'for_loop` + +warning: denote infinite loops with `loop { ... }` + --> $DIR/label_misspelled.rs:6:5 + | +LL | 'while_loop: while true { + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` + | + = note: `#[warn(while_true)]` on by default + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs index 6c4160c36aa3..8a080cfdf494 100644 --- a/src/test/ui/loops/loop-break-value.rs +++ b/src/test/ui/loops/loop-break-value.rs @@ -90,4 +90,10 @@ fn main() { break; //~ ERROR mismatched types break 4; }; + + 'LOOP: for _ in 0 .. 9 { + break LOOP; + //~^ ERROR cannot find value `LOOP` in this scope + //~| ERROR `break` with value from a `for` loop + } } diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr index 0503d3d4c781..0237435c8b46 100644 --- a/src/test/ui/loops/loop-break-value.stderr +++ b/src/test/ui/loops/loop-break-value.stderr @@ -1,3 +1,12 @@ +error[E0425]: cannot find value `LOOP` in this scope + --> $DIR/loop-break-value.rs:95:15 + | +LL | break LOOP; + | ^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'LOOP` + warning: denote infinite loops with `loop { ... }` --> $DIR/loop-break-value.rs:26:5 | @@ -94,6 +103,17 @@ help: instead, use `break` on its own without a value inside this `for` loop LL | break; | ^^^^^ +error[E0571]: `break` with value from a `for` loop + --> $DIR/loop-break-value.rs:95:9 + | +LL | break LOOP; + | ^^^^^^^^^^ can only break with a value inside `loop` or breakable block + | +help: instead, use `break` on its own without a value inside this `for` loop + | +LL | break; + | ^^^^^ + error[E0308]: mismatched types --> $DIR/loop-break-value.rs:4:31 | @@ -151,7 +171,7 @@ LL | break; | expected integer, found `()` | help: give it a value of the expected type: `break value` -error: aborting due to 16 previous errors; 1 warning emitted +error: aborting due to 18 previous errors; 1 warning emitted -Some errors have detailed explanations: E0308, E0571. +Some errors have detailed explanations: E0308, E0425, E0571. For more information about an error, try `rustc --explain E0308`. From e916641fd35bddabc8b018a5e51fe23b93875c66 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Thu, 17 Dec 2020 13:44:08 +0100 Subject: [PATCH 360/719] Address review comments --- compiler/rustc_parse/src/parser/ty.rs | 28 ++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index ee0dc8f6304a..9553f5d09e83 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,6 +43,16 @@ pub(super) enum RecoverQPath { No, } +/// Signals whether parsing a type should recover `->`. +/// +/// More specifically, when parsing a function like: +/// ```rust +/// fn foo() => u8 { 0 } +/// fn bar(): u8 { 0 } +/// ``` +/// The compiler will try to recover interpreting `foo() => u8` as `foo() -> u8` when calling +/// `parse_ty` with anything except `RecoverReturnSign::No`, and it will try to recover `bar(): u8` +/// as `bar() -> u8` when passing `RecoverReturnSign::Yes` to `parse_ty` #[derive(Copy, Clone, PartialEq)] pub(super) enum RecoverReturnSign { Yes, @@ -51,6 +61,10 @@ pub(super) enum RecoverReturnSign { } impl RecoverReturnSign { + /// [RecoverReturnSign::Yes] allows for recovering `fn foo() => u8` and `fn foo(): u8`, + /// [RecoverReturnSign::OnlyFatArrow] allows for recovering only `fn foo() => u8` (recovering + /// colons can cause problems when parsing where clauses), and + /// [RecoverReturnSign::No] doesn't allow for any recovery of the return type arrow fn can_recover(self, token: &TokenKind) -> bool { match self { Self::Yes => matches!(token, token::FatArrow | token::Colon), @@ -81,8 +95,8 @@ impl<'a> Parser<'a> { pub fn parse_ty(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, - RecoverQPath::Yes, AllowCVariadic::No, + RecoverQPath::Yes, RecoverReturnSign::Yes, ) } @@ -93,8 +107,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, - RecoverQPath::Yes, AllowCVariadic::Yes, + RecoverQPath::Yes, RecoverReturnSign::Yes, ) } @@ -108,8 +122,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::No, - RecoverQPath::Yes, AllowCVariadic::No, + RecoverQPath::Yes, RecoverReturnSign::Yes, ) } @@ -118,8 +132,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, - RecoverQPath::Yes, AllowCVariadic::Yes, + RecoverQPath::Yes, RecoverReturnSign::OnlyFatArrow, ) } @@ -135,8 +149,8 @@ impl<'a> Parser<'a> { // FIXME(Centril): Can we unconditionally `allow_plus`? let ty = self.parse_ty_common( allow_plus, - recover_qpath, AllowCVariadic::No, + recover_qpath, recover_return_sign, )?; FnRetTy::Ty(ty) @@ -154,8 +168,8 @@ impl<'a> Parser<'a> { .emit(); let ty = self.parse_ty_common( allow_plus, - recover_qpath, AllowCVariadic::No, + recover_qpath, recover_return_sign, )?; FnRetTy::Ty(ty) @@ -167,8 +181,8 @@ impl<'a> Parser<'a> { fn parse_ty_common( &mut self, allow_plus: AllowPlus, - recover_qpath: RecoverQPath, allow_c_variadic: AllowCVariadic, + recover_qpath: RecoverQPath, recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; From bb68ec6cfc76a6ec69d21c0f64dbc4aa99158958 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Thu, 17 Dec 2020 15:24:44 +0100 Subject: [PATCH 361/719] Apply suggestion from PR review --- clippy_lints/src/doc.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 08134cc16c00..aba655327959 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -407,15 +407,18 @@ fn check_doc<'a, Events: Iterator, Range { in_code = true; if let CodeBlockKind::Fenced(lang) = kind { - let infos = lang.split(',').collect::>(); - is_rust = !infos.iter().any(|&i| i == "ignore") - && infos - .iter() - .any(|i| i.is_empty() || i.starts_with("edition") || RUST_CODE.contains(&i)); - edition = infos - .iter() - .find_map(|i| i.starts_with("edition").then(|| i[7..].parse::().ok())) - .flatten(); + for item in lang.split(',') { + if item == "ignore" { + is_rust = false; + break; + } + if let Some(stripped) = item.strip_prefix("edition") { + is_rust = true; + edition = stripped.parse::().ok(); + } else if item.is_empty() || RUST_CODE.contains(&item) { + is_rust = true; + } + } } }, End(CodeBlock(_)) => { From 46e9212ecb0454d1d5cc9c4d641f4277512111c8 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 17 Dec 2020 16:56:59 +0100 Subject: [PATCH 362/719] Change the message for `if_let_guard` feature gate --- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- src/test/ui/rfc-2294-if-let-guard/feature-gate.rs | 4 ++-- src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 9d54d89e080f..bb222675239a 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -620,7 +620,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { } }; } - gate_all!(if_let_guard, "`if let` guard is not implemented"); + gate_all!(if_let_guard, "`if let` guards are experimental"); gate_all!(let_chains, "`let` expressions in this position are experimental"); gate_all!(async_closure, "async closures are unstable"); gate_all!(generators, "yield syntax is experimental"); diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs index 311d1afcfc0e..4ba7e1eeefaa 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs @@ -5,7 +5,7 @@ use std::ops::Range; fn _if_let_guard() { match () { () if let 0 = 1 => {} - //~^ ERROR `if let` guard is not implemented + //~^ ERROR `if let` guards are experimental () if (let 0 = 1) => {} //~^ ERROR `let` expressions in this position are experimental @@ -74,7 +74,7 @@ fn _macros() { match () { #[cfg(FALSE)] () if let 0 = 1 => {} - //~^ ERROR `if let` guard is not implemented + //~^ ERROR `if let` guards are experimental _ => {} } use_expr!(let 0 = 1); diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr index 1670078e0d38..113870c19f5d 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -7,7 +7,7 @@ LL | macro_rules! use_expr { LL | use_expr!(let 0 = 1); | ^^^ no rules expected this token in macro call -error[E0658]: `if let` guard is not implemented +error[E0658]: `if let` guards are experimental --> $DIR/feature-gate.rs:7:12 | LL | () if let 0 = 1 => {} @@ -16,7 +16,7 @@ LL | () if let 0 = 1 => {} = note: see issue #51114 for more information = help: add `#![feature(if_let_guard)]` to the crate attributes to enable -error[E0658]: `if let` guard is not implemented +error[E0658]: `if let` guards are experimental --> $DIR/feature-gate.rs:76:12 | LL | () if let 0 = 1 => {} From 0ac58f7bf86cd8a3616484b3ff1a794521368536 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Dec 2020 21:37:14 -0500 Subject: [PATCH 363/719] Split apart create_config and run_core --- src/librustdoc/core.rs | 46 +++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b2eeaf584bf2..ed3bc02a5de6 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -273,12 +273,9 @@ where (lint_opts, lint_caps) } -crate fn run_core( - options: RustdocOptions, -) -> (clean::Crate, RenderInfo, RenderOptions, Lrc) { - // Parse, resolve, and typecheck the given crate. - - let RustdocOptions { +/// Parse, resolve, and typecheck the given crate. +fn create_config( + RustdocOptions { input, crate_name, proc_macro_crate, @@ -294,21 +291,10 @@ crate fn run_core( lint_opts, describe_lints, lint_cap, - default_passes, - manual_passes, display_warnings, - render_options, - output_format, .. - } = options; - - let extern_names: Vec = externs - .iter() - .filter(|(_, entry)| entry.add_prelude) - .map(|(name, _)| name) - .cloned() - .collect(); - + }: RustdocOptions, +) -> rustc_interface::Config { // Add the doc cfg into the doc build. cfgs.push("doc".to_string()); @@ -374,7 +360,7 @@ crate fn run_core( ..Options::default() }; - let config = interface::Config { + interface::Config { opts: sessopts, crate_cfg: interface::parse_cfgspecs(cfgs), input, @@ -417,7 +403,25 @@ crate fn run_core( }), make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), - }; + } +} + +crate fn run_core( + options: RustdocOptions, +) -> (clean::Crate, RenderInfo, RenderOptions, Lrc) { + let extern_names: Vec = options + .externs + .iter() + .filter(|(_, entry)| entry.add_prelude) + .map(|(name, _)| name) + .cloned() + .collect(); + let default_passes = options.default_passes; + let output_format = options.output_format; + // TODO: fix this clone (especially render_options) + let manual_passes = options.manual_passes.clone(); + let render_options = options.render_options.clone(); + let config = create_config(options); interface::create_compiler_and_run(config, |compiler| { compiler.enter(|queries| { From 34e8b0aae1fe66e0e0c0f70957cc647361a79ff5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Dec 2020 21:46:58 -0500 Subject: [PATCH 364/719] Separate `create_resolver` into a new function --- src/librustdoc/core.rs | 79 +++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index ed3bc02a5de6..cd05d922f5fe 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -11,7 +11,7 @@ use rustc_hir::{ intravisit::{self, NestedVisitorMap, Visitor}, Path, }; -use rustc_interface::interface; +use rustc_interface::{interface, Queries}; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; @@ -409,16 +409,10 @@ fn create_config( crate fn run_core( options: RustdocOptions, ) -> (clean::Crate, RenderInfo, RenderOptions, Lrc) { - let extern_names: Vec = options - .externs - .iter() - .filter(|(_, entry)| entry.add_prelude) - .map(|(name, _)| name) - .cloned() - .collect(); let default_passes = options.default_passes; let output_format = options.output_format; // TODO: fix this clone (especially render_options) + let externs = options.externs.clone(); let manual_passes = options.manual_passes.clone(); let render_options = options.render_options.clone(); let config = create_config(options); @@ -430,34 +424,7 @@ crate fn run_core( // We need to hold on to the complete resolver, so we cause everything to be // cloned for the analysis passes to use. Suboptimal, but necessary in the // current architecture. - let resolver = { - let parts = abort_on_err(queries.expansion(), sess).peek(); - let resolver = parts.1.borrow(); - - // Before we actually clone it, let's force all the extern'd crates to - // actually be loaded, just in case they're only referred to inside - // intra-doc-links - resolver.borrow_mut().access(|resolver| { - sess.time("load_extern_crates", || { - for extern_name in &extern_names { - debug!("loading extern crate {}", extern_name); - resolver - .resolve_str_path_error( - DUMMY_SP, - extern_name, - TypeNS, - LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(), - ) - .unwrap_or_else(|()| { - panic!("Unable to resolve external crate {}", extern_name) - }); - } - }); - }); - - // Now we're good to clone the resolver because everything should be loaded - resolver.clone() - }; + let resolver = create_resolver(externs, queries, &sess); if sess.has_errors() { sess.fatal("Compilation failed, aborting rustdoc"); @@ -482,6 +449,46 @@ crate fn run_core( }) } +fn create_resolver<'a>( + externs: config::Externs, + queries: &Queries<'a>, + sess: &Session, +) -> Lrc> { + let extern_names: Vec = externs + .iter() + .filter(|(_, entry)| entry.add_prelude) + .map(|(name, _)| name) + .cloned() + .collect(); + + let parts = abort_on_err(queries.expansion(), sess).peek(); + let resolver = parts.1.borrow(); + + // Before we actually clone it, let's force all the extern'd crates to + // actually be loaded, just in case they're only referred to inside + // intra-doc-links + resolver.borrow_mut().access(|resolver| { + sess.time("load_extern_crates", || { + for extern_name in &extern_names { + debug!("loading extern crate {}", extern_name); + resolver + .resolve_str_path_error( + DUMMY_SP, + extern_name, + TypeNS, + LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(), + ) + .unwrap_or_else(|()| { + panic!("Unable to resolve external crate {}", extern_name) + }); + } + }); + }); + + // Now we're good to clone the resolver because everything should be loaded + resolver.clone() +} + fn run_global_ctxt( tcx: TyCtxt<'_>, resolver: Rc>, From 79ab333cf0e8b49676cabc7d8bdaa785a688a67a Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Dec 2020 21:57:48 -0500 Subject: [PATCH 365/719] Move `run_renderer` into the main `global_ctxt` closure --- src/librustdoc/core.rs | 49 ++------------------ src/librustdoc/lib.rs | 103 +++++++++++++++++++++++++++++++---------- 2 files changed, 81 insertions(+), 71 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index cd05d922f5fe..3b789dfd66f4 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -274,7 +274,7 @@ where } /// Parse, resolve, and typecheck the given crate. -fn create_config( +crate fn create_config( RustdocOptions { input, crate_name, @@ -406,50 +406,7 @@ fn create_config( } } -crate fn run_core( - options: RustdocOptions, -) -> (clean::Crate, RenderInfo, RenderOptions, Lrc) { - let default_passes = options.default_passes; - let output_format = options.output_format; - // TODO: fix this clone (especially render_options) - let externs = options.externs.clone(); - let manual_passes = options.manual_passes.clone(); - let render_options = options.render_options.clone(); - let config = create_config(options); - - interface::create_compiler_and_run(config, |compiler| { - compiler.enter(|queries| { - let sess = compiler.session(); - - // We need to hold on to the complete resolver, so we cause everything to be - // cloned for the analysis passes to use. Suboptimal, but necessary in the - // current architecture. - let resolver = create_resolver(externs, queries, &sess); - - if sess.has_errors() { - sess.fatal("Compilation failed, aborting rustdoc"); - } - - let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); - - let (krate, render_info, opts) = sess.time("run_global_ctxt", || { - global_ctxt.enter(|tcx| { - run_global_ctxt( - tcx, - resolver, - default_passes, - manual_passes, - render_options, - output_format, - ) - }) - }); - (krate, render_info, opts, Lrc::clone(sess)) - }) - }) -} - -fn create_resolver<'a>( +crate fn create_resolver<'a>( externs: config::Externs, queries: &Queries<'a>, sess: &Session, @@ -489,7 +446,7 @@ fn create_resolver<'a>( resolver.clone() } -fn run_global_ctxt( +crate fn run_global_ctxt( tcx: TyCtxt<'_>, resolver: Rc>, mut default_passes: passes::DefaultPassOption, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 24045b4e29dc..93c849859aba 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -63,7 +63,9 @@ use std::env; use std::process; use rustc_data_structures::sync::Lrc; +use rustc_driver::abort_on_err; use rustc_errors::ErrorReported; +use rustc_interface::interface; use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; use rustc_session::getopts; use rustc_session::Session; @@ -520,34 +522,85 @@ fn main_options(options: config::Options) -> MainResult { // then generated from the cleaned AST of the crate. This runs all the // plug/cleaning passes. let crate_version = options.crate_version.clone(); + + let default_passes = options.default_passes; let output_format = options.output_format; - let (mut krate, renderinfo, renderopts, sess) = core::run_core(options); + // TODO: fix this clone (especially render_options) + let externs = options.externs.clone(); + let manual_passes = options.manual_passes.clone(); + let render_options = options.render_options.clone(); + let config = core::create_config(options); - info!("finished with rustc"); + interface::create_compiler_and_run(config, |compiler| { + compiler.enter(|queries| { + let sess = compiler.session(); - krate.version = crate_version; + // We need to hold on to the complete resolver, so we cause everything to be + // cloned for the analysis passes to use. Suboptimal, but necessary in the + // current architecture. + let resolver = core::create_resolver(externs, queries, &sess); - if show_coverage { - // if we ran coverage, bail early, we don't need to also generate docs at this point - // (also we didn't load in any of the useful passes) - return Ok(()); - } else if run_check { - // Since we're in "check" mode, no need to generate anything beyond this point. - return Ok(()); - } + if sess.has_errors() { + sess.fatal("Compilation failed, aborting rustdoc"); + } - info!("going to format"); - let (error_format, edition, debugging_options) = diag_opts; - let diag = core::new_handler(error_format, None, &debugging_options); - let sess_time = sess.clone(); - match output_format { - None | Some(config::OutputFormat::Html) => sess_time.time("render_html", || { - run_renderer::( - krate, renderopts, renderinfo, &diag, edition, sess, - ) - }), - Some(config::OutputFormat::Json) => sess_time.time("render_json", || { - run_renderer::(krate, renderopts, renderinfo, &diag, edition, sess) - }), - } + let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); + + global_ctxt.enter(|tcx| { + let (mut krate, render_info, render_opts) = sess.time("run_global_ctxt", || { + core::run_global_ctxt( + tcx, + resolver, + default_passes, + manual_passes, + render_options, + output_format, + ) + }); + info!("finished with rustc"); + + if let Some(name) = crate_name { + krate.name = name + } + + krate.version = crate_version; + + if show_coverage { + // if we ran coverage, bail early, we don't need to also generate docs at this point + // (also we didn't load in any of the useful passes) + return Ok(()); + } else if run_check { + // Since we're in "check" mode, no need to generate anything beyond this point. + return Ok(()); + } + + info!("going to format"); + let (error_format, edition, debugging_options) = diag_opts; + let diag = core::new_handler(error_format, None, &debugging_options); + let sess_format = sess.clone(); + match output_format { + None | Some(config::OutputFormat::Html) => sess.time("render_html", || { + run_renderer::( + krate, + render_opts, + render_info, + &diag, + edition, + sess_format, + ) + }), + Some(config::OutputFormat::Json) => sess.time("render_json", || { + run_renderer::( + krate, + render_opts, + render_info, + &diag, + edition, + sess_format, + ) + }), + } + }) + }) + }) } From 9221d4d1d347ee50f31d2bf50e13ecfdf14c4611 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 16 Dec 2020 14:23:14 -0500 Subject: [PATCH 366/719] [tmp] Pass `TyCtxt` through to the render backend First actually useful step in https://github.com/rust-lang/rust/issues/76382 This doesn't yet compile because there's no way to get a `Lrc` from a TyCtxt, only a `&Session`. --- src/librustdoc/formats/renderer.rs | 9 ++++----- src/librustdoc/html/render/mod.rs | 5 +++-- src/librustdoc/json/mod.rs | 5 +++-- src/librustdoc/lib.rs | 13 +++++-------- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index f61919d78a09..7ec29a70bd0a 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -1,7 +1,6 @@ use std::sync::Arc; -use rustc_data_structures::sync::Lrc; -use rustc_session::Session; +use rustc_middle::ty; use rustc_span::edition::Edition; use crate::clean; @@ -21,7 +20,7 @@ crate trait FormatRenderer: Clone { render_info: RenderInfo, edition: Edition, cache: &mut Cache, - sess: Lrc, + tcx: ty::TyCtxt<'_>, ) -> Result<(Self, clean::Crate), Error>; /// Renders a single non-module item. This means no recursive sub-item rendering is required. @@ -52,7 +51,7 @@ crate fn run_format( render_info: RenderInfo, diag: &rustc_errors::Handler, edition: Edition, - sess: Lrc, + tcx: ty::TyCtxt<'_>, ) -> Result<(), Error> { let (krate, mut cache) = Cache::from_krate( render_info.clone(), @@ -63,7 +62,7 @@ crate fn run_format( ); let (mut format_renderer, mut krate) = - T::init(krate, options, render_info, edition, &mut cache, sess)?; + T::init(krate, options, render_info, edition, &mut cache, tcx)?; let cache = Arc::new(cache); // Freeze the cache now that the index has been built. Put an Arc into TLS for future diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index a775c85435cb..d8d46adfb63d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -57,6 +57,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::Mutability; use rustc_middle::middle::stability; +use rustc_middle::ty; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; @@ -388,7 +389,7 @@ impl FormatRenderer for Context { _render_info: RenderInfo, edition: Edition, cache: &mut Cache, - sess: Lrc, + tcx: ty::TyCtxt<'_>, ) -> Result<(Context, clean::Crate), Error> { // need to save a copy of the options for rendering the index page let md_opts = options.clone(); @@ -462,7 +463,7 @@ impl FormatRenderer for Context { } let (sender, receiver) = channel(); let mut scx = SharedContext { - sess, + tcx, collapsed: krate.collapsed, src_root, include_sources, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 7af26558b76e..3d970918407c 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -14,6 +14,7 @@ use std::rc::Rc; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use rustc_middle::ty; use rustc_session::Session; use rustc_span::edition::Edition; @@ -127,12 +128,12 @@ impl FormatRenderer for JsonRenderer { _render_info: RenderInfo, _edition: Edition, _cache: &mut Cache, - sess: Lrc, + tcx: ty::TyCtxt<'_>, ) -> Result<(Self, clean::Crate), Error> { debug!("Initializing json renderer"); Ok(( JsonRenderer { - sess, + sess: tcx.sess, index: Rc::new(RefCell::new(FxHashMap::default())), out_path: options.output, }, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 93c849859aba..caa0706fd2b5 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -62,13 +62,11 @@ use std::default::Default; use std::env; use std::process; -use rustc_data_structures::sync::Lrc; use rustc_driver::abort_on_err; use rustc_errors::ErrorReported; -use rustc_interface::interface; +use rustc_middle::ty; use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; use rustc_session::getopts; -use rustc_session::Session; use rustc_session::{early_error, early_warn}; #[macro_use] @@ -476,9 +474,9 @@ fn run_renderer( render_info: config::RenderInfo, diag: &rustc_errors::Handler, edition: rustc_span::edition::Edition, - sess: Lrc, + tcx: ty::TyCtxt<'_>, ) -> MainResult { - match formats::run_format::(krate, renderopts, render_info, &diag, edition, sess) { + match formats::run_format::(krate, renderopts, render_info, &diag, edition, tcx) { Ok(_) => Ok(()), Err(e) => { let mut msg = diag.struct_err(&format!("couldn't generate documentation: {}", e.error)); @@ -577,7 +575,6 @@ fn main_options(options: config::Options) -> MainResult { info!("going to format"); let (error_format, edition, debugging_options) = diag_opts; let diag = core::new_handler(error_format, None, &debugging_options); - let sess_format = sess.clone(); match output_format { None | Some(config::OutputFormat::Html) => sess.time("render_html", || { run_renderer::( @@ -586,7 +583,7 @@ fn main_options(options: config::Options) -> MainResult { render_info, &diag, edition, - sess_format, + tcx, ) }), Some(config::OutputFormat::Json) => sess.time("render_json", || { @@ -596,7 +593,7 @@ fn main_options(options: config::Options) -> MainResult { render_info, &diag, edition, - sess_format, + tcx, ) }), } From 47c969436adf2cc5acfbddf1061fb30d0fdacd34 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 16 Dec 2020 14:34:08 -0500 Subject: [PATCH 367/719] Make it compile --- src/librustdoc/formats/renderer.rs | 8 +- src/librustdoc/html/render/mod.rs | 122 ++++++++++++++++++----------- src/librustdoc/html/sources.rs | 12 +-- src/librustdoc/json/conversions.rs | 8 +- src/librustdoc/json/mod.rs | 17 ++-- src/librustdoc/lib.rs | 9 ++- 6 files changed, 104 insertions(+), 72 deletions(-) diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index 7ec29a70bd0a..fbbd3c1ccf51 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -11,7 +11,7 @@ use crate::formats::cache::{Cache, CACHE_KEY}; /// Allows for different backends to rustdoc to be used with the `run_format()` function. Each /// backend renderer has hooks for initialization, documenting an item, entering and exiting a /// module, and cleanup/finalizing output. -crate trait FormatRenderer: Clone { +crate trait FormatRenderer<'tcx>: Clone { /// Sets up any state required for the renderer. When this is called the cache has already been /// populated. fn init( @@ -20,7 +20,7 @@ crate trait FormatRenderer: Clone { render_info: RenderInfo, edition: Edition, cache: &mut Cache, - tcx: ty::TyCtxt<'_>, + tcx: ty::TyCtxt<'tcx>, ) -> Result<(Self, clean::Crate), Error>; /// Renders a single non-module item. This means no recursive sub-item rendering is required. @@ -45,13 +45,13 @@ crate trait FormatRenderer: Clone { } /// Main method for rendering a crate. -crate fn run_format( +crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( krate: clean::Crate, options: RenderOptions, render_info: RenderInfo, diag: &rustc_errors::Handler, edition: Edition, - tcx: ty::TyCtxt<'_>, + tcx: ty::TyCtxt<'tcx>, ) -> Result<(), Error> { let (krate, mut cache) = Cache::from_krate( render_info.clone(), diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d8d46adfb63d..e6d3fdbe185d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -52,12 +52,12 @@ use rustc_ast_pretty::pprust; use rustc_attr::{Deprecation, StabilityLevel}; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::Mutability; use rustc_middle::middle::stability; use rustc_middle::ty; +use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; @@ -103,7 +103,7 @@ crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { /// easily cloned because it is cloned per work-job (about once per item in the /// rustdoc tree). #[derive(Clone)] -crate struct Context { +crate struct Context<'tcx> { /// Current hierarchy of components leading down to what's currently being /// rendered crate current: Vec, @@ -116,15 +116,15 @@ crate struct Context { crate render_redirect_pages: bool, /// The map used to ensure all generated 'id=' attributes are unique. id_map: Rc>, - crate shared: Arc, + crate shared: Arc>, all: Rc>, /// Storage for the errors produced while generating documentation so they /// can be printed together at the end. crate errors: Rc>, } -crate struct SharedContext { - crate sess: Lrc, +crate struct SharedContext<'tcx> { + crate tcx: TyCtxt<'tcx>, /// The path to the crate root source minus the file name. /// Used for simplifying paths to the highlighted source code files. crate src_root: PathBuf, @@ -164,7 +164,7 @@ crate struct SharedContext { playground: Option, } -impl Context { +impl Context<'_> { fn path(&self, filename: &str) -> PathBuf { // We use splitn vs Path::extension here because we might get a filename // like `style.min.css` and we want to process that into @@ -177,11 +177,11 @@ impl Context { } fn sess(&self) -> &Session { - &self.shared.sess + &self.shared.tcx.sess } } -impl SharedContext { +impl SharedContext<'_> { crate fn ensure_dir(&self, dst: &Path) -> Result<(), Error> { let mut dirs = self.created_dirs.borrow_mut(); if !dirs.contains(dst) { @@ -382,15 +382,15 @@ crate fn initial_ids() -> Vec { } /// Generates the documentation for `crate` into the directory `dst` -impl FormatRenderer for Context { +impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { fn init( mut krate: clean::Crate, options: RenderOptions, _render_info: RenderInfo, edition: Edition, cache: &mut Cache, - tcx: ty::TyCtxt<'_>, - ) -> Result<(Context, clean::Crate), Error> { + tcx: ty::TyCtxt<'tcx>, + ) -> Result<(Self, clean::Crate), Error> { // need to save a copy of the options for rendering the index page let md_opts = options.clone(); let RenderOptions { @@ -689,7 +689,7 @@ impl FormatRenderer for Context { } fn write_shared( - cx: &Context, + cx: &Context<'_>, krate: &clean::Crate, search_index: String, options: &RenderOptions, @@ -1206,7 +1206,7 @@ fn write_minify( } } -fn write_srclink(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) { +fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Cache) { if let Some(l) = cx.src_href(item, cache) { write!( buf, @@ -1517,7 +1517,7 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result { fn derive_id(&self, id: String) -> String { let mut map = self.id_map.borrow_mut(); map.derive(id) @@ -1702,7 +1702,7 @@ where write!(w, "") } -fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) { +fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Cache) { debug_assert!(!item.is_stripped()); // Write the breadcrumb trail header for the top write!(buf, "

"); @@ -1817,14 +1817,14 @@ fn item_path(ty: ItemType, name: &str) -> String { } } -fn full_path(cx: &Context, item: &clean::Item) -> String { +fn full_path(cx: &Context<'_>, item: &clean::Item) -> String { let mut s = cx.current.join("::"); s.push_str("::"); s.push_str(&item.name.unwrap().as_str()); s } -fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) { +fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option<&clean::Item>) { if let Some(ref name) = item.name { info!("Documenting {}", name); } @@ -1835,7 +1835,7 @@ fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&cl /// Render md_text as markdown. fn render_markdown( w: &mut Buffer, - cx: &Context, + cx: &Context<'_>, md_text: &str, links: Vec, prefix: &str, @@ -1864,7 +1864,7 @@ fn render_markdown( fn document_short( w: &mut Buffer, item: &clean::Item, - cx: &Context, + cx: &Context<'_>, link: AssocItemLink<'_>, prefix: &str, is_hidden: bool, @@ -1905,7 +1905,13 @@ fn document_short( } } -fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str, is_hidden: bool) { +fn document_full( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + prefix: &str, + is_hidden: bool, +) { if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) { debug!("Doc block: =====\n{}\n=====", s); render_markdown(w, cx, &*s, item.links(), prefix, is_hidden); @@ -1926,7 +1932,7 @@ fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str, /// * Required features (through the `doc_cfg` feature) fn document_item_info( w: &mut Buffer, - cx: &Context, + cx: &Context<'_>, item: &clean::Item, is_hidden: bool, parent: Option<&clean::Item>, @@ -2030,7 +2036,7 @@ crate fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering { Ordering::Equal } -fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) { +fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) { document(w, cx, item, None); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); @@ -2272,7 +2278,11 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option) -> Vec { +fn short_item_info( + item: &clean::Item, + cx: &Context<'_>, + parent: Option<&clean::Item>, +) -> Vec { let mut extra_info = vec![]; let error_codes = cx.shared.codes; @@ -2362,7 +2372,7 @@ fn short_item_info(item: &clean::Item, cx: &Context, parent: Option<&clean::Item extra_info } -fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Constant) { +fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) { write!(w, "
");
     render_attributes(w, it, false);
 
@@ -2397,7 +2407,7 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons
     document(w, cx, it, None)
 }
 
-fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) {
+fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
     write!(w, "
");
     render_attributes(w, it, false);
     write!(
@@ -2411,7 +2421,7 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static
     document(w, cx, it, None)
 }
 
-fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) {
+fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
     let header_len = format!(
         "{}{}{}{}{:#}fn {}{:#}",
         it.visibility.print_with_space(),
@@ -2445,7 +2455,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
 }
 
 fn render_implementor(
-    cx: &Context,
+    cx: &Context<'_>,
     implementor: &Impl,
     parent: &clean::Item,
     w: &mut Buffer,
@@ -2482,7 +2492,7 @@ fn render_implementor(
 }
 
 fn render_impls(
-    cx: &Context,
+    cx: &Context<'_>,
     w: &mut Buffer,
     traits: &[&&Impl],
     containing_item: &clean::Item,
@@ -2541,7 +2551,7 @@ fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering {
     compare_names(&lhs, &rhs)
 }
 
-fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, cache: &Cache) {
+fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait, cache: &Cache) {
     let bounds = bounds(&t.bounds, false);
     let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>();
     let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>();
@@ -2637,7 +2647,13 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
         write!(w, "{}Loading content...", extra_content)
     }
 
-    fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item, cache: &Cache) {
+    fn trait_item(
+        w: &mut Buffer,
+        cx: &Context<'_>,
+        m: &clean::Item,
+        t: &clean::Item,
+        cache: &Cache,
+    ) {
         let name = m.name.as_ref().unwrap();
         info!("Documenting {} on {:?}", name, t.name);
         let item_type = m.type_();
@@ -3040,7 +3056,13 @@ fn render_assoc_item(
     }
 }
 
-fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct, cache: &Cache) {
+fn item_struct(
+    w: &mut Buffer,
+    cx: &Context<'_>,
+    it: &clean::Item,
+    s: &clean::Struct,
+    cache: &Cache,
+) {
     wrap_into_docblock(w, |w| {
         write!(w, "
");
         render_attributes(w, it, true);
@@ -3090,7 +3112,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
 
-fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, cache: &Cache) {
+fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union, cache: &Cache) {
     wrap_into_docblock(w, |w| {
         write!(w, "
");
         render_attributes(w, it, true);
@@ -3136,7 +3158,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union,
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
 
-fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, cache: &Cache) {
+fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum, cache: &Cache) {
     wrap_into_docblock(w, |w| {
         write!(w, "
");
         render_attributes(w, it, true);
@@ -3444,7 +3466,7 @@ impl<'a> AssocItemLink<'a> {
 
 fn render_assoc_items(
     w: &mut Buffer,
-    cx: &Context,
+    cx: &Context<'_>,
     containing_item: &clean::Item,
     it: DefId,
     what: AssocItemRender<'_>,
@@ -3560,7 +3582,7 @@ fn render_assoc_items(
 
 fn render_deref_methods(
     w: &mut Buffer,
-    cx: &Context,
+    cx: &Context<'_>,
     impl_: &Impl,
     container_item: &clean::Item,
     deref_mut: bool,
@@ -3676,7 +3698,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String {
 
 fn render_impl(
     w: &mut Buffer,
-    cx: &Context,
+    cx: &Context<'_>,
     i: &Impl,
     parent: &clean::Item,
     link: AssocItemLink<'_>,
@@ -3770,7 +3792,7 @@ fn render_impl(
 
     fn doc_impl_item(
         w: &mut Buffer,
-        cx: &Context,
+        cx: &Context<'_>,
         item: &clean::Item,
         parent: &clean::Item,
         link: AssocItemLink<'_>,
@@ -3907,7 +3929,7 @@ fn render_impl(
 
     fn render_default_items(
         w: &mut Buffer,
-        cx: &Context,
+        cx: &Context<'_>,
         t: &clean::Trait,
         i: &clean::Impl,
         parent: &clean::Item,
@@ -3967,7 +3989,7 @@ fn render_impl(
 
 fn item_opaque_ty(
     w: &mut Buffer,
-    cx: &Context,
+    cx: &Context<'_>,
     it: &clean::Item,
     t: &clean::OpaqueTy,
     cache: &Cache,
@@ -3994,7 +4016,7 @@ fn item_opaque_ty(
 
 fn item_trait_alias(
     w: &mut Buffer,
-    cx: &Context,
+    cx: &Context<'_>,
     it: &clean::Item,
     t: &clean::TraitAlias,
     cache: &Cache,
@@ -4019,7 +4041,13 @@ fn item_trait_alias(
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
 
-fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typedef, cache: &Cache) {
+fn item_typedef(
+    w: &mut Buffer,
+    cx: &Context<'_>,
+    it: &clean::Item,
+    t: &clean::Typedef,
+    cache: &Cache,
+) {
     write!(w, "
");
     render_attributes(w, it, false);
     write!(
@@ -4040,7 +4068,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typed
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
 
-fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cache) {
+fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, cache: &Cache) {
     writeln!(w, "
extern {{");
     render_attributes(w, it, false);
     write!(
@@ -4055,7 +4083,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cac
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
 
-fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Cache) {
+fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache: &Cache) {
     let parentlen = cx.current.len() - if it.is_mod() { 1 } else { 0 };
 
     if it.is_struct()
@@ -4686,7 +4714,7 @@ fn sidebar_foreign_type(buf: &mut Buffer, it: &clean::Item) {
     }
 }
 
-fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) {
+fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
     wrap_into_docblock(w, |w| {
         w.write_str(&highlight::render_with_highlighting(
             t.source.clone(),
@@ -4698,7 +4726,7 @@ fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro)
     document(w, cx, it, None)
 }
 
-fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) {
+fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
     let name = it.name.as_ref().expect("proc-macros always have names");
     match m.kind {
         MacroKind::Bang => {
@@ -4728,12 +4756,12 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::Pr
     document(w, cx, it, None)
 }
 
-fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cache) {
+fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, cache: &Cache) {
     document(w, cx, it, None);
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
 
-fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) {
+fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
     document(w, cx, it, None)
 }
 
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index b6c3300906bf..87934c8a0e50 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -15,7 +15,7 @@ use std::path::{Component, Path, PathBuf};
 
 crate fn render(
     dst: &Path,
-    scx: &mut SharedContext,
+    scx: &mut SharedContext<'_>,
     krate: clean::Crate,
 ) -> Result {
     info!("emitting source files");
@@ -26,14 +26,14 @@ crate fn render(
 }
 
 /// Helper struct to render all source code to HTML pages
-struct SourceCollector<'a> {
-    scx: &'a mut SharedContext,
+struct SourceCollector<'a, 'tcx> {
+    scx: &'a mut SharedContext<'tcx>,
 
     /// Root destination to place all HTML output into
     dst: PathBuf,
 }
 
-impl<'a> DocFolder for SourceCollector<'a> {
+impl DocFolder for SourceCollector<'_, '_> {
     fn fold_item(&mut self, item: clean::Item) -> Option {
         // If we're not rendering sources, there's nothing to do.
         // If we're including source files, and we haven't seen this file yet,
@@ -69,9 +69,9 @@ impl<'a> DocFolder for SourceCollector<'a> {
     }
 }
 
-impl<'a> SourceCollector<'a> {
+impl SourceCollector<'_, '_> {
     fn sess(&self) -> &Session {
-        &self.scx.sess
+        &self.scx.tcx.sess
     }
 
     /// Renders the given filename into its corresponding HTML source file.
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 809cfb9d7432..c362b9d2b964 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -14,7 +14,7 @@ use crate::formats::item_type::ItemType;
 use crate::json::types::*;
 use crate::json::JsonRenderer;
 
-impl JsonRenderer {
+impl JsonRenderer<'_> {
     pub(super) fn convert_item(&self, item: clean::Item) -> Option {
         let item_type = ItemType::from(&item);
         let clean::Item {
@@ -57,10 +57,10 @@ impl JsonRenderer {
     }
 
     fn convert_span(&self, span: clean::Span) -> Option {
-        match span.filename(&self.sess) {
+        match span.filename(self.sess()) {
             rustc_span::FileName::Real(name) => {
-                let hi = span.hi(&self.sess);
-                let lo = span.lo(&self.sess);
+                let hi = span.hi(self.sess());
+                let lo = span.lo(self.sess());
                 Some(Span {
                     filename: match name {
                         rustc_span::RealFileName::Named(path) => path,
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 3d970918407c..dc2bc14e7ceb 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -13,7 +13,6 @@ use std::path::PathBuf;
 use std::rc::Rc;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
 use rustc_middle::ty;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -26,8 +25,8 @@ use crate::formats::FormatRenderer;
 use crate::html::render::cache::ExternalLocation;
 
 #[derive(Clone)]
-crate struct JsonRenderer {
-    sess: Lrc,
+crate struct JsonRenderer<'tcx> {
+    tcx: ty::TyCtxt<'tcx>,
     /// A mapping of IDs that contains all local items for this crate which gets output as a top
     /// level field of the JSON blob.
     index: Rc>>,
@@ -35,7 +34,11 @@ crate struct JsonRenderer {
     out_path: PathBuf,
 }
 
-impl JsonRenderer {
+impl JsonRenderer<'_> {
+    fn sess(&self) -> &Session {
+        self.tcx.sess
+    }
+
     fn get_trait_implementors(
         &mut self,
         id: rustc_span::def_id::DefId,
@@ -121,19 +124,19 @@ impl JsonRenderer {
     }
 }
 
-impl FormatRenderer for JsonRenderer {
+impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     fn init(
         krate: clean::Crate,
         options: RenderOptions,
         _render_info: RenderInfo,
         _edition: Edition,
         _cache: &mut Cache,
-        tcx: ty::TyCtxt<'_>,
+        tcx: ty::TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
         debug!("Initializing json renderer");
         Ok((
             JsonRenderer {
-                sess: tcx.sess,
+                tcx,
                 index: Rc::new(RefCell::new(FxHashMap::default())),
                 out_path: options.output,
             },
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index caa0706fd2b5..2d3b4f870685 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -64,6 +64,7 @@ use std::process;
 
 use rustc_driver::abort_on_err;
 use rustc_errors::ErrorReported;
+use rustc_interface::interface;
 use rustc_middle::ty;
 use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
 use rustc_session::getopts;
@@ -468,13 +469,13 @@ fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainRes
     }
 }
 
-fn run_renderer(
+fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     krate: clean::Crate,
     renderopts: config::RenderOptions,
     render_info: config::RenderInfo,
     diag: &rustc_errors::Handler,
     edition: rustc_span::edition::Edition,
-    tcx: ty::TyCtxt<'_>,
+    tcx: ty::TyCtxt<'tcx>,
 ) -> MainResult {
     match formats::run_format::(krate, renderopts, render_info, &diag, edition, tcx) {
         Ok(_) => Ok(()),
@@ -577,7 +578,7 @@ fn main_options(options: config::Options) -> MainResult {
                 let diag = core::new_handler(error_format, None, &debugging_options);
                 match output_format {
                     None | Some(config::OutputFormat::Html) => sess.time("render_html", || {
-                        run_renderer::(
+                        run_renderer::>(
                             krate,
                             render_opts,
                             render_info,
@@ -587,7 +588,7 @@ fn main_options(options: config::Options) -> MainResult {
                         )
                     }),
                     Some(config::OutputFormat::Json) => sess.time("render_json", || {
-                        run_renderer::(
+                        run_renderer::>(
                             krate,
                             render_opts,
                             render_info,

From 789c902914e66285b36987a4f397d06ac50fed9e Mon Sep 17 00:00:00 2001
From: Joshua Nelson 
Date: Wed, 16 Dec 2020 16:02:15 -0500
Subject: [PATCH 368/719] Fix error with `--cfg parallel_compiler`

Apparently expansion() really does return Rc, not Lrc
---
 src/librustdoc/core.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 3b789dfd66f4..7e85342ac7d5 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -410,7 +410,7 @@ crate fn create_resolver<'a>(
     externs: config::Externs,
     queries: &Queries<'a>,
     sess: &Session,
-) -> Lrc> {
+) -> Rc> {
     let extern_names: Vec = externs
         .iter()
         .filter(|(_, entry)| entry.add_prelude)

From b421f2e8e94e578ed200dde235b7510b6a7014ba Mon Sep 17 00:00:00 2001
From: Joshua Nelson 
Date: Wed, 16 Dec 2020 16:22:11 -0500
Subject: [PATCH 369/719] TODO -> FIXME

---
 src/librustdoc/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 2d3b4f870685..0275a6ecd093 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -524,7 +524,7 @@ fn main_options(options: config::Options) -> MainResult {
 
     let default_passes = options.default_passes;
     let output_format = options.output_format;
-    // TODO: fix this clone (especially render_options)
+    // FIXME: fix this clone (especially render_options)
     let externs = options.externs.clone();
     let manual_passes = options.manual_passes.clone();
     let render_options = options.render_options.clone();

From 0c2f76a4bf515a9c1bdb930ffb7f32b7ba6bd726 Mon Sep 17 00:00:00 2001
From: Joshua Nelson 
Date: Thu, 17 Dec 2020 11:40:02 -0500
Subject: [PATCH 370/719] Fix rebase conflict

---
 src/librustdoc/lib.rs | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 0275a6ecd093..72f1b817d5d8 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -558,10 +558,6 @@ fn main_options(options: config::Options) -> MainResult {
                 });
                 info!("finished with rustc");
 
-                if let Some(name) = crate_name {
-                    krate.name = name
-                }
-
                 krate.version = crate_version;
 
                 if show_coverage {

From 88dc58fc9bb3dddccb99fc0e9f7a917c2052f8d0 Mon Sep 17 00:00:00 2001
From: David Wood 
Date: Thu, 17 Dec 2020 16:06:24 +0000
Subject: [PATCH 371/719] Revert "cg_llvm: `fewer_names` in
 `uncached_llvm_type`"

This reverts commit fa01ce802f1b403a2140fd945b43af86ec3998a1.
---
 compiler/rustc_codegen_llvm/src/type_of.rs | 10 +---------
 src/test/ui/issues/issue-75763.rs          |  3 ++-
 2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 8ea4768f77db..0876907e1194 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -40,9 +40,7 @@ fn uncached_llvm_type<'a, 'tcx>(
         // FIXME(eddyb) producing readable type names for trait objects can result
         // in problematically distinct types due to HRTB and subtyping (see #47638).
         // ty::Dynamic(..) |
-        ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str
-            if !cx.sess().fewer_names() =>
-        {
+        ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str => {
             let mut name = with_no_trimmed_paths(|| layout.ty.to_string());
             if let (&ty::Adt(def, _), &Variants::Single { index }) =
                 (layout.ty.kind(), &layout.variants)
@@ -58,12 +56,6 @@ fn uncached_llvm_type<'a, 'tcx>(
             }
             Some(name)
         }
-        ty::Adt(..) => {
-            // If `Some` is returned then a named struct is created in LLVM. Name collisions are
-            // avoided by LLVM (with increasing suffixes). If rustc doesn't generate names then that
-            // can improve perf.
-            Some(String::new())
-        }
         _ => None,
     };
 
diff --git a/src/test/ui/issues/issue-75763.rs b/src/test/ui/issues/issue-75763.rs
index 2fd9f9a60de9..c311de05a1cf 100644
--- a/src/test/ui/issues/issue-75763.rs
+++ b/src/test/ui/issues/issue-75763.rs
@@ -1,4 +1,5 @@
-// build-pass
+// ignore-test
+// FIXME(const_generics): This test causes an ICE after reverting #76030.
 
 #![allow(incomplete_features)]
 #![feature(const_generics)]

From 3f671bc94450aff38d7fcd9243327a20cb553ee0 Mon Sep 17 00:00:00 2001
From: Ohad Ravid 
Date: Mon, 16 Nov 2020 15:38:22 +0200
Subject: [PATCH 372/719] Added `impl Div for u{0}` which cannot
 panic

---
 library/core/src/num/nonzero.rs | 30 +++++++++++++++++++++++++++++-
 library/core/tests/nonzero.rs   |  8 ++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 716b4a90e5ec..3355fb64ecfd 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -1,7 +1,7 @@
 //! Definitions of integer that is known not to equal zero.
 
 use crate::fmt;
-use crate::ops::{BitOr, BitOrAssign};
+use crate::ops::{BitOr, BitOrAssign, Div};
 use crate::str::FromStr;
 
 use super::from_str_radix;
@@ -263,3 +263,31 @@ nonzero_leading_trailing_zeros! {
     NonZeroI128(u128), -1i128;
     NonZeroIsize(usize), -1isize;
 }
+
+macro_rules! nonzero_integers_div {
+    ( $( $Ty: ident($Int: ty); )+ ) => {
+        $(
+            #[stable(feature = "nonzero_div", since = "1.50.0")]
+            impl Div<$Ty> for $Int {
+                type Output = $Int;
+                /// This operation rounds towards zero,
+                /// truncating any fractional part of the exact result, and cannot panic.
+                #[inline]
+                fn div(self, other: $Ty) -> $Int {
+                    // SAFETY: div by zero is checked because `other` is a nonzero,
+                    // and MIN/-1 is checked because `self` is an unsigned int.
+                    unsafe { crate::intrinsics::unchecked_div(self, other.get()) }
+                }
+            }
+        )+
+    }
+}
+
+nonzero_integers_div! {
+    NonZeroU8(u8);
+    NonZeroU16(u16);
+    NonZeroU32(u32);
+    NonZeroU64(u64);
+    NonZeroU128(u128);
+    NonZeroUsize(usize);
+}
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index b66c482c5e5e..6ec3a04adc08 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -312,3 +312,11 @@ fn nonzero_trailing_zeros() {
     const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros();
     assert_eq!(TRAILING_ZEROS, 2);
 }
+
+#[test]
+fn test_nonzero_uint_div() {
+    let nz = NonZeroU32::new(1).unwrap();
+
+    let x: u32 = 42u32 / nz;
+    assert_eq!(x, 42u32);
+}

From 1e9e30dc404edaec5bf5ef9c1d88157a883da374 Mon Sep 17 00:00:00 2001
From: Ohad Ravid 
Date: Wed, 18 Nov 2020 07:48:03 +0200
Subject: [PATCH 373/719] Added `impl Rem for u{0}` which cannot
 panic

---
 library/core/src/num/nonzero.rs | 14 +++++++++++++-
 library/core/tests/nonzero.rs   |  8 ++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 3355fb64ecfd..e139facb6ea4 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -1,7 +1,7 @@
 //! Definitions of integer that is known not to equal zero.
 
 use crate::fmt;
-use crate::ops::{BitOr, BitOrAssign, Div};
+use crate::ops::{BitOr, BitOrAssign, Div, Rem};
 use crate::str::FromStr;
 
 use super::from_str_radix;
@@ -279,6 +279,18 @@ macro_rules! nonzero_integers_div {
                     unsafe { crate::intrinsics::unchecked_div(self, other.get()) }
                 }
             }
+
+            #[stable(feature = "nonzero_div", since = "1.50.0")]
+            impl Rem<$Ty> for $Int {
+                type Output = $Int;
+                /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
+                #[inline]
+                fn rem(self, other: $Ty) -> $Int {
+                    // SAFETY: rem by zero is checked because `other` is a nonzero,
+                    // and MIN/-1 is checked because `self` is an unsigned int.
+                    unsafe { crate::intrinsics::unchecked_rem(self, other.get()) }
+                }
+            }
         )+
     }
 }
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index 6ec3a04adc08..c2c08522d0ca 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -320,3 +320,11 @@ fn test_nonzero_uint_div() {
     let x: u32 = 42u32 / nz;
     assert_eq!(x, 42u32);
 }
+
+#[test]
+fn test_nonzero_uint_rem() {
+    let nz = NonZeroU32::new(10).unwrap();
+
+    let x: u32 = 42u32 % nz;
+    assert_eq!(x, 2u32);
+}

From 01f36c51c2b6fd3a95b6cdfacff92725cd81d5b0 Mon Sep 17 00:00:00 2001
From: DrMeepster <19316085+DrMeepster@users.noreply.github.com>
Date: Thu, 17 Dec 2020 09:18:06 -0800
Subject: [PATCH 374/719] fix memory leak in test

---
 library/core/tests/mem.rs | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
index 5e24fa690ef5..86990fa0945a 100644
--- a/library/core/tests/mem.rs
+++ b/library/core/tests/mem.rs
@@ -250,14 +250,19 @@ fn uninit_write_slice_cloned_mid_panic() {
 
 #[test]
 fn uninit_write_slice_cloned_no_drop() {
-    let rc = Rc::new(());
+    #[derive(Clone)]
+    struct Bomb;
+
+    impl Drop for Bomb {
+        fn drop(&mut self) {
+            panic!("dropped a bomb! kaboom")
+        }
+    }
 
     let mut dst = [MaybeUninit::uninit()];
-    let src = [rc.clone()];
+    let src = [Bomb];
 
     MaybeUninit::write_slice_cloned(&mut dst, &src);
 
-    drop(src);
-
-    assert_eq!(Rc::strong_count(&rc), 2);
+    forget(src);
 }

From 44e226ceb753075b44bcaadf349b1d1b6a23ad8d Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Thu, 17 Dec 2020 14:02:09 +0100
Subject: [PATCH 375/719] Continue String to Symbol conversion in rustdoc

---
 src/librustdoc/clean/auto_trait.rs  | 14 ++++++-------
 src/librustdoc/clean/inline.rs      |  8 ++++----
 src/librustdoc/clean/mod.rs         | 25 +++++++++++-----------
 src/librustdoc/clean/types.rs       | 32 +++++++++++++++--------------
 src/librustdoc/clean/utils.rs       |  2 +-
 src/librustdoc/html/format.rs       | 17 ++++++++-------
 src/librustdoc/html/render/cache.rs | 14 ++++++-------
 src/librustdoc/html/render/mod.rs   | 12 +++++------
 src/librustdoc/json/conversions.rs  | 19 ++++++++++-------
 9 files changed, 74 insertions(+), 69 deletions(-)

diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 72603f00697e..40c59ed1e0b7 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -61,10 +61,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                             .params
                             .iter()
                             .filter_map(|param| match param.kind {
-                                ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()),
+                                ty::GenericParamDefKind::Lifetime => Some(param.name),
                                 _ => None,
                             })
-                            .map(|name| (name.clone(), Lifetime(name)))
+                            .map(|name| (name, Lifetime(name)))
                             .collect();
                         let lifetime_predicates = self.handle_lifetimes(®ion_data, &names_map);
                         let new_generics = self.param_env_to_generics(
@@ -145,21 +145,21 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
     fn get_lifetime(
         &self,
         region: Region<'_>,
-        names_map: &FxHashMap,
+        names_map: &FxHashMap,
     ) -> Lifetime {
         self.region_name(region)
             .map(|name| {
                 names_map.get(&name).unwrap_or_else(|| {
-                    panic!("Missing lifetime with name {:?} for {:?}", name, region)
+                    panic!("Missing lifetime with name {:?} for {:?}", name.as_str(), region)
                 })
             })
             .unwrap_or(&Lifetime::statik())
             .clone()
     }
 
-    fn region_name(&self, region: Region<'_>) -> Option {
+    fn region_name(&self, region: Region<'_>) -> Option {
         match region {
-            &ty::ReEarlyBound(r) => Some(r.name.to_string()),
+            &ty::ReEarlyBound(r) => Some(r.name),
             _ => None,
         }
     }
@@ -177,7 +177,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
     fn handle_lifetimes<'cx>(
         &self,
         regions: &RegionConstraintData<'cx>,
-        names_map: &FxHashMap,
+        names_map: &FxHashMap,
     ) -> Vec {
         // Our goal is to 'flatten' the list of constraints by eliminating
         // all intermediate RegionVids. At the end, all constraints should
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 7bb8e5e8cfcb..3cff5fa07b15 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -486,13 +486,13 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet)
                         const_stability: None,
                         deprecation: None,
                         kind: clean::ImportItem(clean::Import::new_simple(
-                            item.ident.to_string(),
+                            item.ident.name,
                             clean::ImportSource {
                                 path: clean::Path {
                                     global: false,
                                     res: item.res,
                                     segments: vec![clean::PathSegment {
-                                        name: clean::PrimitiveType::from(p).as_str().to_string(),
+                                        name: clean::PrimitiveType::from(p).as_sym(),
                                         args: clean::GenericArgs::AngleBracketed {
                                             args: Vec::new(),
                                             bindings: Vec::new(),
@@ -562,11 +562,11 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind
                     .collect::()
             );
 
-            clean::MacroItem(clean::Macro { source, imported_from: Some(imported_from).clean(cx) })
+            clean::MacroItem(clean::Macro { source, imported_from: Some(imported_from) })
         }
         LoadedMacro::ProcMacro(ext) => clean::ProcMacroItem(clean::ProcMacro {
             kind: ext.macro_kind(),
-            helpers: ext.helper_attrs.clean(cx),
+            helpers: ext.helper_attrs,
         }),
     }
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2105ec0b0ba0..43272aeda612 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -379,7 +379,7 @@ impl Clean for hir::Lifetime {
             }
             _ => {}
         }
-        Lifetime(self.name.ident().to_string())
+        Lifetime(self.name.ident().name)
     }
 }
 
@@ -397,9 +397,9 @@ impl Clean for hir::GenericParam<'_> {
                     for bound in bounds {
                         s.push_str(&format!(" + {}", bound.name.ident()));
                     }
-                    Lifetime(s)
+                    Lifetime(Symbol::intern(&s))
                 } else {
-                    Lifetime(self.name.ident().to_string())
+                    Lifetime(self.name.ident().name)
                 }
             }
             _ => panic!(),
@@ -423,16 +423,16 @@ impl Clean for hir::ConstArg {
 
 impl Clean for ty::GenericParamDef {
     fn clean(&self, _cx: &DocContext<'_>) -> Lifetime {
-        Lifetime(self.name.to_string())
+        Lifetime(self.name)
     }
 }
 
 impl Clean> for ty::RegionKind {
-    fn clean(&self, cx: &DocContext<'_>) -> Option {
+    fn clean(&self, _cx: &DocContext<'_>) -> Option {
         match *self {
             ty::ReStatic => Some(Lifetime::statik()),
-            ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
-            ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
+            ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name)),
+            ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)),
 
             ty::ReLateBound(..)
             | ty::ReFree(..)
@@ -897,7 +897,7 @@ fn clean_fn_or_proc_macro(
                     }
                 }
             }
-            ProcMacroItem(ProcMacro { kind, helpers: helpers.clean(cx) })
+            ProcMacroItem(ProcMacro { kind, helpers })
         }
         None => {
             let mut func = (sig, generics, body_id).clean(cx);
@@ -1914,7 +1914,7 @@ impl Clean for hir::GenericArgs<'_> {
 
 impl Clean for hir::PathSegment<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> PathSegment {
-        PathSegment { name: self.ident.name.clean(cx), args: self.generic_args().clean(cx) }
+        PathSegment { name: self.ident.name, args: self.generic_args().clean(cx) }
     }
 }
 
@@ -2132,7 +2132,6 @@ fn clean_extern_crate(
             return items;
         }
     }
-    let path = orig_name.map(|x| x.to_string());
     // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
     vec![Item {
         name: None,
@@ -2143,7 +2142,7 @@ fn clean_extern_crate(
         stability: None,
         const_stability: None,
         deprecation: None,
-        kind: ExternCrateItem(name.clean(cx), path),
+        kind: ExternCrateItem(name, orig_name),
     }]
 }
 
@@ -2215,7 +2214,7 @@ impl Clean> for doctree::Import<'_> {
                         const_stability: None,
                         deprecation: None,
                         kind: ImportItem(Import::new_simple(
-                            self.name.clean(cx),
+                            self.name,
                             resolve_use_source(cx, path),
                             false,
                         )),
@@ -2223,7 +2222,7 @@ impl Clean> for doctree::Import<'_> {
                     return items;
                 }
             }
-            Import::new_simple(name.clean(cx), resolve_use_source(cx, path), true)
+            Import::new_simple(name, resolve_use_source(cx, path), true)
         };
 
         vec![Item {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 9bade5ad2ecf..4920e6fd6f15 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -295,7 +295,7 @@ impl Item {
 
 #[derive(Clone, Debug)]
 crate enum ItemKind {
-    ExternCrateItem(String, Option),
+    ExternCrateItem(Symbol, Option),
     ImportItem(Import),
     StructItem(Struct),
     UnionItem(Union),
@@ -877,21 +877,19 @@ impl GenericBound {
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-crate struct Lifetime(pub String);
+crate struct Lifetime(pub Symbol);
 
 impl Lifetime {
-    crate fn get_ref<'a>(&'a self) -> &'a str {
-        let Lifetime(ref s) = *self;
-        let s: &'a str = s;
-        s
+    crate fn get_ref(&self) -> SymbolStr {
+        self.0.as_str()
     }
 
     crate fn statik() -> Lifetime {
-        Lifetime("'static".to_string())
+        Lifetime(kw::StaticLifetime)
     }
 
     crate fn elided() -> Lifetime {
-        Lifetime("'_".to_string())
+        Lifetime(kw::UnderscoreLifetime)
     }
 }
 
@@ -1675,13 +1673,17 @@ crate struct Path {
 }
 
 impl Path {
-    crate fn last_name(&self) -> &str {
+    crate fn last(&self) -> Symbol {
+        self.segments.last().expect("segments were empty").name
+    }
+
+    crate fn last_name(&self) -> SymbolStr {
         self.segments.last().expect("segments were empty").name.as_str()
     }
 
     crate fn whole_name(&self) -> String {
         String::from(if self.global { "::" } else { "" })
-            + &self.segments.iter().map(|s| s.name.clone()).collect::>().join("::")
+            + &self.segments.iter().map(|s| s.name.to_string()).collect::>().join("::")
     }
 }
 
@@ -1700,7 +1702,7 @@ crate enum GenericArgs {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 crate struct PathSegment {
-    crate name: String,
+    crate name: Symbol,
     crate args: GenericArgs,
 }
 
@@ -1777,7 +1779,7 @@ crate struct Import {
 }
 
 impl Import {
-    crate fn new_simple(name: String, source: ImportSource, should_be_displayed: bool) -> Self {
+    crate fn new_simple(name: Symbol, source: ImportSource, should_be_displayed: bool) -> Self {
         Self { kind: ImportKind::Simple(name), source, should_be_displayed }
     }
 
@@ -1789,7 +1791,7 @@ impl Import {
 #[derive(Clone, Debug)]
 crate enum ImportKind {
     // use source as str;
-    Simple(String),
+    Simple(Symbol),
     // use source::*;
     Glob,
 }
@@ -1803,13 +1805,13 @@ crate struct ImportSource {
 #[derive(Clone, Debug)]
 crate struct Macro {
     crate source: String,
-    crate imported_from: Option,
+    crate imported_from: Option,
 }
 
 #[derive(Clone, Debug)]
 crate struct ProcMacro {
     crate kind: MacroKind,
-    crate helpers: Vec,
+    crate helpers: Vec,
 }
 
 /// An type binding on an associated type (e.g., `A = Bar` in `Foo` or
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index ec922b182e2b..1ae2e5de82c4 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -153,7 +153,7 @@ pub(super) fn external_path(
         global: false,
         res: Res::Err,
         segments: vec![PathSegment {
-            name: name.to_string(),
+            name,
             args: external_generic_args(cx, trait_did, has_self, bindings, substs),
         }],
     }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index c49c48922378..f80346aa50b4 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -308,7 +308,7 @@ impl<'a> fmt::Display for WhereClause<'a> {
 }
 
 impl clean::Lifetime {
-    crate fn print(&self) -> &str {
+    crate fn print(&self) -> impl fmt::Display + '_ {
         self.get_ref()
     }
 }
@@ -445,11 +445,10 @@ impl clean::GenericArgs {
 impl clean::PathSegment {
     crate fn print(&self) -> impl fmt::Display + '_ {
         display_fn(move |f| {
-            f.write_str(&self.name)?;
             if f.alternate() {
-                write!(f, "{:#}", self.args.print())
+                write!(f, "{}{:#}", self.name, self.args.print())
             } else {
-                write!(f, "{}", self.args.print())
+                write!(f, "{}{}", self.name, self.args.print())
             }
         })
     }
@@ -544,7 +543,7 @@ fn resolved_path(
                 last.name.to_string()
             }
         } else {
-            anchor(did, &last.name).to_string()
+            anchor(did, &*last.name.as_str()).to_string()
         };
         write!(w, "{}{}", path, last.args.print())?;
     }
@@ -1159,11 +1158,11 @@ impl PrintWithSpace for hir::Mutability {
 impl clean::Import {
     crate fn print(&self) -> impl fmt::Display + '_ {
         display_fn(move |f| match self.kind {
-            clean::ImportKind::Simple(ref name) => {
-                if *name == self.source.path.last_name() {
+            clean::ImportKind::Simple(name) => {
+                if name == self.source.path.last() {
                     write!(f, "use {};", self.source.print())
                 } else {
-                    write!(f, "use {} as {};", self.source.print(), *name)
+                    write!(f, "use {} as {};", self.source.print(), name)
                 }
             }
             clean::ImportKind::Glob => {
@@ -1187,7 +1186,7 @@ impl clean::ImportSource {
                 }
                 let name = self.path.last_name();
                 if let hir::def::Res::PrimTy(p) = self.path.res {
-                    primitive_link(f, PrimitiveType::from(p), name)?;
+                    primitive_link(f, PrimitiveType::from(p), &*name)?;
                 } else {
                     write!(f, "{}", name)?;
                 }
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 80f54d8e161a..94a8b3fef47d 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
 use std::path::Path;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{sym, Symbol};
 use serde::Serialize;
 
 use crate::clean::types::GetDefId;
@@ -191,12 +191,12 @@ fn get_index_type(clean_type: &clean::Type) -> RenderType {
     RenderType {
         ty: clean_type.def_id(),
         idx: None,
-        name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()),
+        name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
         generics: get_generics(clean_type),
     }
 }
 
-fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option {
+fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option {
     match *clean_type {
         clean::ResolvedPath { ref path, .. } => {
             let segments = &path.segments;
@@ -206,10 +206,10 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
                 clean_type, accept_generic
             )
             });
-            Some(path_segment.name.clone())
+            Some(path_segment.name)
         }
-        clean::Generic(s) if accept_generic => Some(s.to_string()),
-        clean::Primitive(ref p) => Some(format!("{:?}", p)),
+        clean::Generic(s) if accept_generic => Some(s),
+        clean::Primitive(ref p) => Some(p.as_sym()),
         clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
         // FIXME: add all from clean::Type.
         _ => None,
@@ -222,7 +222,7 @@ fn get_generics(clean_type: &clean::Type) -> Option> {
             .iter()
             .filter_map(|t| {
                 get_index_type_name(t, false).map(|name| Generic {
-                    name: name.to_ascii_lowercase(),
+                    name: name.as_str().to_ascii_lowercase(),
                     defid: t.def_id(),
                     idx: None,
                 })
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 00294878fe5f..1e888e83e199 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2137,14 +2137,14 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
                         w,
                         "{}extern crate {} as {};",
                         myitem.visibility.print_with_space(),
-                        anchor(myitem.def_id, src),
+                        anchor(myitem.def_id, &*src.as_str()),
                         name
                     ),
                     None => write!(
                         w,
                         "{}extern crate {};",
                         myitem.visibility.print_with_space(),
-                        anchor(myitem.def_id, name)
+                        anchor(myitem.def_id, &*name.as_str())
                     ),
                 }
                 write!(w, "");
@@ -2444,7 +2444,7 @@ fn render_implementor(
     implementor: &Impl,
     parent: &clean::Item,
     w: &mut Buffer,
-    implementor_dups: &FxHashMap<&str, (DefId, bool)>,
+    implementor_dups: &FxHashMap,
     aliases: &[String],
     cache: &Cache,
 ) {
@@ -2455,7 +2455,7 @@ fn render_implementor(
         | clean::BorrowedRef {
             type_: box clean::ResolvedPath { ref path, is_generic: false, .. },
             ..
-        } => implementor_dups[path.last_name()].1,
+        } => implementor_dups[&path.last()].1,
         _ => false,
     };
     render_impl(
@@ -2704,7 +2704,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
     if let Some(implementors) = cache.implementors.get(&it.def_id) {
         // The DefId is for the first Type found with that name. The bool is
         // if any Types with the same name but different DefId have been found.
-        let mut implementor_dups: FxHashMap<&str, (DefId, bool)> = FxHashMap::default();
+        let mut implementor_dups: FxHashMap = FxHashMap::default();
         for implementor in implementors {
             match implementor.inner_impl().for_ {
                 clean::ResolvedPath { ref path, did, is_generic: false, .. }
@@ -2713,7 +2713,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
                     ..
                 } => {
                     let &mut (prev_did, ref mut has_duplicates) =
-                        implementor_dups.entry(path.last_name()).or_insert((did, false));
+                        implementor_dups.entry(path.last()).or_insert((did, false));
                     if prev_did != did {
                         *has_duplicates = true;
                     }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 809cfb9d7432..9dc27e3411dd 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -120,7 +120,7 @@ impl From for GenericArg {
     fn from(arg: clean::GenericArg) -> Self {
         use clean::GenericArg::*;
         match arg {
-            Lifetime(l) => GenericArg::Lifetime(l.0),
+            Lifetime(l) => GenericArg::Lifetime(l.0.to_string()),
             Type(t) => GenericArg::Type(t.into()),
             Const(c) => GenericArg::Const(c.into()),
         }
@@ -163,7 +163,9 @@ impl From for ItemEnum {
         use clean::ItemKind::*;
         match item {
             ModuleItem(m) => ItemEnum::ModuleItem(m.into()),
-            ExternCrateItem(c, a) => ItemEnum::ExternCrateItem { name: c, rename: a },
+            ExternCrateItem(c, a) => {
+                ItemEnum::ExternCrateItem { name: c.to_string(), rename: a.map(|x| x.to_string()) }
+            }
             ImportItem(i) => ItemEnum::ImportItem(i.into()),
             StructItem(s) => ItemEnum::StructItem(s.into()),
             UnionItem(u) => ItemEnum::StructItem(u.into()),
@@ -302,7 +304,7 @@ impl From for WherePredicate {
                 bounds: bounds.into_iter().map(Into::into).collect(),
             },
             RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
-                lifetime: lifetime.0,
+                lifetime: lifetime.0.to_string(),
                 bounds: bounds.into_iter().map(Into::into).collect(),
             },
             EqPredicate { lhs, rhs } => {
@@ -323,7 +325,7 @@ impl From for GenericBound {
                     modifier: modifier.into(),
                 }
             }
-            Outlives(lifetime) => GenericBound::Outlives(lifetime.0),
+            Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()),
         }
     }
 }
@@ -365,7 +367,7 @@ impl From for Type {
                 type_: Box::new((*type_).into()),
             },
             BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
-                lifetime: lifetime.map(|l| l.0),
+                lifetime: lifetime.map(|l| l.0.to_string()),
                 mutable: mutability == ast::Mutability::Mut,
                 type_: Box::new((*type_).into()),
             },
@@ -503,7 +505,7 @@ impl From for Import {
         match import.kind {
             Simple(s) => Import {
                 span: import.source.path.whole_name(),
-                name: s,
+                name: s.to_string(),
                 id: import.source.did.map(Into::into),
                 glob: false,
             },
@@ -519,7 +521,10 @@ impl From for Import {
 
 impl From for ProcMacro {
     fn from(mac: clean::ProcMacro) -> Self {
-        ProcMacro { kind: mac.kind.into(), helpers: mac.helpers }
+        ProcMacro {
+            kind: mac.kind.into(),
+            helpers: mac.helpers.iter().map(|x| x.to_string()).collect(),
+        }
     }
 }
 

From 8e234d5d4b5985fe80af50472e637d77c472c6cc Mon Sep 17 00:00:00 2001
From: bjorn3 
Date: Thu, 17 Dec 2020 18:35:44 +0100
Subject: [PATCH 376/719] Rustup to rustc 1.50.0-nightly (b32e6e6ac 2020-12-16)

---
 build_sysroot/Cargo.lock | 8 ++++----
 build_sysroot/Cargo.toml | 3 ++-
 rust-toolchain           | 2 +-
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/build_sysroot/Cargo.lock b/build_sysroot/Cargo.lock
index a2b8f449f00f..990557694ead 100644
--- a/build_sysroot/Cargo.lock
+++ b/build_sysroot/Cargo.lock
@@ -47,9 +47,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "cc"
-version = "1.0.65"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
+checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
 
 [[package]]
 name = "cfg-if"
@@ -141,9 +141,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.80"
+version = "0.2.81"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
+checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
 dependencies = [
  "rustc-std-workspace-core",
 ]
diff --git a/build_sysroot/Cargo.toml b/build_sysroot/Cargo.toml
index e562dedb5324..3dbd28c286a2 100644
--- a/build_sysroot/Cargo.toml
+++ b/build_sysroot/Cargo.toml
@@ -5,13 +5,14 @@ version = "0.0.0"
 
 [dependencies]
 core = { path = "./sysroot_src/library/core" }
-compiler_builtins = "0.1"
 alloc = { path = "./sysroot_src/library/alloc" }
 std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
 test = { path = "./sysroot_src/library/test" }
 
 alloc_system = { path = "./alloc_system" }
 
+compiler_builtins = { version = "=0.1.36", default-features = false }
+
 [patch.crates-io]
 rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
 rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
diff --git a/rust-toolchain b/rust-toolchain
index 547f1e0d8f0c..eeee23d6a8ba 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-nightly-2020-12-03
+nightly-2020-12-17

From 29114ff0fb79f63f14ba1958e745324cedc13b2d Mon Sep 17 00:00:00 2001
From: Stein Somers 
Date: Mon, 23 Nov 2020 14:41:53 +0100
Subject: [PATCH 377/719] BTreeMap: relax the explicit borrow rule to make code
 shorter and safer

---
 library/alloc/src/collections/btree/map.rs  |   2 +-
 library/alloc/src/collections/btree/node.rs | 212 ++++++++++----------
 2 files changed, 108 insertions(+), 106 deletions(-)

diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index bd2ad257402f..735213363f60 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -248,7 +248,7 @@ where
         let (map, dormant_map) = DormantMutRef::new(self);
         let root_node = Self::ensure_is_owned(&mut map.root).borrow_mut();
         match search::search_tree::, K, (), K>(root_node, &key) {
-            Found(handle) => Some(mem::replace(handle.into_key_mut(), key)),
+            Found(mut kv) => Some(mem::replace(kv.key_mut(), key)),
             GoDown(handle) => {
                 VacantEntry { key, handle, dormant_map, _marker: PhantomData }.insert(());
                 None
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 22e179af4a93..a3ff83561f1b 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -239,17 +239,16 @@ impl NodeRef {
 /// - We cannot get implicit coercion from say `Mut<'a>` to `Immut<'a>`.
 ///   Therefore, we have to explicitly call `reborrow` on a more powerfull
 ///   `NodeRef` in order to reach a method like `key_at`.
-/// - All methods on `NodeRef` that return some kind of reference, except
-///   `reborrow` and `reborrow_mut`, take `self` by value and not by reference.
-///   This avoids silently returning a second reference somewhere in the tree.
-///   That is irrelevant when `BorrowType` is `Immut<'a>`, but the rule does
-///   no harm because we make those `NodeRef` implicitly `Copy`.
-///   The rule also avoids implicitly returning the lifetime of `&self`,
-///   instead of the lifetime carried by `BorrowType`.
-///   An exception to this rule are the insert functions.
-/// - Given the above, we need a `reborrow_mut` to explicitly copy a `Mut<'a>`
-///   `NodeRef` whenever we want to invoke a method returning an extra reference
-///   somewhere in the tree.
+///
+/// All methods on `NodeRef` that return some kind of reference, either:
+/// - Take `self` by value, and return the lifetime carried by `BorrowType`.
+///   Sometimes, to invoke such a method, we need to call `reborrow_mut`.
+/// - Take `self` by reference, and (implicitly) return that reference's
+///   lifetime, instead of the lifetime carried by `BorrowType`. That way,
+///   the borrow checker guarantees that the `NodeRef` remains borrowed as long
+///   as the returned reference is used.
+///   The methods supporting insert bend this rule by returning a raw pointer,
+///   i.e., a reference without any lifetime.
 pub struct NodeRef {
     /// The number of levels that the node and the level of leaves are apart, a
     /// constant of the node that cannot be entirely described by `Type`, and that
@@ -305,9 +304,9 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> {
 }
 
 impl<'a, K, V> NodeRef, K, V, marker::Internal> {
-    /// Offers exclusive access to the data of an internal node.
-    fn as_internal_mut(this: &mut Self) -> &'a mut InternalNode {
-        let ptr = Self::as_internal_ptr(this);
+    /// Borrows exclusive access to the data of an internal node.
+    fn as_internal_mut(&mut self) -> &mut InternalNode {
+        let ptr = Self::as_internal_ptr(self);
         unsafe { &mut *ptr }
     }
 }
@@ -355,7 +354,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> {
     /// The node has more than `idx` initialized elements.
     pub unsafe fn key_at(self, idx: usize) -> &'a K {
         debug_assert!(idx < self.len());
-        unsafe { Self::as_leaf(&self).keys.get_unchecked(idx).assume_init_ref() }
+        unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() }
     }
 
     /// Exposes one of the values stored in the node.
@@ -364,7 +363,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> {
     /// The node has more than `idx` initialized elements.
     unsafe fn val_at(self, idx: usize) -> &'a V {
         debug_assert!(idx < self.len());
-        unsafe { Self::as_leaf(&self).vals.get_unchecked(idx).assume_init_ref() }
+        unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() }
     }
 }
 
@@ -431,8 +430,8 @@ impl NodeRef {
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> {
     /// Exposes the leaf portion of any leaf or internal node in an immutable tree.
-    fn as_leaf(this: &Self) -> &'a LeafNode {
-        let ptr = Self::as_leaf_ptr(this);
+    fn into_leaf(self) -> &'a LeafNode {
+        let ptr = Self::as_leaf_ptr(&self);
         // SAFETY: there can be no mutable references into this tree borrowed as `Immut`.
         unsafe { &*ptr }
     }
@@ -489,42 +488,49 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> {
         NodeRef { height: self.height, node: self.node, _marker: PhantomData }
     }
 
+    /// Borrows exclusive access to the leaf portion of any leaf or internal node.
+    fn as_leaf_mut(&mut self) -> &mut LeafNode {
+        let ptr = Self::as_leaf_ptr(self);
+        // SAFETY: we have exclusive access to the entire node.
+        unsafe { &mut *ptr }
+    }
+
     /// Offers exclusive access to the leaf portion of any leaf or internal node.
-    fn as_leaf_mut(this: &mut Self) -> &'a mut LeafNode {
-        let ptr = Self::as_leaf_ptr(this);
+    fn into_leaf_mut(mut self) -> &'a mut LeafNode {
+        let ptr = Self::as_leaf_ptr(&mut self);
         // SAFETY: we have exclusive access to the entire node.
         unsafe { &mut *ptr }
     }
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> {
-    /// Offers exclusive access to a part of the key storage area.
+    /// Borrows exclusive access to an element of the key storage area.
     ///
     /// # Safety
     /// The node has more than `idx` initialized elements.
-    unsafe fn into_key_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit {
+    unsafe fn key_area_mut_at(&mut self, idx: usize) -> &mut MaybeUninit {
         debug_assert!(idx < self.len());
-        unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(idx) }
+        unsafe { self.as_leaf_mut().keys.get_unchecked_mut(idx) }
     }
 
-    /// Offers exclusive access to a part of the value storage area.
+    /// Borrows exclusive access to an element of the value storage area.
     ///
     /// # Safety
     /// The node has more than `idx` initialized elements.
-    unsafe fn into_val_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit {
+    unsafe fn val_area_mut_at(&mut self, idx: usize) -> &mut MaybeUninit {
         debug_assert!(idx < self.len());
-        unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(idx) }
+        unsafe { self.as_leaf_mut().vals.get_unchecked_mut(idx) }
     }
 }
 
 impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> {
-    /// Offers exclusive access to a part of the storage area for edge contents.
+    /// Borrows exclusive access to an element of the storage area for edge contents.
     ///
     /// # Safety
     /// The node has at least `idx` initialized elements.
-    unsafe fn into_edge_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit> {
+    unsafe fn edge_area_mut_at(&mut self, idx: usize) -> &mut MaybeUninit> {
         debug_assert!(idx <= self.len());
-        unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(idx) }
+        unsafe { self.as_internal_mut().edges.get_unchecked_mut(idx) }
     }
 }
 
@@ -533,14 +539,14 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> {
     /// regardless of the node's current length,
     /// having exclusive access to the entire node.
     unsafe fn key_area(self) -> &'a [MaybeUninit] {
-        Self::as_leaf(&self).keys.as_slice()
+        self.into_leaf().keys.as_slice()
     }
 
     /// Exposes the entire value storage area in the node,
     /// regardless of the node's current length,
     /// having exclusive access to the entire node.
     unsafe fn val_area(self) -> &'a [MaybeUninit] {
-        Self::as_leaf(&self).vals.as_slice()
+        self.into_leaf().vals.as_slice()
     }
 }
 
@@ -554,33 +560,33 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> {
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> {
-    /// Offers exclusive access to a sized slice of key storage area in the node.
-    unsafe fn into_key_area_slice(mut self) -> &'a mut [MaybeUninit] {
+    /// Borrows exclusive access to a sized slice of key storage area in the node.
+    unsafe fn key_area_slice(&mut self) -> &mut [MaybeUninit] {
         let len = self.len();
         // SAFETY: the caller will not be able to call further methods on self
         // until the key slice reference is dropped, as we have unique access
         // for the lifetime of the borrow.
-        unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(..len) }
+        unsafe { self.as_leaf_mut().keys.get_unchecked_mut(..len) }
     }
 
-    /// Offers exclusive access to a sized slice of value storage area in the node.
-    unsafe fn into_val_area_slice(mut self) -> &'a mut [MaybeUninit] {
+    /// Borrows exclusive access to a sized slice of value storage area in the node.
+    unsafe fn val_area_slice(&mut self) -> &mut [MaybeUninit] {
         let len = self.len();
         // SAFETY: the caller will not be able to call further methods on self
         // until the value slice reference is dropped, as we have unique access
         // for the lifetime of the borrow.
-        unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(..len) }
+        unsafe { self.as_leaf_mut().vals.get_unchecked_mut(..len) }
     }
 }
 
 impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> {
-    /// Offers exclusive access to a sized slice of storage area for edge contents in the node.
-    unsafe fn into_edge_area_slice(mut self) -> &'a mut [MaybeUninit>] {
+    /// Borrows exclusive access to a sized slice of storage area for edge contents in the node.
+    unsafe fn edge_area_slice(&mut self) -> &mut [MaybeUninit>] {
         let len = self.len();
         // SAFETY: the caller will not be able to call further methods on self
         // until the edge slice reference is dropped, as we have unique access
         // for the lifetime of the borrow.
-        unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(..len + 1) }
+        unsafe { self.as_internal_mut().edges.get_unchecked_mut(..len + 1) }
     }
 }
 
@@ -604,9 +610,9 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> {
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> {
-    /// Exposes exclusive access to the length of the node.
-    pub fn into_len_mut(mut self) -> &'a mut u16 {
-        &mut (*Self::as_leaf_mut(&mut self)).len
+    /// Borrows exclusive access to the length of the node.
+    pub fn len_mut(&mut self) -> &mut u16 {
+        &mut self.as_leaf_mut().len
     }
 }
 
@@ -623,7 +629,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> {
 impl NodeRef {
     /// Clears the root's link to its parent edge.
     fn clear_parent_link(&mut self) {
-        let leaf = NodeRef::as_leaf_mut(&mut self.borrow_mut());
+        let mut root_node = self.borrow_mut();
+        let leaf = root_node.as_leaf_mut();
         leaf.parent = None;
     }
 }
@@ -631,13 +638,13 @@ impl NodeRef {
 impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> {
     /// Adds a key-value pair to the end of the node.
     pub fn push(&mut self, key: K, val: V) {
-        let len = unsafe { self.reborrow_mut().into_len_mut() };
+        let len = self.len_mut();
         let idx = usize::from(*len);
         assert!(idx < CAPACITY);
         *len += 1;
         unsafe {
-            self.reborrow_mut().into_key_area_mut_at(idx).write(key);
-            self.reborrow_mut().into_val_area_mut_at(idx).write(val);
+            self.key_area_mut_at(idx).write(key);
+            self.val_area_mut_at(idx).write(val);
         }
     }
 
@@ -646,9 +653,9 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> {
         assert!(self.len() < CAPACITY);
 
         unsafe {
-            *self.reborrow_mut().into_len_mut() += 1;
-            slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
-            slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
+            *self.len_mut() += 1;
+            slice_insert(self.key_area_slice(), 0, key);
+            slice_insert(self.val_area_slice(), 0, val);
         }
     }
 }
@@ -675,14 +682,14 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> {
     pub fn push(&mut self, key: K, val: V, edge: Root) {
         assert!(edge.height == self.height - 1);
 
-        let len = unsafe { self.reborrow_mut().into_len_mut() };
+        let len = self.len_mut();
         let idx = usize::from(*len);
         assert!(idx < CAPACITY);
         *len += 1;
         unsafe {
-            self.reborrow_mut().into_key_area_mut_at(idx).write(key);
-            self.reborrow_mut().into_val_area_mut_at(idx).write(val);
-            self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.node);
+            self.key_area_mut_at(idx).write(key);
+            self.val_area_mut_at(idx).write(val);
+            self.edge_area_mut_at(idx + 1).write(edge.node);
             Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link();
         }
     }
@@ -694,10 +701,10 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> {
         assert!(self.len() < CAPACITY);
 
         unsafe {
-            *self.reborrow_mut().into_len_mut() += 1;
-            slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
-            slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
-            slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.node);
+            *self.len_mut() += 1;
+            slice_insert(self.key_area_slice(), 0, key);
+            slice_insert(self.val_area_slice(), 0, val);
+            slice_insert(self.edge_area_slice(), 0, edge.node);
         }
 
         self.correct_all_childrens_parent_links();
@@ -728,7 +735,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> {
                 }
             };
 
-            *self.reborrow_mut().into_len_mut() -= 1;
+            *self.len_mut() -= 1;
             (key, val, edge)
         }
     }
@@ -742,12 +749,12 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> {
         let old_len = self.len();
 
         unsafe {
-            let key = slice_remove(self.reborrow_mut().into_key_area_slice(), 0);
-            let val = slice_remove(self.reborrow_mut().into_val_area_slice(), 0);
+            let key = slice_remove(self.key_area_slice(), 0);
+            let val = slice_remove(self.val_area_slice(), 0);
             let edge = match self.reborrow_mut().force() {
                 ForceResult::Leaf(_) => None,
                 ForceResult::Internal(mut internal) => {
-                    let node = slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
+                    let node = slice_remove(internal.edge_area_slice(), 0);
                     let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
                     // Currently, clearing the parent link is superfluous, because we will
                     // insert the node elsewhere and set its parent link again.
@@ -759,14 +766,14 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> {
                 }
             };
 
-            *self.reborrow_mut().into_len_mut() -= 1;
+            *self.len_mut() -= 1;
 
             (key, val, edge)
         }
     }
 
     fn into_kv_pointers_mut(mut self) -> (*mut K, *mut V) {
-        let leaf = Self::as_leaf_mut(&mut self);
+        let leaf = self.as_leaf_mut();
         let keys = MaybeUninit::slice_as_mut_ptr(&mut leaf.keys);
         let vals = MaybeUninit::slice_as_mut_ptr(&mut leaf.vals);
         (keys, vals)
@@ -970,11 +977,11 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark
         debug_assert!(self.node.len() < CAPACITY);
 
         unsafe {
-            *self.node.reborrow_mut().into_len_mut() += 1;
-            slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
-            slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
+            *self.node.len_mut() += 1;
+            slice_insert(self.node.key_area_slice(), self.idx, key);
+            slice_insert(self.node.val_area_slice(), self.idx, val);
 
-            self.node.reborrow_mut().into_val_area_mut_at(self.idx).assume_init_mut()
+            self.node.val_area_mut_at(self.idx).assume_init_mut()
         }
     }
 }
@@ -1028,10 +1035,10 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>,
         debug_assert!(edge.height == self.node.height - 1);
 
         unsafe {
-            *self.node.reborrow_mut().into_len_mut() += 1;
-            slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
-            slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
-            slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, edge.node);
+            *self.node.len_mut() += 1;
+            slice_insert(self.node.key_area_slice(), self.idx, key);
+            slice_insert(self.node.val_area_slice(), self.idx, val);
+            slice_insert(self.node.edge_area_slice(), self.idx + 1, edge.node);
 
             self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len());
         }
@@ -1134,12 +1141,13 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeTyp
 }
 
 impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> {
-    pub fn into_key_mut(self) -> &'a mut K {
-        unsafe { self.node.into_key_area_mut_at(self.idx).assume_init_mut() }
+    pub fn key_mut(&mut self) -> &mut K {
+        unsafe { self.node.key_area_mut_at(self.idx).assume_init_mut() }
     }
 
     pub fn into_val_mut(self) -> &'a mut V {
-        unsafe { self.node.into_val_area_mut_at(self.idx).assume_init_mut() }
+        let leaf = self.node.into_leaf_mut();
+        unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
     }
 }
 
@@ -1154,7 +1162,7 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>
         // We cannot call separate key and value methods, because calling the second one
         // invalidates the reference returned by the first.
         unsafe {
-            let leaf = NodeRef::as_leaf_mut(&mut self.node.reborrow_mut());
+            let leaf = self.node.as_leaf_mut();
             let key = leaf.keys.get_unchecked_mut(self.idx).assume_init_mut();
             let val = leaf.vals.get_unchecked_mut(self.idx).assume_init_mut();
             (key, val)
@@ -1196,7 +1204,7 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>
                 new_len,
             );
 
-            *self.node.reborrow_mut().into_len_mut() = self.idx as u16;
+            *self.node.len_mut() = self.idx as u16;
             (k, v)
         }
     }
@@ -1227,9 +1235,9 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark
         mut self,
     ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) {
         unsafe {
-            let k = slice_remove(self.node.reborrow_mut().into_key_area_slice(), self.idx);
-            let v = slice_remove(self.node.reborrow_mut().into_val_area_slice(), self.idx);
-            *self.node.reborrow_mut().into_len_mut() -= 1;
+            let k = slice_remove(self.node.key_area_slice(), self.idx);
+            let v = slice_remove(self.node.val_area_slice(), self.idx);
+            *self.node.len_mut() -= 1;
             ((k, v), self.left_edge())
         }
     }
@@ -1374,29 +1382,27 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
         });
 
         unsafe {
-            *left_node.reborrow_mut().into_len_mut() = new_left_len as u16;
+            *left_node.len_mut() = new_left_len as u16;
 
-            let parent_key =
-                slice_remove(parent_node.reborrow_mut().into_key_area_slice(), parent_idx);
-            left_node.reborrow_mut().into_key_area_mut_at(old_left_len).write(parent_key);
+            let parent_key = slice_remove(parent_node.key_area_slice(), parent_idx);
+            left_node.key_area_mut_at(old_left_len).write(parent_key);
             ptr::copy_nonoverlapping(
                 right_node.reborrow().key_area().as_ptr(),
-                left_node.reborrow_mut().into_key_area_slice().as_mut_ptr().add(old_left_len + 1),
+                left_node.key_area_slice().as_mut_ptr().add(old_left_len + 1),
                 right_len,
             );
 
-            let parent_val =
-                slice_remove(parent_node.reborrow_mut().into_val_area_slice(), parent_idx);
-            left_node.reborrow_mut().into_val_area_mut_at(old_left_len).write(parent_val);
+            let parent_val = slice_remove(parent_node.val_area_slice(), parent_idx);
+            left_node.val_area_mut_at(old_left_len).write(parent_val);
             ptr::copy_nonoverlapping(
                 right_node.reborrow().val_area().as_ptr(),
-                left_node.reborrow_mut().into_val_area_slice().as_mut_ptr().add(old_left_len + 1),
+                left_node.val_area_slice().as_mut_ptr().add(old_left_len + 1),
                 right_len,
             );
 
-            slice_remove(&mut parent_node.reborrow_mut().into_edge_area_slice(), parent_idx + 1);
+            slice_remove(&mut parent_node.edge_area_slice(), parent_idx + 1);
             parent_node.correct_childrens_parent_links(parent_idx + 1..old_parent_len);
-            *parent_node.reborrow_mut().into_len_mut() -= 1;
+            *parent_node.len_mut() -= 1;
 
             if parent_node.height > 1 {
                 // SAFETY: the height of the nodes being merged is one below the height
@@ -1405,11 +1411,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
                 let right_node = right_node.cast_to_internal_unchecked();
                 ptr::copy_nonoverlapping(
                     right_node.reborrow().edge_area().as_ptr(),
-                    left_node
-                        .reborrow_mut()
-                        .into_edge_area_slice()
-                        .as_mut_ptr()
-                        .add(old_left_len + 1),
+                    left_node.edge_area_slice().as_mut_ptr().add(old_left_len + 1),
                     right_len + 1,
                 );
 
@@ -1511,14 +1513,14 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
                 move_kv(left_kv, new_left_len, parent_kv, 0, 1);
             }
 
-            *left_node.reborrow_mut().into_len_mut() -= count as u16;
-            *right_node.reborrow_mut().into_len_mut() += count as u16;
+            *left_node.len_mut() -= count as u16;
+            *right_node.len_mut() += count as u16;
 
             match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) {
                 (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
                     // Make room for stolen edges.
                     let left = left.reborrow();
-                    let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr();
+                    let right_edges = right.edge_area_slice().as_mut_ptr();
                     ptr::copy(right_edges, right_edges.add(count), old_right_len + 1);
                     right.correct_childrens_parent_links(count..count + old_right_len + 1);
 
@@ -1569,8 +1571,8 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
                 ptr::copy(right_kv.1.add(count), right_kv.1, new_right_len);
             }
 
-            *left_node.reborrow_mut().into_len_mut() += count as u16;
-            *right_node.reborrow_mut().into_len_mut() -= count as u16;
+            *left_node.len_mut() += count as u16;
+            *right_node.len_mut() -= count as u16;
 
             match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) {
                 (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
@@ -1578,7 +1580,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
                     move_edges(right.reborrow(), 0, left, old_left_len + 1, count);
 
                     // Fill gap where stolen edges used to be.
-                    let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr();
+                    let right_edges = right.edge_area_slice().as_mut_ptr();
                     ptr::copy(right_edges.add(count), right_edges, new_right_len + 1);
                     right.correct_childrens_parent_links(0..=new_right_len);
                 }
@@ -1612,7 +1614,7 @@ unsafe fn move_edges<'a, K: 'a, V: 'a>(
 ) {
     unsafe {
         let source_ptr = source.edge_area().as_ptr();
-        let dest_ptr = dest.reborrow_mut().into_edge_area_slice().as_mut_ptr();
+        let dest_ptr = dest.edge_area_slice().as_mut_ptr();
         ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count);
         dest.correct_childrens_parent_links(dest_offset..dest_offset + count);
     }
@@ -1708,8 +1710,8 @@ impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, ma
 
                 move_kv(left_kv, new_left_len, right_kv, 0, new_right_len);
 
-                *left_node.reborrow_mut().into_len_mut() = new_left_len as u16;
-                *right_node.reborrow_mut().into_len_mut() = new_right_len as u16;
+                *left_node.len_mut() = new_left_len as u16;
+                *right_node.len_mut() = new_right_len as u16;
 
                 match (left_node.force(), right_node.force()) {
                     (ForceResult::Internal(left), ForceResult::Internal(right)) => {

From 419d3ae02849d47899f8fc221d37b05ac24f4efd Mon Sep 17 00:00:00 2001
From: Aaron Hill 
Date: Tue, 20 Oct 2020 16:31:54 -0400
Subject: [PATCH 378/719] Prefer regions with an `external_name` in
 `approx_universal_upper_bound`

Fixes #75785

When displaying a MIR borrowcheck error, we may need to find an upper
bound for a region, which gives us a region to point to in the error
message. However, a region might outlive multiple distinct universal
regions, in which case the only upper bound is 'static

To try to display a meaningful error message, we compute an
'approximate' upper bound by picking one of the universal regions.
Currently, we pick the region with the lowest index - however, this
caused us to produce a suboptimal error message in issue #75785

This PR `approx_universal_upper_bound` to prefer regions with an
`external_name`. This causes us to prefer regions from function
arguments/upvars, which seems to lead to a nicer error message in some
cases.
---
 .../src/borrow_check/region_infer/mod.rs       | 18 +++++++++++++++++-
 ...ssue-74072-lifetime-name-annotations.stderr |  2 +-
 .../issue-75785-confusing-named-region.rs      | 13 +++++++++++++
 .../issue-75785-confusing-named-region.stderr  | 15 +++++++++++++++
 4 files changed, 46 insertions(+), 2 deletions(-)
 create mode 100644 src/test/ui/async-await/issue-75785-confusing-named-region.rs
 create mode 100644 src/test/ui/async-await/issue-75785-confusing-named-region.stderr

diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index 3586be2804d6..9d45f6fd0d34 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -1145,8 +1145,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
             let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
             debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub);
+            // The upper bound of two non-static regions is static: this
+            // means we know nothing about the relationship between these
+            // two regions. Pick a 'better' one to use when constructing
+            // a diagnostic
             if ur != static_r && lub != static_r && new_lub == static_r {
-                lub = std::cmp::min(ur, lub);
+                // Prefer the region with an `external_name` - this
+                // indicates that the region is early-bound, so working with
+                // it can produce a nicer error.
+                if self.region_definition(ur).external_name.is_some() {
+                    lub = ur;
+                } else if self.region_definition(lub).external_name.is_some() {
+                    // Leave lub unchanged
+                } else {
+                    // If we get here, we don't have any reason to prefer
+                    // one region over the other. Just pick the
+                    // one with the lower index for now.
+                    lub = std::cmp::min(ur, lub);
+                }
             } else {
                 lub = new_lub;
             }
diff --git a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr
index 123c3192cffb..b96cab9f0f51 100644
--- a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr
+++ b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr
@@ -2,7 +2,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed
   --> $DIR/issue-74072-lifetime-name-annotations.rs:9:5
    |
 LL | pub async fn async_fn(x: &mut i32) -> &i32 {
-   |                                       - let's call the lifetime of this reference `'1`
+   |                          - let's call the lifetime of this reference `'1`
 LL |     let y = &*x;
    |             --- borrow of `*x` occurs here
 LL |     *x += 1;
diff --git a/src/test/ui/async-await/issue-75785-confusing-named-region.rs b/src/test/ui/async-await/issue-75785-confusing-named-region.rs
new file mode 100644
index 000000000000..452614087be9
--- /dev/null
+++ b/src/test/ui/async-await/issue-75785-confusing-named-region.rs
@@ -0,0 +1,13 @@
+// edition:2018
+//
+// Regression test for issue #75785
+// Tests that we don't point to a confusing named
+// region when emitting a diagnostic
+
+pub async fn async_fn(x: &mut i32) -> (&i32, &i32) {
+    let y = &*x;
+    *x += 1; //~ ERROR cannot assign to
+    (&32, y)
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-75785-confusing-named-region.stderr b/src/test/ui/async-await/issue-75785-confusing-named-region.stderr
new file mode 100644
index 000000000000..3b731d9c60a6
--- /dev/null
+++ b/src/test/ui/async-await/issue-75785-confusing-named-region.stderr
@@ -0,0 +1,15 @@
+error[E0506]: cannot assign to `*x` because it is borrowed
+  --> $DIR/issue-75785-confusing-named-region.rs:9:5
+   |
+LL | pub async fn async_fn(x: &mut i32) -> (&i32, &i32) {
+   |                          - let's call the lifetime of this reference `'1`
+LL |     let y = &*x;
+   |             --- borrow of `*x` occurs here
+LL |     *x += 1;
+   |     ^^^^^^^ assignment to borrowed `*x` occurs here
+LL |     (&32, y)
+   |     -------- returning this value requires that `*x` is borrowed for `'1`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.

From 613cc9bb45a35949ca0df5ba5139b986e31ca673 Mon Sep 17 00:00:00 2001
From: pierwill 
Date: Thu, 17 Dec 2020 11:39:39 -0800
Subject: [PATCH 379/719] Edit rustc_ast::ast::FieldPat docs

Punctuation fixes.
---
 compiler/rustc_ast/src/ast.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 220bbed7e78b..20f98d390960 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -636,16 +636,16 @@ impl Pat {
     }
 }
 
-/// A single field in a struct pattern
+/// A single field in a struct pattern.
 ///
-/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
-/// are treated the same as` x: x, y: ref y, z: ref mut z`,
-/// except is_shorthand is true
+/// Patterns like the fields of `Foo { x, ref y, ref mut z }`
+/// are treated the same as `x: x, y: ref y, z: ref mut z`,
+/// except when `is_shorthand` is true.
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct FieldPat {
-    /// The identifier for the field
+    /// The identifier for the field.
     pub ident: Ident,
-    /// The pattern the field is destructured to
+    /// The pattern the field is destructured to.
     pub pat: P,
     pub is_shorthand: bool,
     pub attrs: AttrVec,

From 30c9307bfc9e57d9901cbd0efe792f321ad2b48b Mon Sep 17 00:00:00 2001
From: pierwill <19642016+pierwill@users.noreply.github.com>
Date: Thu, 17 Dec 2020 11:55:49 -0800
Subject: [PATCH 380/719] docs: Edit rustc_ast::token::Token

Add missing punctuation.
---
 compiler/rustc_ast/src/token.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index f583825fbb3c..a74464937c8b 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -434,7 +434,7 @@ impl Token {
             || self == &OpenDelim(Paren)
     }
 
-    /// Returns `true` if the token is any literal
+    /// Returns `true` if the token is any literal.
     pub fn is_lit(&self) -> bool {
         match self.kind {
             Literal(..) => true,

From 54cce72da5b0505e1c617d4359bfe45c3235908a Mon Sep 17 00:00:00 2001
From: pierwill <19642016+pierwill@users.noreply.github.com>
Date: Thu, 17 Dec 2020 12:02:34 -0800
Subject: [PATCH 381/719] docs: Edit rustc_span::symbol::Symbol method

Edit wording of the doc comment for rustc_span::symbol::Symbol::can_be_raw
to match related methods.
---
 compiler/rustc_span/src/symbol.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index f61a32a0f790..9e08e540caa6 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1632,7 +1632,7 @@ impl Symbol {
         self == kw::True || self == kw::False
     }
 
-    /// This symbol can be a raw identifier.
+    /// Returns `true` if this symbol can be a raw identifier.
     pub fn can_be_raw(self) -> bool {
         self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword()
     }

From 3e31ffda973d2fe8e314378a98d0b4633fce9485 Mon Sep 17 00:00:00 2001
From: Matthew Jasper 
Date: Thu, 17 Dec 2020 20:16:10 +0000
Subject: [PATCH 382/719] Revert change to evaluation order

This change breaks some code and doesn't appear to enable any new code.
---
 .../src/traits/select/confirmation.rs         |  6 +--
 src/test/ui/traits/impl-evaluation-order.rs   | 39 +++++++++++++++++++
 2 files changed, 42 insertions(+), 3 deletions(-)
 create mode 100644 src/test/ui/traits/impl-evaluation-order.rs

diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index ed22d5849e2b..c40d781e17c8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -336,7 +336,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn vtable_impl(
         &mut self,
         impl_def_id: DefId,
-        mut substs: Normalized<'tcx, SubstsRef<'tcx>>,
+        substs: Normalized<'tcx, SubstsRef<'tcx>>,
         cause: ObligationCause<'tcx>,
         recursion_depth: usize,
         param_env: ty::ParamEnv<'tcx>,
@@ -358,9 +358,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // relying on projections in the impl-trait-ref.
         //
         // e.g., `impl> Foo<::T> for V`
-        substs.obligations.append(&mut impl_obligations);
+        impl_obligations.extend(substs.obligations);
 
-        ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: substs.obligations }
+        ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations }
     }
 
     fn confirm_object_candidate(
diff --git a/src/test/ui/traits/impl-evaluation-order.rs b/src/test/ui/traits/impl-evaluation-order.rs
new file mode 100644
index 000000000000..57809d89aa64
--- /dev/null
+++ b/src/test/ui/traits/impl-evaluation-order.rs
@@ -0,0 +1,39 @@
+// Regression test for #79902
+
+// Check that evaluation (which is used to determine whether to copy a type in
+// MIR building) evaluates bounds from normalizing an impl after evaluating
+// any bounds on the impl.
+
+// check-pass
+
+trait A {
+    type B;
+}
+trait M {}
+
+struct G(*const T, *const U);
+
+impl Clone for G {
+    fn clone(&self) -> Self {
+        G { ..*self }
+    }
+}
+
+impl Copy for G
+where
+    T: A,
+    U: A,
+{
+}
+
+impl A for () {
+    type B = ();
+}
+
+fn is_m(_: T) {}
+
+fn main() {
+    let x = G(&(), &());
+    drop(x);
+    drop(x);
+}

From dea13632a8e8f90febe3de17c740498285397936 Mon Sep 17 00:00:00 2001
From: Aaron Hill 
Date: Thu, 17 Dec 2020 15:25:55 -0500
Subject: [PATCH 383/719] Suppress `CONST_ITEM_MUTATION` lint if a dereference
 occurs anywhere

Fixes #79971
---
 .../src/transform/check_const_item_mutation.rs   |  8 +++++---
 src/test/ui/lint/lint-const-item-mutation.rs     |  8 ++++++++
 src/test/ui/lint/lint-const-item-mutation.stderr | 16 ++++++++--------
 3 files changed, 21 insertions(+), 11 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 a84570432786..e2d50ba034ad 100644
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
@@ -66,12 +66,14 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
         location: Location,
         decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>,
     ) {
-        // Don't lint on borrowing/assigning to a dereference
-        // e.g:
+        // Don't lint on borrowing/assigning when a dereference is involved.
+        // If we 'leave' the temporary via a dereference, we must
+        // be modifying something else
         //
         // `unsafe { *FOO = 0; *BAR.field = 1; }`
         // `unsafe { &mut *FOO }`
-        if !matches!(place.projection.last(), Some(PlaceElem::Deref)) {
+        // `unsafe { (*ARRAY)[0] = val; }
+        if !place.projection.iter().any(|p| matches!(p, PlaceElem::Deref)) {
             let source_info = self.body.source_info(location);
             let lint_root = self.body.source_scopes[source_info.scope]
                 .local_data
diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs
index ef55f31593b6..4bf5e0a9e212 100644
--- a/src/test/ui/lint/lint-const-item-mutation.rs
+++ b/src/test/ui/lint/lint-const-item-mutation.rs
@@ -30,6 +30,8 @@ const MUTABLE: Mutable = Mutable { msg: "" };
 const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
 const VEC: Vec = Vec::new();
 const PTR: *mut () = 1 as *mut _;
+const PTR_TO_ARRAY: *mut [u32; 4] = 0x12345678 as _;
+const ARRAY_OF_PTR: [*mut u32; 1] = [1 as *mut _];
 
 fn main() {
     ARRAY[0] = 5; //~ WARN attempting to modify
@@ -55,4 +57,10 @@ fn main() {
     // Test that we don't warn when converting a raw pointer
     // into a mutable reference
     unsafe { &mut *PTR };
+
+    // Test that we don't warn when there's a dereference involved.
+    // If we ever 'leave' the const via a deference, we're going
+    // to end up modifying something other than the temporary
+    unsafe { (*PTR_TO_ARRAY)[0] = 1 };
+    unsafe { *ARRAY_OF_PTR[0] = 25; }
 }
diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr
index ae95abc72f39..74505eeb987c 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:35:5
+  --> $DIR/lint-const-item-mutation.rs:37: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:36:5
+  --> $DIR/lint-const-item-mutation.rs:38: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:37:5
+  --> $DIR/lint-const-item-mutation.rs:39: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:38:5
+  --> $DIR/lint-const-item-mutation.rs:40: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:39:5
+  --> $DIR/lint-const-item-mutation.rs:41: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:40:5
+  --> $DIR/lint-const-item-mutation.rs:42: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:52:5
+  --> $DIR/lint-const-item-mutation.rs:54:5
    |
 LL |     MUTABLE2.msg = "wow";
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:53:5
+  --> $DIR/lint-const-item-mutation.rs:55:5
    |
 LL |     VEC.push(0);
    |     ^^^^^^^^^^^

From d6f1787447e1132d929efbb5b772be232e336c23 Mon Sep 17 00:00:00 2001
From: Camelid 
Date: Thu, 17 Dec 2020 13:51:20 -0800
Subject: [PATCH 384/719] Don't allow `const` to begin a nonterminal

Thanks to Vadim Petrochenkov who [told me what the fix was][z]!

[z]: https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/finding.20which.20macro.20rule.20to.20use/near/220240422
---
 .../rustc_parse/src/parser/nonterminal.rs     |  2 ++
 src/test/ui/inline-const/macro-with-const.rs  | 20 +++++++++++++++++++
 2 files changed, 22 insertions(+)
 create mode 100644 src/test/ui/inline-const/macro-with-const.rs

diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index c007f96a7980..76ad5acd5303 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -27,6 +27,8 @@ impl<'a> Parser<'a> {
                 token.can_begin_expr()
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Let)
+                // This exception is here for backwards compatibility.
+                && !token.is_keyword(kw::Const)
             }
             NonterminalKind::Ty => token.can_begin_type(),
             NonterminalKind::Ident => get_macro_ident(token).is_some(),
diff --git a/src/test/ui/inline-const/macro-with-const.rs b/src/test/ui/inline-const/macro-with-const.rs
new file mode 100644
index 000000000000..e7393166d8df
--- /dev/null
+++ b/src/test/ui/inline-const/macro-with-const.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+macro_rules! exp {
+    (const $n:expr) => {
+        $n
+    };
+}
+
+macro_rules! stmt {
+    (exp $e:expr) => {
+        $e
+    };
+    (exp $($t:tt)+) => {
+        exp!($($t)+)
+    };
+}
+
+fn main() {
+    stmt!(exp const 1);
+}

From b11b705e52c534300565fa9a44fa4630a896ae5b Mon Sep 17 00:00:00 2001
From: Nixon Enraght-Moony 
Date: Thu, 17 Dec 2020 22:06:00 +0000
Subject: [PATCH 385/719] Add test for issue #74824

---
 .../generic-associated-types/issue-74824.rs   | 27 +++++++++++++++++++
 .../issue-74824.stderr                        | 27 +++++++++++++++++++
 2 files changed, 54 insertions(+)
 create mode 100644 src/test/ui/generic-associated-types/issue-74824.rs
 create mode 100644 src/test/ui/generic-associated-types/issue-74824.stderr

diff --git a/src/test/ui/generic-associated-types/issue-74824.rs b/src/test/ui/generic-associated-types/issue-74824.rs
new file mode 100644
index 000000000000..00761a97d00c
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-74824.rs
@@ -0,0 +1,27 @@
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+#![allow(incomplete_features)]
+
+use std::ops::Deref;
+
+trait UnsafeCopy {
+    type Copy: Copy = Box;
+    //~^ ERROR the trait bound `Box: Copy` is not satisfied
+    //~^^ ERROR the trait bound `T: Clone` is not satisfied
+    fn copy(x: &Self::Copy) -> Self::Copy {
+        *x
+    }
+}
+
+impl UnsafeCopy for T {}
+
+fn main() {
+    let b = Box::new(42usize);
+    let copy = <()>::copy(&b);
+
+    let raw_b = Box::deref(&b) as *const _;
+    let raw_copy = Box::deref(©) as *const _;
+
+    // assert the addresses.
+    assert_eq!(raw_b, raw_copy);
+}
diff --git a/src/test/ui/generic-associated-types/issue-74824.stderr b/src/test/ui/generic-associated-types/issue-74824.stderr
new file mode 100644
index 000000000000..34a2c1932ebc
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-74824.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `Box: Copy` is not satisfied
+  --> $DIR/issue-74824.rs:8:5
+   |
+LL |     type Copy: Copy = Box;
+   |     ^^^^^^^^^^^^^^----^^^^^^^^^^
+   |     |             |
+   |     |             required by this bound in `UnsafeCopy::Copy`
+   |     the trait `Copy` is not implemented for `Box`
+
+error[E0277]: the trait bound `T: Clone` is not satisfied
+  --> $DIR/issue-74824.rs:8:5
+   |
+LL |     type Copy: Copy = Box;
+   |     ^^^^^^^^^^^^^^----^^^^^^^^^^
+   |     |             |
+   |     |             required by this bound in `UnsafeCopy::Copy`
+   |     the trait `Clone` is not implemented for `T`
+   |
+   = note: required because of the requirements on the impl of `Clone` for `Box`
+help: consider restricting type parameter `T`
+   |
+LL |     type Copy: Copy = Box;
+   |                ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.

From 2b2462e8b0a6b83191a8035d9209f7aa87a2feb0 Mon Sep 17 00:00:00 2001
From: Arlie Davis 
Date: Mon, 14 Dec 2020 11:34:55 -0800
Subject: [PATCH 386/719] Stop using intermediate macros in definition of
 symbols

Currently, the rustc_macros::symbols macro generates two
`macro_rules!` macros as its output. These two macros are
used in rustc_span/src/symbol.rs.

This means that each Symbol that we define is represented
in the AST of rustc_symbols twice: once in the definition
of the `define_symbols!` macro (similarly for the
`keywords! macro), and once in the rustc_span::symbols
definition.

That would be OK if there were only a handful of symbols,
but currently we define over 1100 symbols. The definition
of the `define_symbols!` macro contains the expanded definition
of each symbol, so that's a lot of AST storage wasted on a
macro that is used exactly once.

This commit removes the `define_symbols` macro, and simply
allows the proc macro to directly generate the
`rustc_symbols::symbol::sym` module.

The benefit is mainly in reducing memory wasted during
compilation of rustc itself. It should also reduce memory used
by Rust Analyzer.

This commit also reduces the size of the AST for symbol
definitions, by moving two `#[allow(...)]` attributes from
the symbol constants to the `sym` module. This eliminates 2200+
attribute nodes.

This commit also eliminates the need for the `digits_array`
constant. There's no need to store an array of Symbol values
for digits. We can simply define a constant of the base value,
and add to that base value.
---
 compiler/rustc_macros/src/symbols.rs | 37 ++++++++++++----------------
 compiler/rustc_span/src/symbol.rs    | 16 ++++++------
 2 files changed, 24 insertions(+), 29 deletions(-)

diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs
index f449900d5c24..5b932864dff5 100644
--- a/compiler/rustc_macros/src/symbols.rs
+++ b/compiler/rustc_macros/src/symbols.rs
@@ -126,7 +126,6 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) {
 
     let mut keyword_stream = quote! {};
     let mut symbols_stream = quote! {};
-    let mut digits_stream = quote! {};
     let mut prefill_stream = quote! {};
     let mut counter = 0u32;
     let mut keys =
@@ -162,7 +161,6 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) {
             #value,
         });
         keyword_stream.extend(quote! {
-            #[allow(non_upper_case_globals)]
             pub const #name: Symbol = Symbol::new(#counter);
         });
         counter += 1;
@@ -182,42 +180,39 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) {
             #value,
         });
         symbols_stream.extend(quote! {
-            #[allow(rustc::default_hash_types)]
-            #[allow(non_upper_case_globals)]
             pub const #name: Symbol = Symbol::new(#counter);
         });
         counter += 1;
     }
 
     // Generate symbols for the strings "0", "1", ..., "9".
+    let digits_base = counter;
+    counter += 10;
     for n in 0..10 {
         let n = n.to_string();
         check_dup(Span::call_site(), &n, &mut errors);
         prefill_stream.extend(quote! {
             #n,
         });
-        digits_stream.extend(quote! {
-            Symbol::new(#counter),
-        });
-        counter += 1;
     }
+    let _ = counter; // for future use
 
     let output = quote! {
-        macro_rules! keywords {
-            () => {
-                #keyword_stream
-            }
+        const SYMBOL_DIGITS_BASE: u32 = #digits_base;
+
+        #[doc(hidden)]
+        #[allow(non_upper_case_globals)]
+        mod kw_generated {
+            use super::Symbol;
+            #keyword_stream
         }
 
-        macro_rules! define_symbols {
-            () => {
-                #symbols_stream
-
-                #[allow(non_upper_case_globals)]
-                pub const digits_array: &[Symbol; 10] = &[
-                    #digits_stream
-                ];
-            }
+        #[allow(rustc::default_hash_types)]
+        #[allow(non_upper_case_globals)]
+        #[doc(hidden)]
+        pub mod sym_generated {
+            use super::Symbol;
+            #symbols_stream
         }
 
         impl Interner {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index f61a32a0f790..cceede42cacb 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1577,8 +1577,7 @@ impl Interner {
 /// Given that `kw` is imported, use them like `kw::keyword_name`.
 /// For example `kw::Loop` or `kw::Break`.
 pub mod kw {
-    use super::Symbol;
-    keywords!();
+    pub use super::kw_generated::*;
 }
 
 // This module has a very short name because it's used a lot.
@@ -1586,22 +1585,23 @@ pub mod kw {
 ///
 /// Given that `sym` is imported, use them like `sym::symbol_name`.
 /// For example `sym::rustfmt` or `sym::u8`.
-#[allow(rustc::default_hash_types)]
 pub mod sym {
     use super::Symbol;
     use std::convert::TryInto;
 
-    define_symbols!();
+    pub use super::sym_generated::*;
 
     // Used from a macro in `librustc_feature/accepted.rs`
     pub use super::kw::MacroRules as macro_rules;
 
-    // Get the symbol for an integer. The first few non-negative integers each
-    // have a static symbol and therefore are fast.
+    /// Get the symbol for an integer.
+    ///
+    /// The first few non-negative integers each have a static symbol and therefore
+    /// are fast.
     pub fn integer + Copy + ToString>(n: N) -> Symbol {
         if let Result::Ok(idx) = n.try_into() {
-            if let Option::Some(&sym_) = digits_array.get(idx) {
-                return sym_;
+            if idx < 10 {
+                return Symbol::new(super::SYMBOL_DIGITS_BASE + idx as u32);
             }
         }
         Symbol::intern(&n.to_string())

From 1eb7608a2e7284eff2d0ba80705f1cf28a1117e5 Mon Sep 17 00:00:00 2001
From: Andrew Houts 
Date: Thu, 17 Dec 2020 21:09:55 -0600
Subject: [PATCH 387/719] make needless_update ignore non_exhaustive structs

---
 clippy_lints/src/needless_update.rs | 21 +++++++++++++++++++--
 tests/ui/needless_update.rs         | 11 +++++++++++
 tests/ui/needless_update.stderr     |  2 +-
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs
index 98e9078094a2..1e387b518c3a 100644
--- a/clippy_lints/src/needless_update.rs
+++ b/clippy_lints/src/needless_update.rs
@@ -21,7 +21,14 @@ declare_clippy_lint! {
     /// #     z: i32,
     /// # }
     /// # let zero_point = Point { x: 0, y: 0, z: 0 };
-    ///
+    /// #
+    /// # #[non_exhaustive]
+    /// # struct Options {
+    /// #     a: bool,
+    /// #     b: i32,
+    /// # }
+    /// # let default_options = Options { a: false, b: 0 };
+    /// #
     /// // Bad
     /// Point {
     ///     x: 1,
@@ -36,6 +43,14 @@ declare_clippy_lint! {
     ///     y: 1,
     ///     ..zero_point
     /// };
+    ///
+    /// // this lint is not applied to structs marked with [non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html)
+    /// // Ok
+    /// Options {
+    ///     a: true,
+    ///     b: 321,
+    ///     ..default_options
+    ///  };
     /// ```
     pub NEEDLESS_UPDATE,
     complexity,
@@ -49,7 +64,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate {
         if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.kind {
             let ty = cx.typeck_results().expr_ty(expr);
             if let ty::Adt(def, _) = ty.kind() {
-                if fields.len() == def.non_enum_variant().fields.len() {
+                if fields.len() == def.non_enum_variant().fields.len()
+                    && !def.variants[0_usize.into()].is_field_list_non_exhaustive()
+                {
                     span_lint(
                         cx,
                         NEEDLESS_UPDATE,
diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs
index bfa005a19f91..b93ff048a62f 100644
--- a/tests/ui/needless_update.rs
+++ b/tests/ui/needless_update.rs
@@ -6,9 +6,20 @@ struct S {
     pub b: i32,
 }
 
+#[non_exhaustive]
+struct T {
+    pub x: i32,
+    pub y: i32,
+}
+
 fn main() {
     let base = S { a: 0, b: 0 };
     S { ..base }; // no error
     S { a: 1, ..base }; // no error
     S { a: 1, b: 1, ..base };
+
+    let base = T { x: 0, y: 0 };
+    T { ..base }; // no error
+    T { x: 1, ..base }; // no error
+    T { x: 1, y: 1, ..base }; // no error
 }
diff --git a/tests/ui/needless_update.stderr b/tests/ui/needless_update.stderr
index 133c834880dd..b154b3b306dd 100644
--- a/tests/ui/needless_update.stderr
+++ b/tests/ui/needless_update.stderr
@@ -1,5 +1,5 @@
 error: struct update has no effect, all the fields in the struct have already been specified
-  --> $DIR/needless_update.rs:13:23
+  --> $DIR/needless_update.rs:19:23
    |
 LL |     S { a: 1, b: 1, ..base };
    |                       ^^^^

From 605c97864183894339aae983518cf1e8a8fc0116 Mon Sep 17 00:00:00 2001
From: pierwill <19642016+pierwill@users.noreply.github.com>
Date: Thu, 17 Dec 2020 20:47:05 -0800
Subject: [PATCH 388/719] Fix typo in rustc_typeck docs

---
 compiler/rustc_typeck/src/check/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index d27a68ccf1bd..8177b363a5a5 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -270,7 +270,7 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option {
 
 /// If this `DefId` is a "primary tables entry", returns
 /// `Some((body_id, header, decl))` with information about
-/// it's body-id, fn-header and fn-decl (if any). Otherwise,
+/// its body-id, fn-header and fn-decl (if any). Otherwise,
 /// returns `None`.
 ///
 /// If this function returns `Some`, then `typeck_results(def_id)` will

From ea338f544395c44dba171ae9f01fe55cb0cc8200 Mon Sep 17 00:00:00 2001
From: pierwill 
Date: Thu, 17 Dec 2020 21:17:43 -0800
Subject: [PATCH 389/719] Edit formatting in Rust Prelude docs

Use consistent punctuation and capitalization in the list
of things re-exported in the prelude.

Also adds a (possibly missing) word.
---
 library/std/src/prelude/mod.rs | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs
index c7a7c779d3c5..a3776681d034 100644
--- a/library/std/src/prelude/mod.rs
+++ b/library/std/src/prelude/mod.rs
@@ -26,38 +26,37 @@
 //! # Prelude contents
 //!
 //! The current version of the prelude (version 1) lives in
-//! [`std::prelude::v1`], and re-exports the following.
+//! [`std::prelude::v1`], and re-exports the following:
 //!
-//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]}. The
-//!   marker traits indicate fundamental properties of types.
-//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various
+//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]},
+//!   marker traits that indicate fundamental properties of types.
+//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}, various
 //!   operations for both destructors and overloading `()`.
 //! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly
 //!   dropping a value.
 //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
-//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines
+//! * [`std::borrow`]::[`ToOwned`], the conversion trait that defines
 //!   [`to_owned`], the generic method for creating an owned type from a
 //!   borrowed type.
 //! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines
 //!   [`clone`][`Clone::clone`], the method for producing a copy of a value.
-//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The
+//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }, the
 //!   comparison traits, which implement the comparison operators and are often
 //!   seen in trait bounds.
-//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}. Generic
+//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}, generic
 //!   conversions, used by savvy API authors to create overloaded methods.
 //! * [`std::default`]::[`Default`], types that have default values.
-//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`],
-//!   [`DoubleEndedIterator`], [`ExactSizeIterator`]}. Iterators of various
+//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`]
+//!   [`DoubleEndedIterator`], [`ExactSizeIterator`]}, iterators of various
 //!   kinds.
-//! * [`std::option`]::[`Option`]::{[`self`][`Option`], [`Some`], [`None`]}. A
+//! * [`std::option`]::[`Option`]::{[`self`][`Option`], [`Some`], [`None`]}, a
 //!   type which expresses the presence or absence of a value. This type is so
 //!   commonly used, its variants are also exported.
-//! * [`std::result`]::[`Result`]::{[`self`][`Result`], [`Ok`], [`Err`]}. A type
+//! * [`std::result`]::[`Result`]::{[`self`][`Result`], [`Ok`], [`Err`]}, a type
 //!   for functions that may succeed or fail. Like [`Option`], its variants are
 //!   exported as well.
 //! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
-//! * [`std::vec`]::[`Vec`], a growable, heap-allocated
-//!   vector.
+//! * [`std::vec`]::[`Vec`], a growable, heap-allocated vector.
 //!
 //! [`mem::drop`]: crate::mem::drop
 //! [`std::borrow`]: crate::borrow

From 920c9a4aaefbc4bade7032e32ec099bff1c7b58a Mon Sep 17 00:00:00 2001
From: Suyash458 
Date: Fri, 18 Dec 2020 10:55:09 +0530
Subject: [PATCH 390/719] add more lints to msrv docs

---
 clippy_lints/src/utils/conf.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 6403ff6dad18..32d7840a451c 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -106,7 +106,7 @@ macro_rules! define_Conf {
 
 pub use self::helpers::Conf;
 define_Conf! {
-    /// Lint: MANUAL_NON_EXHAUSTIVE, MANUAL_STRIP, OPTION_AS_REF_DEREF, MATCH_LIKE_MATCHES_MACRO. The minimum rust version that the project supports
+    /// Lint: REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN. The minimum rust version that the project supports
     (msrv, "msrv": Option, None),
     /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
     (blacklisted_names, "blacklisted_names": Vec, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),

From 9cb43bd9945e2c10a0641cf6c944b753fc02a38d Mon Sep 17 00:00:00 2001
From: pierwill <19642016+pierwill@users.noreply.github.com>
Date: Thu, 17 Dec 2020 21:49:32 -0800
Subject: [PATCH 391/719] Add missing punctuation to std::alloc docs

Add a period to first line of module docs to match other modules in std.
---
 library/std/src/alloc.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index 819d57a934dc..8491ff400335 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -1,4 +1,4 @@
-//! Memory allocation APIs
+//! Memory allocation APIs.
 //!
 //! In a given program, the standard library has one “global” memory allocator
 //! that is used for example by `Box` and `Vec`.

From 32f92aa34f87afa705c553d2455345a6107c3309 Mon Sep 17 00:00:00 2001
From: bjorn3 
Date: Fri, 18 Dec 2020 11:11:48 +0100
Subject: [PATCH 392/719] Rustup to rustc 1.50.0-nightly (eb4fc71dc 2020-12-17)

---
 rust-toolchain | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rust-toolchain b/rust-toolchain
index eeee23d6a8ba..fca771e13e14 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-nightly-2020-12-17
+nightly-2020-12-18

From 54ba238a6d4d1c2106848ffeb44b6932e95d27fa Mon Sep 17 00:00:00 2001
From: bjorn3 
Date: Fri, 18 Dec 2020 11:12:52 +0100
Subject: [PATCH 393/719] Remove implementation of intrinsics that are now
 lowered

See rust-lang/rust#80040
---
 src/intrinsics/mod.rs | 27 +--------------------------
 1 file changed, 1 insertion(+), 26 deletions(-)

diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs
index 2910af8c2b75..be5b247bb9f0 100644
--- a/src/intrinsics/mod.rs
+++ b/src/intrinsics/mod.rs
@@ -444,9 +444,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
                 "abort" => {
                     trap_abort(fx, "Called intrinsic::abort.");
                 }
-                "unreachable" => {
-                    trap_unreachable(fx, "[corruption] Called intrinsic::unreachable.");
-                }
                 "transmute" => {
                     crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
                 }
@@ -559,12 +556,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
                 fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
             }
         };
-        discriminant_value, (c ptr) {
-            let pointee_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
-            let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), pointee_layout);
-            let discr = crate::discriminant::codegen_get_discriminant(fx, val, ret.layout());
-            ret.write_cvalue(fx, discr);
-        };
         size_of_val,  (c ptr) {
             let layout = fx.layout_of(T);
             let size = if layout.is_unsized() {
@@ -625,22 +616,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             );
             ret.write_cvalue(fx, res);
         };
-        _ if intrinsic.starts_with("wrapping_"), (c x, c y) {
-            assert_eq!(x.layout().ty, y.layout().ty);
-            let bin_op = match intrinsic {
-                "wrapping_add" => BinOp::Add,
-                "wrapping_sub" => BinOp::Sub,
-                "wrapping_mul" => BinOp::Mul,
-                _ => unreachable!("intrinsic {}", intrinsic),
-            };
-            let res = crate::num::codegen_int_binop(
-                fx,
-                bin_op,
-                x,
-                y,
-            );
-            ret.write_cvalue(fx, res);
-        };
         _ if intrinsic.starts_with("saturating_"),  (c lhs, c rhs) {
             assert_eq!(lhs.layout().ty, rhs.layout().ty);
             let bin_op = match intrinsic {
@@ -900,7 +875,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             dest.write_cvalue(fx, val);
         };
 
-        size_of | pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
+        pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
             let const_val =
                 fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
             let val = crate::constant::codegen_const_value(

From 57266f1df6e9168f262b208f4a2ee62ebdaf9ad2 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Fri, 18 Dec 2020 12:05:51 +0100
Subject: [PATCH 394/719] Continue String to Symbol conversion in rustdoc

---
 src/librustdoc/clean/blanket_impl.rs | 2 +-
 src/librustdoc/clean/inline.rs       | 2 +-
 src/librustdoc/clean/mod.rs          | 4 ++--
 src/librustdoc/clean/types.rs        | 2 +-
 src/librustdoc/html/render/mod.rs    | 4 ++--
 src/librustdoc/json/conversions.rs   | 5 ++++-
 6 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 33b5e84c5e07..22496065afd7 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -103,7 +103,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                     .cx
                     .tcx
                     .provided_trait_methods(trait_def_id)
-                    .map(|meth| meth.ident.to_string())
+                    .map(|meth| meth.ident.name)
                     .collect();
 
                 impls.push(Item {
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 3cff5fa07b15..783be6c8243d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -427,7 +427,7 @@ crate fn build_impl(
 
     let provided = trait_
         .def_id()
-        .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect())
+        .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
         .unwrap_or_default();
 
     debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2809e85761d4..07255168d068 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2065,9 +2065,9 @@ fn clean_impl(impl_: &hir::Item<'_>, cx: &DocContext<'_>) -> Vec {
         build_deref_target_impls(cx, &items, &mut ret);
     }
 
-    let provided: FxHashSet = trait_
+    let provided: FxHashSet = trait_
         .def_id()
-        .map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect())
+        .map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
         .unwrap_or_default();
 
     let for_ = for_.clean(cx);
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 52d023c83cb6..cd6eccea5321 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1762,7 +1762,7 @@ crate enum ImplPolarity {
 crate struct Impl {
     crate unsafety: hir::Unsafety,
     crate generics: Generics,
-    crate provided_trait_methods: FxHashSet,
+    crate provided_trait_methods: FxHashSet,
     crate trait_: Option,
     crate for_: Type,
     crate items: Vec,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 62dac717968c..d55c8f389124 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2966,7 +2966,7 @@ fn render_assoc_item(
             AssocItemLink::GotoSource(did, provided_methods) => {
                 // We're creating a link from an impl-item to the corresponding
                 // trait-item and need to map the anchored type accordingly.
-                let ty = if provided_methods.contains(&*name.as_str()) {
+                let ty = if provided_methods.contains(&name) {
                     ItemType::Method
                 } else {
                     ItemType::TyMethod
@@ -3429,7 +3429,7 @@ fn render_union(
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
-    GotoSource(DefId, &'a FxHashSet),
+    GotoSource(DefId, &'a FxHashSet),
 }
 
 impl<'a> AssocItemLink<'a> {
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 9dc27e3411dd..020b77871742 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -440,7 +440,10 @@ impl From for Impl {
         Impl {
             is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
             generics: generics.into(),
-            provided_trait_methods: provided_trait_methods.into_iter().collect(),
+            provided_trait_methods: provided_trait_methods
+                .into_iter()
+                .map(|x| x.to_string())
+                .collect(),
             trait_: trait_.map(Into::into),
             for_: for_.into(),
             items: ids(items),

From 56530a2f25b621b4589c4f0c7aa147ec811a040e Mon Sep 17 00:00:00 2001
From: Hirochika Matsumoto 
Date: Fri, 18 Dec 2020 22:13:25 +0900
Subject: [PATCH 395/719] Fix typo

---
 compiler/rustc_lexer/src/unescape.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index 697d25fdb585..b4dd0fc2449e 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -201,7 +201,7 @@ fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result return Err(EscapeError::LeadingUnderscoreUnicodeEscape),

From 1523f67f16cb65da740d20b9853ce7f267579a7d Mon Sep 17 00:00:00 2001
From: Joshua Nelson 
Date: Wed, 16 Dec 2020 15:54:05 -0500
Subject: [PATCH 396/719] Calculate stability, const_stability, and deprecation
 on-demand

Previously, they would always be calculated ahead of time, which bloated
the size of `clean::Item`.
---
 src/librustdoc/clean/auto_trait.rs   |  3 -
 src/librustdoc/clean/blanket_impl.rs |  3 -
 src/librustdoc/clean/inline.rs       |  3 -
 src/librustdoc/clean/mod.rs          |  9 ---
 src/librustdoc/clean/types.rs        | 34 ++++++-----
 src/librustdoc/html/render/mod.rs    | 90 +++++++++++++++++-----------
 src/librustdoc/json/conversions.rs   | 13 +---
 7 files changed, 75 insertions(+), 80 deletions(-)

diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 40c59ed1e0b7..96d19e8e17de 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -123,9 +123,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                     attrs: Default::default(),
                     visibility: Inherited,
                     def_id: self.cx.next_def_id(param_env_def_id.krate),
-                    stability: None,
-                    const_stability: None,
-                    deprecation: None,
                     kind: ImplItem(Impl {
                         unsafety: hir::Unsafety::Normal,
                         generics: new_generics,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 33b5e84c5e07..0ecd71d008fc 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -112,9 +112,6 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                     attrs: Default::default(),
                     visibility: Inherited,
                     def_id: self.cx.next_def_id(impl_def_id.krate),
-                    stability: None,
-                    const_stability: None,
-                    deprecation: None,
                     kind: ImplItem(Impl {
                         unsafety: hir::Unsafety::Normal,
                         generics: (
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 3cff5fa07b15..fd30d62ea1fb 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -482,9 +482,6 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet)
                         source: clean::Span::dummy(),
                         def_id: DefId::local(CRATE_DEF_INDEX),
                         visibility: clean::Public,
-                        stability: None,
-                        const_stability: None,
-                        deprecation: None,
                         kind: clean::ImportItem(clean::Import::new_simple(
                             item.ident.name,
                             clean::ImportSource {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2809e85761d4..0d3bfd26f968 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2139,9 +2139,6 @@ fn clean_extern_crate(
         source: krate.span.clean(cx),
         def_id: crate_def_id,
         visibility: krate.vis.clean(cx),
-        stability: None,
-        const_stability: None,
-        deprecation: None,
         kind: ExternCrateItem(name, orig_name),
     }]
 }
@@ -2210,9 +2207,6 @@ impl Clean> for doctree::Import<'_> {
                         source: self.span.clean(cx),
                         def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
                         visibility: self.vis.clean(cx),
-                        stability: None,
-                        const_stability: None,
-                        deprecation: None,
                         kind: ImportItem(Import::new_simple(
                             self.name,
                             resolve_use_source(cx, path),
@@ -2231,9 +2225,6 @@ impl Clean> for doctree::Import<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: None,
-            const_stability: None,
-            deprecation: None,
             kind: ImportItem(inner),
         }]
     }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 52d023c83cb6..9cff129993d2 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -86,9 +86,6 @@ crate struct Item {
     crate visibility: Visibility,
     crate kind: ItemKind,
     crate def_id: DefId,
-    crate stability: Option,
-    crate deprecation: Option,
-    crate const_stability: Option,
 }
 
 impl fmt::Debug for Item {
@@ -102,13 +99,23 @@ impl fmt::Debug for Item {
             .field("kind", &self.kind)
             .field("visibility", &self.visibility)
             .field("def_id", def_id)
-            .field("stability", &self.stability)
-            .field("deprecation", &self.deprecation)
             .finish()
     }
 }
 
 impl Item {
+    crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability> {
+        if self.is_fake() { None } else { tcx.lookup_stability(self.def_id) }
+    }
+
+    crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
+        if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id) }
+    }
+
+    crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option {
+        if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id) }
+    }
+
     /// Finds the `doc` attribute as a NameValue and returns the corresponding
     /// value found.
     crate fn doc_value(&self) -> Option<&str> {
@@ -150,9 +157,6 @@ impl Item {
             source: source.clean(cx),
             attrs: cx.tcx.get_attrs(def_id).clean(cx),
             visibility: cx.tcx.visibility(def_id).clean(cx),
-            stability: cx.tcx.lookup_stability(def_id).cloned(),
-            deprecation: cx.tcx.lookup_deprecation(def_id),
-            const_stability: cx.tcx.lookup_const_stability(def_id).cloned(),
         }
     }
 
@@ -236,8 +240,8 @@ impl Item {
         }
     }
 
-    crate fn stability_class(&self) -> Option {
-        self.stability.as_ref().and_then(|ref s| {
+    crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option {
+        self.stability(tcx).as_ref().and_then(|ref s| {
             let mut classes = Vec::with_capacity(2);
 
             if s.level.is_unstable() {
@@ -245,7 +249,7 @@ impl Item {
             }
 
             // FIXME: what about non-staged API items that are deprecated?
-            if self.deprecation.is_some() {
+            if self.deprecation(tcx).is_some() {
                 classes.push("deprecated");
             }
 
@@ -253,15 +257,15 @@ impl Item {
         })
     }
 
-    crate fn stable_since(&self) -> Option {
-        match self.stability?.level {
+    crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option {
+        match self.stability(tcx)?.level {
             StabilityLevel::Stable { since, .. } => Some(since.as_str()),
             StabilityLevel::Unstable { .. } => None,
         }
     }
 
-    crate fn const_stable_since(&self) -> Option {
-        match self.const_stability?.level {
+    crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option {
+        match self.const_stability(tcx)?.level {
             StabilityLevel::Stable { since, .. } => Some(since.as_str()),
             StabilityLevel::Unstable { .. } => None,
         }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 67ccc3d4cf8d..75c32481286b 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -164,7 +164,7 @@ crate struct SharedContext<'tcx> {
     playground: Option,
 }
 
-impl Context<'_> {
+impl<'tcx> Context<'tcx> {
     fn path(&self, filename: &str) -> PathBuf {
         // We use splitn vs Path::extension here because we might get a filename
         // like `style.min.css` and we want to process that into
@@ -176,6 +176,10 @@ impl Context<'_> {
         self.dst.join(&filename)
     }
 
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.shared.tcx
+    }
+
     fn sess(&self) -> &Session {
         &self.shared.tcx.sess
     }
@@ -1708,8 +1712,8 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Ca
     write!(buf, "

"); render_stability_since_raw( buf, - item.stable_since().as_deref(), - item.const_stable_since().as_deref(), + item.stable_since(cx.tcx()).as_deref(), + item.const_stable_since(cx.tcx()).as_deref(), None, None, ); @@ -2061,14 +2065,20 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl } } - fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering { + fn cmp( + i1: &clean::Item, + i2: &clean::Item, + idx1: usize, + idx2: usize, + tcx: TyCtxt<'_>, + ) -> Ordering { let ty1 = i1.type_(); let ty2 = i2.type_(); if ty1 != ty2 { return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2)); } - let s1 = i1.stability.as_ref().map(|s| s.level); - let s2 = i2.stability.as_ref().map(|s| s.level); + let s1 = i1.stability(tcx).as_ref().map(|s| s.level); + let s2 = i2.stability(tcx).as_ref().map(|s| s.level); if let (Some(a), Some(b)) = (s1, s2) { match (a.is_stable(), b.is_stable()) { (true, true) | (false, false) => {} @@ -2082,7 +2092,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl } if cx.shared.sort_modules_alphabetically { - indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2)); + indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2, cx.tcx())); } // This call is to remove re-export duplicates in cases such as: // @@ -2184,7 +2194,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl _ => "", }; - let stab = myitem.stability_class(); + let stab = myitem.stability_class(cx.tcx()); let add = if stab.is_some() { " " } else { "" }; let doc_value = myitem.doc_value().unwrap_or(""); @@ -2196,7 +2206,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl {stab_tags}{docs}\ ", name = *myitem.name.as_ref().unwrap(), - stab_tags = extra_info_tags(myitem, item), + stab_tags = extra_info_tags(myitem, item, cx.tcx()), docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(), class = myitem.type_(), add = add, @@ -2220,7 +2230,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl /// Render the stability, deprecation and portability tags that are displayed in the item's summary /// at the module level. -fn extra_info_tags(item: &clean::Item, parent: &clean::Item) -> String { +fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> String { let mut tags = String::new(); fn tag_html(class: &str, title: &str, contents: &str) -> String { @@ -2228,7 +2238,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item) -> String { } // The trailing space after each tag is to space it properly against the rest of the docs. - if let Some(depr) = &item.deprecation { + if let Some(depr) = &item.deprecation(tcx) { let mut message = "Deprecated"; if !stability::deprecation_in_effect( depr.is_since_rustc_version, @@ -2241,7 +2251,10 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item) -> String { // The "rustc_private" crates are permanently unstable so it makes no sense // to render "unstable" everywhere. - if item.stability.as_ref().map(|s| s.level.is_unstable() && s.feature != sym::rustc_private) + if item + .stability(tcx) + .as_ref() + .map(|s| s.level.is_unstable() && s.feature != sym::rustc_private) == Some(true) { tags += &tag_html("unstable", "", "Experimental"); @@ -2287,7 +2300,7 @@ fn short_item_info( let error_codes = cx.shared.codes; if let Some(Deprecation { note, since, is_since_rustc_version, suggestion: _ }) = - item.deprecation + item.deprecation(cx.tcx()) { // We display deprecation messages for #[deprecated] and #[rustc_deprecated] // but only display the future-deprecation messages for #[rustc_deprecated]. @@ -2327,7 +2340,7 @@ fn short_item_info( // Render unstable items. But don't render "rustc_private" crates (internal compiler crates). // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere. if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item - .stability + .stability(cx.tcx()) .as_ref() .filter(|stab| stab.feature != sym::rustc_private) .map(|stab| (stab.level, stab.feature)) @@ -2480,8 +2493,8 @@ fn render_implementor( parent, AssocItemLink::Anchor(None), RenderMode::Normal, - implementor.impl_item.stable_since().as_deref(), - implementor.impl_item.const_stable_since().as_deref(), + implementor.impl_item.stable_since(cx.tcx()).as_deref(), + implementor.impl_item.const_stable_since(cx.tcx()).as_deref(), false, Some(use_absolute), false, @@ -2511,8 +2524,8 @@ fn render_impls( containing_item, assoc_link, RenderMode::Normal, - containing_item.stable_since().as_deref(), - containing_item.const_stable_since().as_deref(), + containing_item.stable_since(cx.tcx()).as_deref(), + containing_item.const_stable_since(cx.tcx()).as_deref(), true, None, false, @@ -2661,7 +2674,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra write!(w, "

", id = id,); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, ""); - render_stability_since(w, m, t); + render_stability_since(w, m, t, cx.tcx()); write_srclink(cx, m, w, cache); write!(w, "

"); document(w, cx, m, Some(t)); @@ -2768,8 +2781,8 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra it, assoc_link, RenderMode::Normal, - implementor.impl_item.stable_since().as_deref(), - implementor.impl_item.const_stable_since().as_deref(), + implementor.impl_item.stable_since(cx.tcx()).as_deref(), + implementor.impl_item.const_stable_since(cx.tcx()).as_deref(), false, None, true, @@ -2950,13 +2963,18 @@ fn render_stability_since_raw( } } -fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: &clean::Item) { +fn render_stability_since( + w: &mut Buffer, + item: &clean::Item, + containing_item: &clean::Item, + tcx: TyCtxt<'_>, +) { render_stability_since_raw( w, - item.stable_since().as_deref(), - item.const_stable_since().as_deref(), - containing_item.stable_since().as_deref(), - containing_item.const_stable_since().as_deref(), + item.stable_since(tcx).as_deref(), + item.const_stable_since(tcx).as_deref(), + containing_item.stable_since(tcx).as_deref(), + containing_item.const_stable_since(tcx).as_deref(), ) } @@ -3149,7 +3167,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni shortty = ItemType::StructField, ty = ty.print() ); - if let Some(stability_class) = field.stability_class() { + if let Some(stability_class) = field.stability_class(cx.tcx()) { write!(w, "", stab = stability_class); } document(w, cx, field, Some(it)); @@ -3279,7 +3297,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum } write!(w, ""); } - render_stability_since(w, variant, it); + render_stability_since(w, variant, it, cx.tcx()); } } render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) @@ -3510,8 +3528,8 @@ fn render_assoc_items( containing_item, AssocItemLink::Anchor(None), render_mode, - containing_item.stable_since().as_deref(), - containing_item.const_stable_since().as_deref(), + containing_item.stable_since(cx.tcx()).as_deref(), + containing_item.const_stable_since(cx.tcx()).as_deref(), true, None, false, @@ -3758,8 +3776,8 @@ fn render_impl( write!(w, "
", id); render_stability_since_raw( w, - i.impl_item.stable_since().as_deref(), - i.impl_item.const_stable_since().as_deref(), + i.impl_item.stable_since(cx.tcx()).as_deref(), + i.impl_item.const_stable_since(cx.tcx()).as_deref(), outer_version, outer_const_version, ); @@ -3831,8 +3849,8 @@ fn render_impl( write!(w, ""); render_stability_since_raw( w, - item.stable_since().as_deref(), - item.const_stable_since().as_deref(), + item.stable_since(cx.tcx()).as_deref(), + item.const_stable_since(cx.tcx()).as_deref(), outer_version, outer_const_version, ); @@ -3853,8 +3871,8 @@ fn render_impl( write!(w, ""); render_stability_since_raw( w, - item.stable_since().as_deref(), - item.const_stable_since().as_deref(), + item.stable_since(cx.tcx()).as_deref(), + item.const_stable_since(cx.tcx()).as_deref(), outer_version, outer_const_version, ); diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 99587f4ec64e..ef490086ed04 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -17,17 +17,8 @@ use crate::json::JsonRenderer; impl JsonRenderer<'_> { pub(super) fn convert_item(&self, item: clean::Item) -> Option { let item_type = ItemType::from(&item); - let clean::Item { - source, - name, - attrs, - kind, - visibility, - def_id, - stability: _, - const_stability: _, - deprecation, - } = item; + let deprecation = item.deprecation(self.tcx); + let clean::Item { source, name, attrs, kind, visibility, def_id } = item; match kind { clean::StrippedItem(_) => None, _ => Some(Item { From 48d5874914083e920a8500e860d01d1757701283 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Thu, 19 Nov 2020 21:22:32 +0100 Subject: [PATCH 397/719] Add the "promise" aliases to the `async` lang feature --- library/std/src/keyword_docs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index b990b7857039..54f4eb22d6a1 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2175,6 +2175,7 @@ mod where_keyword {} // 2018 Edition keywords +#[doc(alias = "promise")] #[doc(keyword = "async")] // /// Return a [`Future`] instead of blocking the current thread. From 74498c17e0d7ba29dd33e7765234ea75929b6aa7 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 16 Dec 2020 09:03:33 -0800 Subject: [PATCH 398/719] Update cargo --- Cargo.lock | 60 ++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 3 +++ src/bootstrap/dist.rs | 6 +++++ src/bootstrap/tool.rs | 37 ++++++++++++++++++++++++-- src/tools/cargo | 2 +- 5 files changed, 101 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9fef7fc1e352..fcfd23f2dae5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,6 +355,35 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "cargo-credential" +version = "0.1.0" + +[[package]] +name = "cargo-credential-1password" +version = "0.1.0" +dependencies = [ + "cargo-credential", + "serde", + "serde_json", +] + +[[package]] +name = "cargo-credential-macos-keychain" +version = "0.1.0" +dependencies = [ + "cargo-credential", + "security-framework", +] + +[[package]] +name = "cargo-credential-wincred" +version = "0.1.0" +dependencies = [ + "cargo-credential", + "winapi 0.3.9", +] + [[package]] name = "cargo-miri" version = "0.1.0" @@ -4442,6 +4471,29 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "security-framework" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -4489,18 +4541,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.115" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.115" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index e1a36d880867..204c92045b11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ members = [ "src/tools/rust-installer", "src/tools/rust-demangler", "src/tools/cargo", + "src/tools/cargo/crates/credential/cargo-credential-1password", + "src/tools/cargo/crates/credential/cargo-credential-macos-keychain", + "src/tools/cargo/crates/credential/cargo-credential-wincred", "src/tools/rustdoc", "src/tools/rls", "src/tools/rustfmt", diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 360e51ed2bb2..46110b71153e 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1247,6 +1247,12 @@ impl Step for Cargo { builder.create_dir(&image.join("etc/bash_completion.d")); let cargo = builder.ensure(tool::Cargo { compiler, target }); builder.install(&cargo, &image.join("bin"), 0o755); + for dirent in fs::read_dir(cargo.parent().unwrap()).expect("read_dir") { + let dirent = dirent.expect("read dir entry"); + if dirent.file_name().to_str().expect("utf8").starts_with("cargo-credential-") { + builder.install(&dirent.path(), &image.join("libexec"), 0o755); + } + } for man in t!(etc.join("man").read_dir()) { let man = t!(man); builder.install(&man.path(), &image.join("share/man/man1"), 0o644); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 290e3744852f..dc786249d996 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -563,7 +563,7 @@ impl Step for Cargo { } fn run(self, builder: &Builder<'_>) -> PathBuf { - builder + let cargo_bin_path = builder .ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -574,7 +574,40 @@ impl Step for Cargo { source_type: SourceType::Submodule, extra_features: Vec::new(), }) - .expect("expected to build -- essential tool") + .expect("expected to build -- essential tool"); + + let build_cred = |name, path| { + // These credential helpers are currently experimental. + // Any build failures will be ignored. + let _ = builder.ensure(ToolBuild { + compiler: self.compiler, + target: self.target, + tool: name, + mode: Mode::ToolRustc, + path, + is_optional_tool: true, + source_type: SourceType::Submodule, + extra_features: Vec::new(), + }); + }; + + if self.target.contains("windows") { + build_cred( + "cargo-credential-wincred", + "src/tools/cargo/crates/credential/cargo-credential-wincred", + ); + } + if self.target.contains("apple-darwin") { + build_cred( + "cargo-credential-macos-keychain", + "src/tools/cargo/crates/credential/cargo-credential-macos-keychain", + ); + } + build_cred( + "cargo-credential-1password", + "src/tools/cargo/crates/credential/cargo-credential-1password", + ); + cargo_bin_path } } diff --git a/src/tools/cargo b/src/tools/cargo index d274fcf862b8..a3c2627fbc2f 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit d274fcf862b89264fa2c6b917b15230705257317 +Subproject commit a3c2627fbc2f5391c65ba45ab53b81bf71fa323c From 2309783a0b65163041b03dce04d7df85dcabc2cd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 17 Dec 2020 00:42:49 +0000 Subject: [PATCH 399/719] Add tests --- .../exhaustiveness-unreachable-pattern.rs | 31 +++++++++++++++++++ .../exhaustiveness-unreachable-pattern.stderr | 22 ++++++++++--- src/test/ui/pattern/usefulness/issue-15129.rs | 8 ++--- src/test/ui/pattern/usefulness/issue-2111.rs | 13 ++++---- .../ui/pattern/usefulness/issue-2111.stderr | 6 ++-- src/test/ui/pattern/usefulness/issue-56379.rs | 14 +++++++++ .../ui/pattern/usefulness/issue-56379.stderr | 20 ++++++++++++ 7 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/pattern/usefulness/issue-56379.rs create mode 100644 src/test/ui/pattern/usefulness/issue-56379.stderr diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index 512f1e283cb4..178a4aa6681a 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -64,6 +64,37 @@ fn main() { | 2, ..] => {} _ => {} } + // FIXME: incorrect + match &[][..] { + [true] => {} + [true //~ ERROR unreachable + | false, ..] => {} + _ => {} + } + match &[][..] { + [false] => {} + [true, ..] => {} + [true //~ ERROR unreachable + | false, ..] => {} + _ => {} + } + match (true, None) { + (true, Some(_)) => {} + (false, Some(true)) => {} + (true | false, None | Some(true // FIXME: should be unreachable + | false)) => {} + } + macro_rules! t_or_f { + () => { + (true // FIXME: should be unreachable + | false) + }; + } + match (true, None) { + (true, Some(_)) => {} + (false, Some(true)) => {} + (true | false, None | Some(t_or_f!())) => {} + } match Some(0) { Some(0) => {} Some(0 //~ ERROR unreachable diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index e968310d108d..38e2369ae7db 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -95,28 +95,40 @@ LL | [1 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:69:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:70:10 + | +LL | [true + | ^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:77:10 + | +LL | [true + | ^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:100:14 | LL | Some(0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:88:19 + --> $DIR/exhaustiveness-unreachable-pattern.rs:119:19 | LL | | false) => {} | ^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:96:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:127:15 | LL | | true) => {} | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:102:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:133:15 | LL | | true, | ^^^^ -error: aborting due to 19 previous errors +error: aborting due to 21 previous errors diff --git a/src/test/ui/pattern/usefulness/issue-15129.rs b/src/test/ui/pattern/usefulness/issue-15129.rs index ed134c175edd..bcfc32be9a48 100644 --- a/src/test/ui/pattern/usefulness/issue-15129.rs +++ b/src/test/ui/pattern/usefulness/issue-15129.rs @@ -1,17 +1,17 @@ pub enum T { T1(()), - T2(()) + T2(()), } pub enum V { V1(isize), - V2(bool) + V2(bool), } fn main() { match (T::T1(()), V::V2(true)) { - //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered + //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered (T::T1(()), V::V1(i)) => (), - (T::T2(()), V::V2(b)) => () + (T::T2(()), V::V2(b)) => (), } } diff --git a/src/test/ui/pattern/usefulness/issue-2111.rs b/src/test/ui/pattern/usefulness/issue-2111.rs index 7e5835e8697a..0847045cdaa9 100644 --- a/src/test/ui/pattern/usefulness/issue-2111.rs +++ b/src/test/ui/pattern/usefulness/issue-2111.rs @@ -1,12 +1,11 @@ fn foo(a: Option, b: Option) { - match (a,b) { - //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered - (Some(a), Some(b)) if a == b => { } - (Some(_), None) | - (None, Some(_)) => { } - } + match (a, b) { + //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered + (Some(a), Some(b)) if a == b => {} + (Some(_), None) | (None, Some(_)) => {} + } } fn main() { - foo(None, None); + foo(None, None); } diff --git a/src/test/ui/pattern/usefulness/issue-2111.stderr b/src/test/ui/pattern/usefulness/issue-2111.stderr index a39a479e078d..f0609ccebc16 100644 --- a/src/test/ui/pattern/usefulness/issue-2111.stderr +++ b/src/test/ui/pattern/usefulness/issue-2111.stderr @@ -1,8 +1,8 @@ error[E0004]: non-exhaustive patterns: `(None, None)` not covered - --> $DIR/issue-2111.rs:2:9 + --> $DIR/issue-2111.rs:2:11 | -LL | match (a,b) { - | ^^^^^ pattern `(None, None)` not covered +LL | match (a, b) { + | ^^^^^^ pattern `(None, None)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(Option, Option)` diff --git a/src/test/ui/pattern/usefulness/issue-56379.rs b/src/test/ui/pattern/usefulness/issue-56379.rs new file mode 100644 index 000000000000..5454e80cdb4f --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-56379.rs @@ -0,0 +1,14 @@ +enum Foo { + A(bool), + B(bool), + C(bool), +} + +fn main() { + match Foo::A(true) { + //~^ ERROR non-exhaustive patterns: `A(false)` not covered + Foo::A(true) => {} + Foo::B(true) => {} + Foo::C(true) => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-56379.stderr b/src/test/ui/pattern/usefulness/issue-56379.stderr new file mode 100644 index 000000000000..661e0dbb4392 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-56379.stderr @@ -0,0 +1,20 @@ +error[E0004]: non-exhaustive patterns: `A(false)` not covered + --> $DIR/issue-56379.rs:8:11 + | +LL | / enum Foo { +LL | | A(bool), + | | - not covered +LL | | B(bool), +LL | | C(bool), +LL | | } + | |_- `Foo` defined here +... +LL | match Foo::A(true) { + | ^^^^^^^^^^^^ pattern `A(false)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. From 7009d202904e9af500ef13285b4c50cf63c2e75b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 16 Dec 2020 06:24:31 +0000 Subject: [PATCH 400/719] Factor out or-pattern usefulness merging --- .../src/thir/pattern/usefulness.rs | 153 +++++++++--------- 1 file changed, 81 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index f3e1507b37ae..ae92898a0f41 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -648,6 +648,81 @@ impl<'tcx> Usefulness<'tcx> { !matches!(*self, NotUseful) } + /// When trying several branches and each returns a `Usefulness`, we need to combine the + /// results together. + fn merge(usefulnesses: impl Iterator, column_count: usize) -> Self { + // If two branches have detected some unreachable sub-branches, we need to be careful. If + // they were detected in columns that are not the current one, we want to keep only the + // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last + // `true` is unreachable in the second branch of the first or-pattern, but not otherwise. + // Therefore we don't want to lint that it is unreachable. + // + // ``` + // match (true, true) { + // (true, true) => {} + // (false | true, false | true) => {} + // } + // ``` + // If however the sub-branches come from the current column, they come from the inside of + // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want + // to lint that the last `false` is unreachable. + // ``` + // match None { + // Some(false) => {} + // None | Some(true | false) => {} + // } + // ``` + + // We keep track of sub-branches separately depending on whether they come from this column + // or from others. + let mut unreachables_this_column: FxHashSet = FxHashSet::default(); + let mut unreachables_other_columns: Vec> = Vec::default(); + // Whether at least one branch is reachable. + let mut any_is_useful = false; + + for (u, span) in usefulnesses { + match u { + Useful(unreachables) => { + if let Some((this_column, other_columns)) = unreachables.split_last() { + // We keep the union of unreachables found in the first column. + unreachables_this_column.extend(this_column); + // We keep the intersection of unreachables found in other columns. + if unreachables_other_columns.is_empty() { + unreachables_other_columns = other_columns.to_vec(); + } else { + unreachables_other_columns = unreachables_other_columns + .into_iter() + .zip(other_columns) + .map(|(x, y)| x.intersection(&y).copied().collect()) + .collect(); + } + } + any_is_useful = true; + } + NotUseful => { + unreachables_this_column.insert(span); + } + UsefulWithWitness(_) => { + bug!( + "encountered or-pat in the expansion of `_` during exhaustiveness checking" + ) + } + } + } + + if any_is_useful { + let mut unreachables = if unreachables_other_columns.is_empty() { + (0..column_count - 1).map(|_| FxHashSet::default()).collect() + } else { + unreachables_other_columns + }; + unreachables.push(unreachables_this_column); + Useful(unreachables) + } else { + NotUseful + } + } + fn apply_constructor<'p>( self, pcx: PatCtxt<'_, 'p, 'tcx>, @@ -833,85 +908,19 @@ fn is_useful<'p, 'tcx>( if let Some(vs) = v.expand_or_pat() { // We expand the or pattern, trying each of its branches in turn and keeping careful track // of possible unreachable sub-branches. - // - // If two branches have detected some unreachable sub-branches, we need to be careful. If - // they were detected in columns that are not the current one, we want to keep only the - // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last - // `true` is unreachable in the second branch of the first or-pattern, but not otherwise. - // Therefore we don't want to lint that it is unreachable. - // - // ``` - // match (true, true) { - // (true, true) => {} - // (false | true, false | true) => {} - // } - // ``` - // If however the sub-branches come from the current column, they come from the inside of - // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want - // to lint that the last `false` is unreachable. - // ``` - // match None { - // Some(false) => {} - // None | Some(true | false) => {} - // } - // ``` - let mut matrix = matrix.clone(); - // We keep track of sub-branches separately depending on whether they come from this column - // or from others. - let mut unreachables_this_column: FxHashSet = FxHashSet::default(); - let mut unreachables_other_columns: Vec> = Vec::default(); - // Whether at least one branch is reachable. - let mut any_is_useful = false; - - for v in vs { - let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); - match res { - Useful(unreachables) => { - if let Some((this_column, other_columns)) = unreachables.split_last() { - // We keep the union of unreachables found in the first column. - unreachables_this_column.extend(this_column); - // We keep the intersection of unreachables found in other columns. - if unreachables_other_columns.is_empty() { - unreachables_other_columns = other_columns.to_vec(); - } else { - unreachables_other_columns = unreachables_other_columns - .into_iter() - .zip(other_columns) - .map(|(x, y)| x.intersection(&y).copied().collect()) - .collect(); - } - } - any_is_useful = true; - } - NotUseful => { - unreachables_this_column.insert(v.head().span); - } - UsefulWithWitness(_) => bug!( - "encountered or-pat in the expansion of `_` during exhaustiveness checking" - ), - } - + let usefulnesses = vs.into_iter().map(|v| { + let span = v.head().span; + let u = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); // If pattern has a guard don't add it to the matrix. if !is_under_guard { // We push the already-seen patterns into the matrix in order to detect redundant // branches like `Some(_) | Some(0)`. matrix.push(v); } - } - - return if any_is_useful { - let mut unreachables = if unreachables_other_columns.is_empty() { - let n_columns = v.len(); - (0..n_columns - 1).map(|_| FxHashSet::default()).collect() - } else { - unreachables_other_columns - }; - unreachables.push(unreachables_this_column); - Useful(unreachables) - } else { - NotUseful - }; + (u, span) + }); + return Usefulness::merge(usefulnesses, v.len()); } // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). From 170fae2c187936498ffdebbbd7e3cad47af31cc9 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 17 Dec 2020 00:47:31 +0000 Subject: [PATCH 401/719] Log the output of `is_useful` in the or-pattern case too --- .../src/thir/pattern/usefulness.rs | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index ae92898a0f41..9646f7ffcf7f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -904,8 +904,14 @@ fn is_useful<'p, 'tcx>( assert!(rows.iter().all(|r| r.len() == v.len())); + // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). + let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); + let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level }; + + debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head()); + // If the first pattern is an or-pattern, expand it. - if let Some(vs) = v.expand_or_pat() { + let ret = if let Some(vs) = v.expand_or_pat() { // We expand the or pattern, trying each of its branches in turn and keeping careful track // of possible unreachable sub-branches. let mut matrix = matrix.clone(); @@ -920,30 +926,30 @@ fn is_useful<'p, 'tcx>( } (u, span) }); - return Usefulness::merge(usefulnesses, v.len()); - } - - // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). - let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); - let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level }; - - debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head()); - - let ret = v - .head_ctor(cx) - .split(pcx, Some(hir_id)) - .into_iter() - .map(|ctor| { - // We cache the result of `Fields::wildcards` because it is used a lot. - let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); - let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); - let v = v.pop_head_constructor(&ctor_wild_subpatterns); - let usefulness = - is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); - usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) - }) - .find(|result| result.is_useful()) - .unwrap_or(NotUseful); + Usefulness::merge(usefulnesses, v.len()) + } else { + v.head_ctor(cx) + .split(pcx, Some(hir_id)) + .into_iter() + .map(|ctor| { + // We cache the result of `Fields::wildcards` because it is used a lot. + let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); + let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); + let v = v.pop_head_constructor(&ctor_wild_subpatterns); + let usefulness = is_useful( + pcx.cx, + &matrix, + &v, + witness_preference, + hir_id, + is_under_guard, + false, + ); + usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) + }) + .find(|result| result.is_useful()) + .unwrap_or(NotUseful) + }; debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret); ret } From d7a6365b77e171337d4f4220ebdc618965524ecd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 17 Dec 2020 01:07:49 +0000 Subject: [PATCH 402/719] Rewrite usefulness merging using `SpanSet` `SpanSet` is heavily inspired from `DefIdForest`. --- .../src/thir/pattern/check_match.rs | 2 +- .../src/thir/pattern/usefulness.rs | 177 +++++++++++------- .../exhaustiveness-unreachable-pattern.rs | 2 +- .../exhaustiveness-unreachable-pattern.stderr | 8 +- 4 files changed, 122 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 97edbd83b89c..2c37f7bdb45d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -402,7 +402,7 @@ fn report_arm_reachability<'p, 'tcx>( Useful(unreachables) if unreachables.is_empty() => {} // The arm is reachable, but contains unreachable subpatterns (from or-patterns). Useful(unreachables) => { - let mut unreachables: Vec<_> = unreachables.iter().flatten().copied().collect(); + let mut unreachables: Vec<_> = unreachables.iter().collect(); // Emit lints in the order in which they occur in the file. unreachables.sort_unstable(); for span in unreachables { diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 9646f7ffcf7f..5af155bd746a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -311,7 +311,6 @@ use super::{Pat, PatKind}; use super::{PatternFoldable, PatternFolder}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::OnceCell; use rustc_arena::TypedArena; @@ -626,11 +625,81 @@ impl<'p, 'tcx> FromIterator> for Matrix<'p, 'tcx> { } } +/// Represents a set of `Span`s closed under the containment relation. That is, if a `Span` is +/// contained in the set then all `Span`s contained in it are also implicitly contained in the set. +/// In particular this means that when intersecting two sets, taking the intersection of some span +/// and one of its subspans returns the subspan, whereas a simple `HashSet` would have returned an +/// empty intersection. +/// It is assumed that two spans don't overlap without one being contained in the other; in other +/// words, that the inclusion structure forms a tree and not a DAG. +/// Operations on this do not need to be fast since it's only nonempty in the diagnostic path. +#[derive(Debug, Clone, Default)] +pub(crate) struct SpanSet { + /// The minimal set of `Span`s required to represent the whole set. If A and B are `Span`s in + /// the `SpanSet`, and A is a descendant of B, then only B will be in `root_spans`. + /// Invariant: the spans are disjoint. + root_spans: Vec, +} + +impl SpanSet { + /// Creates an empty set. + fn new() -> Self { + Self::default() + } + + /// Tests whether the set is empty. + pub(crate) fn is_empty(&self) -> bool { + self.root_spans.is_empty() + } + + /// Iterate over the disjoint list of spans at the roots of this set. + pub(crate) fn iter<'a>(&'a self) -> impl Iterator + Captures<'a> { + self.root_spans.iter().copied() + } + + /// Tests whether the set contains a given Span. + fn contains(&self, span: Span) -> bool { + self.iter().any(|root_span| root_span.contains(span)) + } + + /// Add a span to the set if we know the span has no intersection in this set. + fn push_nonintersecting(&mut self, new_span: Span) { + self.root_spans.push(new_span); + } + + fn intersection_mut(&mut self, other: &Self) { + if self.is_empty() || other.is_empty() { + *self = Self::new(); + return; + } + // Those that were in `self` but not contained in `other` + let mut leftover = SpanSet::new(); + // We keep the elements in `self` that are also in `other`. + self.root_spans.retain(|span| { + let retain = other.contains(*span); + if !retain { + leftover.root_spans.push(*span); + } + retain + }); + // We keep the elements in `other` that are also in the original `self`. You might think + // this is not needed because `self` already contains the intersection. But those aren't + // just sets of things. If `self = [a]`, `other = [b]` and `a` contains `b`, then `b` + // belongs in the intersection but we didn't catch it in the filtering above. We look at + // `leftover` instead of the full original `self` to avoid duplicates. + for span in other.iter() { + if leftover.contains(span) { + self.root_spans.push(span); + } + } + } +} + #[derive(Clone, Debug)] crate enum Usefulness<'tcx> { - /// Carries, for each column in the matrix, a set of sub-branches that have been found to be - /// unreachable. Used only in the presence of or-patterns, otherwise it stays empty. - Useful(Vec>), + /// Pontentially carries a set of sub-branches that have been found to be unreachable. Used + /// only in the presence of or-patterns, otherwise it stays empty. + Useful(SpanSet), /// Carries a list of witnesses of non-exhaustiveness. UsefulWithWitness(Vec>), NotUseful, @@ -640,7 +709,7 @@ impl<'tcx> Usefulness<'tcx> { fn new_useful(preference: WitnessPreference) -> Self { match preference { ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]), - LeaveOutWitness => Useful(vec![]), + LeaveOutWitness => Useful(Default::default()), } } @@ -650,22 +719,20 @@ impl<'tcx> Usefulness<'tcx> { /// When trying several branches and each returns a `Usefulness`, we need to combine the /// results together. - fn merge(usefulnesses: impl Iterator, column_count: usize) -> Self { - // If two branches have detected some unreachable sub-branches, we need to be careful. If - // they were detected in columns that are not the current one, we want to keep only the - // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last - // `true` is unreachable in the second branch of the first or-pattern, but not otherwise. - // Therefore we don't want to lint that it is unreachable. - // + fn merge(usefulnesses: impl Iterator) -> Self { + // If we have detected some unreachable sub-branches, we only want to keep them when they + // were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable + // in the second branch of the first or-pattern, but not otherwise. Therefore we don't want + // to lint that it is unreachable. // ``` // match (true, true) { // (true, true) => {} // (false | true, false | true) => {} // } // ``` - // If however the sub-branches come from the current column, they come from the inside of - // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want - // to lint that the last `false` is unreachable. + // Here however we _do_ want to lint that the last `false` is unreachable. So we don't want + // to intersect the spans that come directly from the or-pattern, since each branch of the + // or-pattern brings a new disjoint pattern. // ``` // match None { // Some(false) => {} @@ -673,35 +740,34 @@ impl<'tcx> Usefulness<'tcx> { // } // ``` - // We keep track of sub-branches separately depending on whether they come from this column - // or from others. - let mut unreachables_this_column: FxHashSet = FxHashSet::default(); - let mut unreachables_other_columns: Vec> = Vec::default(); - // Whether at least one branch is reachable. - let mut any_is_useful = false; + // Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the + // sets are only non-empty in the diagnostic path. + let mut unreachables: Option = None; + // In case of or-patterns we don't want to intersect subpatterns that come from the first + // column. Invariant: contains a list of disjoint spans. + let mut unreachables_this_column = Vec::new(); - for (u, span) in usefulnesses { + for (u, branch_span) in usefulnesses { match u { - Useful(unreachables) => { - if let Some((this_column, other_columns)) = unreachables.split_last() { - // We keep the union of unreachables found in the first column. - unreachables_this_column.extend(this_column); - // We keep the intersection of unreachables found in other columns. - if unreachables_other_columns.is_empty() { - unreachables_other_columns = other_columns.to_vec(); - } else { - unreachables_other_columns = unreachables_other_columns - .into_iter() - .zip(other_columns) - .map(|(x, y)| x.intersection(&y).copied().collect()) - .collect(); + Useful(spans) if spans.is_empty() => { + // Hot path: `spans` is only non-empty in the diagnostic path. + unreachables = Some(SpanSet::new()); + } + Useful(spans) => { + for span in spans.iter() { + if branch_span.contains(span) { + unreachables_this_column.push(span) } } - any_is_useful = true; - } - NotUseful => { - unreachables_this_column.insert(span); + if let Some(set) = &mut unreachables { + if !set.is_empty() { + set.intersection_mut(&spans); + } + } else { + unreachables = Some(spans); + } } + NotUseful => unreachables_this_column.push(branch_span), UsefulWithWitness(_) => { bug!( "encountered or-pat in the expansion of `_` during exhaustiveness checking" @@ -710,13 +776,13 @@ impl<'tcx> Usefulness<'tcx> { } } - if any_is_useful { - let mut unreachables = if unreachables_other_columns.is_empty() { - (0..column_count - 1).map(|_| FxHashSet::default()).collect() - } else { - unreachables_other_columns - }; - unreachables.push(unreachables_this_column); + if let Some(mut unreachables) = unreachables { + for span in unreachables_this_column { + // `unreachables` contained no spans from the first column, and + // `unreachables_this_column` contains only disjoint spans. Therefore it is valid + // to call `push_nonintersecting`. + unreachables.push_nonintersecting(span); + } Useful(unreachables) } else { NotUseful @@ -752,23 +818,6 @@ impl<'tcx> Usefulness<'tcx> { }; UsefulWithWitness(new_witnesses) } - Useful(mut unreachables) => { - if !unreachables.is_empty() { - // When we apply a constructor, there are `arity` columns of the matrix that - // corresponded to its arguments. All the unreachables found in these columns - // will, after `apply`, come from the first column. So we take the union of all - // the corresponding sets and put them in the first column. - // Note that `arity` may be 0, in which case we just push a new empty set. - let len = unreachables.len(); - let arity = ctor_wild_subpatterns.len(); - let mut unioned = FxHashSet::default(); - for set in unreachables.drain((len - arity)..) { - unioned.extend(set) - } - unreachables.push(unioned); - } - Useful(unreachables) - } x => x, } } @@ -926,7 +975,7 @@ fn is_useful<'p, 'tcx>( } (u, span) }); - Usefulness::merge(usefulnesses, v.len()) + Usefulness::merge(usefulnesses) } else { v.head_ctor(cx) .split(pcx, Some(hir_id)) diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index 178a4aa6681a..3e242a797a20 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -81,7 +81,7 @@ fn main() { match (true, None) { (true, Some(_)) => {} (false, Some(true)) => {} - (true | false, None | Some(true // FIXME: should be unreachable + (true | false, None | Some(true //~ ERROR unreachable | false)) => {} } macro_rules! t_or_f { diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index 38e2369ae7db..ac0b34c2bd54 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -106,6 +106,12 @@ error: unreachable pattern LL | [true | ^^^^ +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:84:36 + | +LL | (true | false, None | Some(true + | ^^^^ + error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:100:14 | @@ -130,5 +136,5 @@ error: unreachable pattern LL | | true, | ^^^^ -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors From 2d71a0b9b9871966dd1f63b4113eeecc2d6e2f6f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 17 Dec 2020 01:18:01 +0000 Subject: [PATCH 403/719] Keep all witnesses of non-exhaustiveness --- .../src/thir/pattern/usefulness.rs | 64 +++++++++++-------- src/test/ui/pattern/usefulness/issue-15129.rs | 2 +- .../ui/pattern/usefulness/issue-15129.stderr | 4 +- src/test/ui/pattern/usefulness/issue-2111.rs | 2 +- .../ui/pattern/usefulness/issue-2111.stderr | 4 +- src/test/ui/pattern/usefulness/issue-56379.rs | 2 +- .../ui/pattern/usefulness/issue-56379.stderr | 6 +- .../usefulness/non-exhaustive-match.rs | 2 +- .../usefulness/non-exhaustive-match.stderr | 4 +- 9 files changed, 51 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 5af155bd746a..02b5e0eb3b22 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -713,13 +713,9 @@ impl<'tcx> Usefulness<'tcx> { } } - fn is_useful(&self) -> bool { - !matches!(*self, NotUseful) - } - /// When trying several branches and each returns a `Usefulness`, we need to combine the /// results together. - fn merge(usefulnesses: impl Iterator) -> Self { + fn merge_or_patterns(usefulnesses: impl Iterator) -> Self { // If we have detected some unreachable sub-branches, we only want to keep them when they // were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable // in the second branch of the first or-pattern, but not otherwise. Therefore we don't want @@ -789,6 +785,27 @@ impl<'tcx> Usefulness<'tcx> { } } + /// When trying several branches and each returns a `Usefulness`, we need to combine the + /// results together. + fn merge_split_constructors(usefulnesses: impl Iterator) -> Self { + // Witnesses of usefulness, if any. + let mut witnesses = Vec::new(); + + for u in usefulnesses { + match u { + Useful(..) => { + return u; + } + NotUseful => {} + UsefulWithWitness(wits) => { + witnesses.extend(wits); + } + } + } + + if !witnesses.is_empty() { UsefulWithWitness(witnesses) } else { NotUseful } + } + fn apply_constructor<'p>( self, pcx: PatCtxt<'_, 'p, 'tcx>, @@ -975,29 +992,22 @@ fn is_useful<'p, 'tcx>( } (u, span) }); - Usefulness::merge(usefulnesses) + Usefulness::merge_or_patterns(usefulnesses) } else { - v.head_ctor(cx) - .split(pcx, Some(hir_id)) - .into_iter() - .map(|ctor| { - // We cache the result of `Fields::wildcards` because it is used a lot. - let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); - let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); - let v = v.pop_head_constructor(&ctor_wild_subpatterns); - let usefulness = is_useful( - pcx.cx, - &matrix, - &v, - witness_preference, - hir_id, - is_under_guard, - false, - ); - usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) - }) - .find(|result| result.is_useful()) - .unwrap_or(NotUseful) + // We split the head constructor of `v`. + let ctors = v.head_ctor(cx).split(pcx, Some(hir_id)); + // For each constructor, we compute whether there's a value that starts with it that would + // witness the usefulness of `v`. + let usefulnesses = ctors.into_iter().map(|ctor| { + // We cache the result of `Fields::wildcards` because it is used a lot. + let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); + let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); + let v = v.pop_head_constructor(&ctor_wild_subpatterns); + let usefulness = + is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); + usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) + }); + Usefulness::merge_split_constructors(usefulnesses) }; debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret); ret diff --git a/src/test/ui/pattern/usefulness/issue-15129.rs b/src/test/ui/pattern/usefulness/issue-15129.rs index bcfc32be9a48..d2b72a86b74c 100644 --- a/src/test/ui/pattern/usefulness/issue-15129.rs +++ b/src/test/ui/pattern/usefulness/issue-15129.rs @@ -10,7 +10,7 @@ pub enum V { fn main() { match (T::T1(()), V::V2(true)) { - //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered + //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered (T::T1(()), V::V1(i)) => (), (T::T2(()), V::V2(b)) => (), } diff --git a/src/test/ui/pattern/usefulness/issue-15129.stderr b/src/test/ui/pattern/usefulness/issue-15129.stderr index aa4434e72b5c..79a77240937a 100644 --- a/src/test/ui/pattern/usefulness/issue-15129.stderr +++ b/src/test/ui/pattern/usefulness/issue-15129.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` not covered +error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered --> $DIR/issue-15129.rs:12:11 | LL | match (T::T1(()), V::V2(true)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(T1(()), V2(_))` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(T, V)` diff --git a/src/test/ui/pattern/usefulness/issue-2111.rs b/src/test/ui/pattern/usefulness/issue-2111.rs index 0847045cdaa9..d27beaeffd63 100644 --- a/src/test/ui/pattern/usefulness/issue-2111.rs +++ b/src/test/ui/pattern/usefulness/issue-2111.rs @@ -1,6 +1,6 @@ fn foo(a: Option, b: Option) { match (a, b) { - //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered + //~^ ERROR: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered (Some(a), Some(b)) if a == b => {} (Some(_), None) | (None, Some(_)) => {} } diff --git a/src/test/ui/pattern/usefulness/issue-2111.stderr b/src/test/ui/pattern/usefulness/issue-2111.stderr index f0609ccebc16..60d9b8514b7f 100644 --- a/src/test/ui/pattern/usefulness/issue-2111.stderr +++ b/src/test/ui/pattern/usefulness/issue-2111.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `(None, None)` not covered +error[E0004]: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered --> $DIR/issue-2111.rs:2:11 | LL | match (a, b) { - | ^^^^^^ pattern `(None, None)` not covered + | ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(Option, Option)` diff --git a/src/test/ui/pattern/usefulness/issue-56379.rs b/src/test/ui/pattern/usefulness/issue-56379.rs index 5454e80cdb4f..9bccccca9c2b 100644 --- a/src/test/ui/pattern/usefulness/issue-56379.rs +++ b/src/test/ui/pattern/usefulness/issue-56379.rs @@ -6,7 +6,7 @@ enum Foo { fn main() { match Foo::A(true) { - //~^ ERROR non-exhaustive patterns: `A(false)` not covered + //~^ ERROR non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered Foo::A(true) => {} Foo::B(true) => {} Foo::C(true) => {} diff --git a/src/test/ui/pattern/usefulness/issue-56379.stderr b/src/test/ui/pattern/usefulness/issue-56379.stderr index 661e0dbb4392..6a231b868c8c 100644 --- a/src/test/ui/pattern/usefulness/issue-56379.stderr +++ b/src/test/ui/pattern/usefulness/issue-56379.stderr @@ -1,16 +1,18 @@ -error[E0004]: non-exhaustive patterns: `A(false)` not covered +error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered --> $DIR/issue-56379.rs:8:11 | LL | / enum Foo { LL | | A(bool), | | - not covered LL | | B(bool), + | | - not covered LL | | C(bool), + | | - not covered LL | | } | |_- `Foo` defined here ... LL | match Foo::A(true) { - | ^^^^^^^^^^^^ pattern `A(false)` not covered + | ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `Foo` diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs index a28cfb579f4f..4ff12aa2ff5e 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs @@ -15,7 +15,7 @@ fn main() { // and `(_, _, 5_i32..=i32::MAX)` not covered (_, _, 4) => {} } - match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` not covered + match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` and `(B, B)` not covered (T::A, T::B) => {} (T::B, T::A) => {} } diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index 12412743b83f..c953cd314406 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -45,11 +45,11 @@ LL | match (2, 3, 4) { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(i32, i32, i32)` -error[E0004]: non-exhaustive patterns: `(A, A)` not covered +error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered --> $DIR/non-exhaustive-match.rs:18:11 | LL | match (T::A, T::A) { - | ^^^^^^^^^^^^ pattern `(A, A)` not covered + | ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(T, T)` From 6319d737e07d732aa044864933b69a39fdbeec0a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 17 Dec 2020 01:25:53 +0000 Subject: [PATCH 404/719] Merge unreachable subpatterns correctly --- .../src/thir/pattern/usefulness.rs | 31 +++++++++++++++++-- .../exhaustiveness-unreachable-pattern.rs | 4 +-- .../exhaustiveness-unreachable-pattern.stderr | 20 +++++------- 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 02b5e0eb3b22..c07d4c9b8f74 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -788,13 +788,32 @@ impl<'tcx> Usefulness<'tcx> { /// When trying several branches and each returns a `Usefulness`, we need to combine the /// results together. fn merge_split_constructors(usefulnesses: impl Iterator) -> Self { + // If we have detected some unreachable sub-branches, we only want to keep them when they + // were unreachable in _all_ branches. So we take a big intersection. + + // Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the + // sets are only non-empty in the diagnostic path. + let mut unreachables: Option = None; // Witnesses of usefulness, if any. let mut witnesses = Vec::new(); for u in usefulnesses { match u { - Useful(..) => { - return u; + Useful(spans) if spans.is_empty() => { + // Once we reach the empty set, more intersections won't change the result. + return Useful(SpanSet::new()); + } + Useful(spans) => { + if let Some(unreachables) = &mut unreachables { + if !unreachables.is_empty() { + unreachables.intersection_mut(&spans); + } + if unreachables.is_empty() { + return Useful(SpanSet::new()); + } + } else { + unreachables = Some(spans); + } } NotUseful => {} UsefulWithWitness(wits) => { @@ -803,7 +822,13 @@ impl<'tcx> Usefulness<'tcx> { } } - if !witnesses.is_empty() { UsefulWithWitness(witnesses) } else { NotUseful } + if !witnesses.is_empty() { + UsefulWithWitness(witnesses) + } else if let Some(unreachables) = unreachables { + Useful(unreachables) + } else { + NotUseful + } } fn apply_constructor<'p>( diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index 3e242a797a20..184ffa85c40e 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -64,11 +64,9 @@ fn main() { | 2, ..] => {} _ => {} } - // FIXME: incorrect match &[][..] { [true] => {} - [true //~ ERROR unreachable - | false, ..] => {} + [true | false, ..] => {} _ => {} } match &[][..] { diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index ac0b34c2bd54..8b1003b5514a 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -95,46 +95,40 @@ LL | [1 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:70:10 + --> $DIR/exhaustiveness-unreachable-pattern.rs:75:10 | LL | [true | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:77:10 - | -LL | [true - | ^^^^ - -error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:84:36 + --> $DIR/exhaustiveness-unreachable-pattern.rs:82:36 | LL | (true | false, None | Some(true | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:100:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:98:14 | LL | Some(0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:119:19 + --> $DIR/exhaustiveness-unreachable-pattern.rs:117:19 | LL | | false) => {} | ^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:127:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:125:15 | LL | | true) => {} | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:133:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:131:15 | LL | | true, | ^^^^ -error: aborting due to 22 previous errors +error: aborting due to 21 previous errors From cefcadbe9278cf30175e93309cdd5f1da6714869 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 17 Dec 2020 01:56:22 +0000 Subject: [PATCH 405/719] Unify the two kinds of usefulness merging This is elegant but a bit of a perf gamble. That said, or-patterns rarely have many branches and it's easy to optimize or revert if we ever need to. In the meantime simpler code is worth it. --- .../src/thir/pattern/usefulness.rs | 98 +++++++------------ 1 file changed, 35 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index c07d4c9b8f74..0ecc034ac0ba 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -632,7 +632,8 @@ impl<'p, 'tcx> FromIterator> for Matrix<'p, 'tcx> { /// empty intersection. /// It is assumed that two spans don't overlap without one being contained in the other; in other /// words, that the inclusion structure forms a tree and not a DAG. -/// Operations on this do not need to be fast since it's only nonempty in the diagnostic path. +/// Intersection is not very efficient. It compares everything pairwise. If needed it could be made +/// faster by sorting the `Span`s and merging cleverly. #[derive(Debug, Clone, Default)] pub(crate) struct SpanSet { /// The minimal set of `Span`s required to represent the whole set. If A and B are `Span`s in @@ -715,7 +716,7 @@ impl<'tcx> Usefulness<'tcx> { /// When trying several branches and each returns a `Usefulness`, we need to combine the /// results together. - fn merge_or_patterns(usefulnesses: impl Iterator) -> Self { + fn merge(usefulnesses: impl Iterator) -> Self { // If we have detected some unreachable sub-branches, we only want to keep them when they // were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable // in the second branch of the first or-pattern, but not otherwise. Therefore we don't want @@ -737,62 +738,7 @@ impl<'tcx> Usefulness<'tcx> { // ``` // Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the - // sets are only non-empty in the diagnostic path. - let mut unreachables: Option = None; - // In case of or-patterns we don't want to intersect subpatterns that come from the first - // column. Invariant: contains a list of disjoint spans. - let mut unreachables_this_column = Vec::new(); - - for (u, branch_span) in usefulnesses { - match u { - Useful(spans) if spans.is_empty() => { - // Hot path: `spans` is only non-empty in the diagnostic path. - unreachables = Some(SpanSet::new()); - } - Useful(spans) => { - for span in spans.iter() { - if branch_span.contains(span) { - unreachables_this_column.push(span) - } - } - if let Some(set) = &mut unreachables { - if !set.is_empty() { - set.intersection_mut(&spans); - } - } else { - unreachables = Some(spans); - } - } - NotUseful => unreachables_this_column.push(branch_span), - UsefulWithWitness(_) => { - bug!( - "encountered or-pat in the expansion of `_` during exhaustiveness checking" - ) - } - } - } - - if let Some(mut unreachables) = unreachables { - for span in unreachables_this_column { - // `unreachables` contained no spans from the first column, and - // `unreachables_this_column` contains only disjoint spans. Therefore it is valid - // to call `push_nonintersecting`. - unreachables.push_nonintersecting(span); - } - Useful(unreachables) - } else { - NotUseful - } - } - - /// When trying several branches and each returns a `Usefulness`, we need to combine the - /// results together. - fn merge_split_constructors(usefulnesses: impl Iterator) -> Self { - // If we have detected some unreachable sub-branches, we only want to keep them when they - // were unreachable in _all_ branches. So we take a big intersection. - - // Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the - // sets are only non-empty in the diagnostic path. + // sets are only non-empty in the presence of or-patterns. let mut unreachables: Option = None; // Witnesses of usefulness, if any. let mut witnesses = Vec::new(); @@ -831,6 +777,30 @@ impl<'tcx> Usefulness<'tcx> { } } + /// After calculating the usefulness for a branch of an or-pattern, call this to make this + /// usefulness mergeable with those from the other branches. + fn unsplit_or_pat(self, this_span: Span, or_pat_spans: &[Span]) -> Self { + match self { + Useful(mut spans) => { + // We register the spans of the other branches of this or-pattern as being + // unreachable from this one. This ensures that intersecting together the sets of + // spans returns what we want. + // Until we optimize `SpanSet` however, intersecting this entails a number of + // comparisons quadratic in the number of branches. + for &span in or_pat_spans { + if span != this_span { + spans.push_nonintersecting(span); + } + } + Useful(spans) + } + x => x, + } + } + + /// After calculating usefulness after a specialization, call this to recontruct a usefulness + /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged + /// with the results of specializing with the other constructors. fn apply_constructor<'p>( self, pcx: PatCtxt<'_, 'p, 'tcx>, @@ -1003,21 +973,23 @@ fn is_useful<'p, 'tcx>( // If the first pattern is an or-pattern, expand it. let ret = if let Some(vs) = v.expand_or_pat() { + let subspans: Vec<_> = vs.iter().map(|v| v.head().span).collect(); // We expand the or pattern, trying each of its branches in turn and keeping careful track // of possible unreachable sub-branches. let mut matrix = matrix.clone(); let usefulnesses = vs.into_iter().map(|v| { - let span = v.head().span; - let u = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); + let v_span = v.head().span; + let usefulness = + is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); // If pattern has a guard don't add it to the matrix. if !is_under_guard { // We push the already-seen patterns into the matrix in order to detect redundant // branches like `Some(_) | Some(0)`. matrix.push(v); } - (u, span) + usefulness.unsplit_or_pat(v_span, &subspans) }); - Usefulness::merge_or_patterns(usefulnesses) + Usefulness::merge(usefulnesses) } else { // We split the head constructor of `v`. let ctors = v.head_ctor(cx).split(pcx, Some(hir_id)); @@ -1032,7 +1004,7 @@ fn is_useful<'p, 'tcx>( is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) }); - Usefulness::merge_split_constructors(usefulnesses) + Usefulness::merge(usefulnesses) }; debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret); ret From f2743a5db756bfdbe311815fa25a5a3e3fa92b95 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 18 Dec 2020 11:36:10 -0500 Subject: [PATCH 406/719] Add array search aliases --- library/std/src/primitive_docs.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 7aca5451ebc2..48b82fd8b1d3 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -478,8 +478,10 @@ mod prim_unit {} #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} +#[doc(alias = "[]")] +#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases +#[doc(alias = "[T; N]")] #[doc(primitive = "array")] -// /// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the /// non-negative compile-time constant size, `N`. /// From a2fb4b95ddda1c2d622c809e63aa5e158cfb9976 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 16 Dec 2020 18:10:04 -0500 Subject: [PATCH 407/719] Remove `DefPath` from `Visibility` and calculate it on demand --- src/librustdoc/clean/mod.rs | 19 ++++---- src/librustdoc/clean/types.rs | 4 +- src/librustdoc/html/format.rs | 11 +++-- src/librustdoc/html/render/mod.rs | 74 +++++++++++++++++------------- src/librustdoc/json/conversions.rs | 30 ++++++------ 5 files changed, 76 insertions(+), 62 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2809e85761d4..0ce689957ca5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1775,25 +1775,28 @@ impl Clean for hir::Visibility<'_> { hir::VisibilityKind::Inherited => Visibility::Inherited, hir::VisibilityKind::Crate(_) => { let krate = DefId::local(CRATE_DEF_INDEX); - Visibility::Restricted(krate, cx.tcx.def_path(krate)) + Visibility::Restricted(krate) } hir::VisibilityKind::Restricted { ref path, .. } => { let path = path.clean(cx); let did = register_res(cx, path.res); - Visibility::Restricted(did, cx.tcx.def_path(did)) + Visibility::Restricted(did) } } } } impl Clean for ty::Visibility { - fn clean(&self, cx: &DocContext<'_>) -> Visibility { + fn clean(&self, _cx: &DocContext<'_>) -> Visibility { match *self { ty::Visibility::Public => Visibility::Public, + // NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private', + // while rustdoc really does mean inherited. That means that for enum variants, such as + // `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc. + // This is the main reason `impl Clean for hir::Visibility` still exists; various parts of clean + // override `tcx.visibility` explicitly to make sure this distinction is captured. ty::Visibility::Invisible => Visibility::Inherited, - ty::Visibility::Restricted(module) => { - Visibility::Restricted(module, cx.tcx.def_path(module)) - } + ty::Visibility::Restricted(module) => Visibility::Restricted(module), } } } @@ -2303,14 +2306,14 @@ impl Clean for (&hir::MacroDef<'_>, Option) { if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", - vis.print_with_space(), + vis.print_with_space(cx.tcx), name, matchers.iter().map(|span| span.to_src(cx)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", - vis.print_with_space(), + vis.print_with_space(cx.tcx), name, matchers .iter() diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 52d023c83cb6..35917924fa68 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1569,11 +1569,11 @@ impl From for PrimitiveType { } } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] crate enum Visibility { Public, Inherited, - Restricted(DefId, rustc_hir::definitions::DefPath), + Restricted(DefId), } impl Visibility { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f80346aa50b4..7b0b219570b9 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -11,6 +11,7 @@ use std::fmt; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; +use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_target::spec::abi::Abi; @@ -1084,18 +1085,18 @@ impl Function<'_> { } impl clean::Visibility { - crate fn print_with_space(&self) -> impl fmt::Display + '_ { + crate fn print_with_space<'tcx>(self, tcx: TyCtxt<'tcx>) -> impl fmt::Display + 'tcx { use rustc_span::symbol::kw; - display_fn(move |f| match *self { + display_fn(move |f| match self { clean::Public => f.write_str("pub "), clean::Inherited => Ok(()), - // If this is `pub(crate)`, `path` will be empty. - clean::Visibility::Restricted(did, _) if did.index == CRATE_DEF_INDEX => { + clean::Visibility::Restricted(did) if did.index == CRATE_DEF_INDEX => { write!(f, "pub(crate) ") } - clean::Visibility::Restricted(did, ref path) => { + clean::Visibility::Restricted(did) => { f.write_str("pub(")?; + let path = tcx.def_path(did); debug!("path={:?}", path); let first_name = path.data[0].data.get_opt_name().expect("modules are always named"); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 67ccc3d4cf8d..76db0205695e 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -164,7 +164,7 @@ crate struct SharedContext<'tcx> { playground: Option, } -impl Context<'_> { +impl<'tcx> Context<'tcx> { fn path(&self, filename: &str) -> PathBuf { // We use splitn vs Path::extension here because we might get a filename // like `style.min.css` and we want to process that into @@ -176,6 +176,10 @@ impl Context<'_> { self.dst.join(&filename) } + fn tcx(&self) -> TyCtxt<'tcx> { + self.shared.tcx + } + fn sess(&self) -> &Session { &self.shared.tcx.sess } @@ -2147,14 +2151,14 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl Some(ref src) => write!( w, "{}extern crate {} as {};", - myitem.visibility.print_with_space(), + myitem.visibility.print_with_space(cx.tcx()), anchor(myitem.def_id, &*src.as_str()), name ), None => write!( w, "{}extern crate {};", - myitem.visibility.print_with_space(), + myitem.visibility.print_with_space(cx.tcx()), anchor(myitem.def_id, &*name.as_str()) ), } @@ -2165,7 +2169,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl write!( w, "{}{}", - myitem.visibility.print_with_space(), + myitem.visibility.print_with_space(cx.tcx()), import.print() ); } @@ -2379,7 +2383,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean:: write!( w, "{vis}const {name}: {typ}", - vis = it.visibility.print_with_space(), + vis = it.visibility.print_with_space(cx.tcx()), name = it.name.as_ref().unwrap(), typ = c.type_.print(), ); @@ -2413,7 +2417,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St write!( w, "{vis}static {mutability}{name}: {typ}

", - vis = it.visibility.print_with_space(), + vis = it.visibility.print_with_space(cx.tcx()), mutability = s.mutability.print_with_space(), name = it.name.as_ref().unwrap(), typ = s.type_.print() @@ -2424,7 +2428,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) { let header_len = format!( "{}{}{}{}{:#}fn {}{:#}", - it.visibility.print_with_space(), + it.visibility.print_with_space(cx.tcx()), f.header.constness.print_with_space(), f.header.asyncness.print_with_space(), f.header.unsafety.print_with_space(), @@ -2439,7 +2443,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: w, "{vis}{constness}{asyncness}{unsafety}{abi}fn \ {name}{generics}{decl}{spotlight}{where_clause}
", - vis = it.visibility.print_with_space(), + vis = it.visibility.print_with_space(cx.tcx()), constness = f.header.constness.print_with_space(), asyncness = f.header.asyncness.print_with_space(), unsafety = f.header.unsafety.print_with_space(), @@ -2565,7 +2569,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra write!( w, "{}{}{}trait {}{}{}", - it.visibility.print_with_space(), + it.visibility.print_with_space(cx.tcx()), t.unsafety.print_with_space(), if t.is_auto { "auto " } else { "" }, it.name.as_ref().unwrap(), @@ -2585,21 +2589,21 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra // FIXME: we should be using a derived_id for the Anchors here write!(w, "{{\n"); for t in &types { - render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait); + render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx); write!(w, ";\n"); } if !types.is_empty() && !consts.is_empty() { w.write_str("\n"); } for t in &consts { - render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait); + render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx); write!(w, ";\n"); } if !consts.is_empty() && !required.is_empty() { w.write_str("\n"); } for (pos, m) in required.iter().enumerate() { - render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait); + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx); write!(w, ";\n"); if pos < required.len() - 1 { @@ -2610,7 +2614,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra w.write_str("\n"); } for (pos, m) in provided.iter().enumerate() { - render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait); + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx); match m.kind { clean::MethodItem(ref inner, _) if !inner.generics.where_predicates.is_empty() => @@ -2659,7 +2663,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); write!(w, "

", id = id,); - render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); + render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx); write!(w, ""); render_stability_since(w, m, t); write_srclink(cx, m, w, cache); @@ -2877,12 +2881,13 @@ fn assoc_const( _default: Option<&String>, link: AssocItemLink<'_>, extra: &str, + cx: &Context<'_>, ) { write!( w, "{}{}const {}: {}", extra, - it.visibility.print_with_space(), + it.visibility.print_with_space(cx.tcx()), naive_assoc_href(it, link), it.name.as_ref().unwrap(), ty.print() @@ -2965,6 +2970,7 @@ fn render_assoc_item( item: &clean::Item, link: AssocItemLink<'_>, parent: ItemType, + cx: &Context<'_>, ) { fn method( w: &mut Buffer, @@ -2974,6 +2980,7 @@ fn render_assoc_item( d: &clean::FnDecl, link: AssocItemLink<'_>, parent: ItemType, + cx: &Context<'_>, ) { let name = meth.name.as_ref().unwrap(); let anchor = format!("#{}.{}", meth.type_(), name); @@ -2994,7 +3001,7 @@ fn render_assoc_item( }; let mut header_len = format!( "{}{}{}{}{}{:#}fn {}{:#}", - meth.visibility.print_with_space(), + meth.visibility.print_with_space(cx.tcx()), header.constness.print_with_space(), header.asyncness.print_with_space(), header.unsafety.print_with_space(), @@ -3016,7 +3023,7 @@ fn render_assoc_item( "{}{}{}{}{}{}{}fn {name}\ {generics}{decl}{spotlight}{where_clause}", if parent == ItemType::Trait { " " } else { "" }, - meth.visibility.print_with_space(), + meth.visibility.print_with_space(cx.tcx()), header.constness.print_with_space(), header.asyncness.print_with_space(), header.unsafety.print_with_space(), @@ -3032,9 +3039,11 @@ fn render_assoc_item( } match item.kind { clean::StrippedItem(..) => {} - clean::TyMethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent), + clean::TyMethodItem(ref m) => { + method(w, item, m.header, &m.generics, &m.decl, link, parent, cx) + } clean::MethodItem(ref m, _) => { - method(w, item, m.header, &m.generics, &m.decl, link, parent) + method(w, item, m.header, &m.generics, &m.decl, link, parent, cx) } clean::AssocConstItem(ref ty, ref default) => assoc_const( w, @@ -3043,6 +3052,7 @@ fn render_assoc_item( default.as_ref(), link, if parent == ItemType::Trait { " " } else { "" }, + cx, ), clean::AssocTypeItem(ref bounds, ref default) => assoc_type( w, @@ -3066,7 +3076,7 @@ fn item_struct( wrap_into_docblock(w, |w| { write!(w, "
");
         render_attributes(w, it, true);
-        render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true);
+        render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx);
         write!(w, "
") }); @@ -3116,7 +3126,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni wrap_into_docblock(w, |w| { write!(w, "
");
         render_attributes(w, it, true);
-        render_union(w, it, Some(&s.generics), &s.fields, "", true);
+        render_union(w, it, Some(&s.generics), &s.fields, "", true, cx);
         write!(w, "
") }); @@ -3165,7 +3175,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum write!( w, "{}enum {}{}{}", - it.visibility.print_with_space(), + it.visibility.print_with_space(cx.tcx()), it.name.as_ref().unwrap(), e.generics.print(), WhereClause { gens: &e.generics, indent: 0, end_newline: true } @@ -3191,7 +3201,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum write!(w, ")"); } clean::VariantKind::Struct(ref s) => { - render_struct(w, v, None, s.struct_type, &s.fields, " ", false); + render_struct(w, v, None, s.struct_type, &s.fields, " ", false, cx); } }, _ => unreachable!(), @@ -3335,11 +3345,12 @@ fn render_struct( fields: &[clean::Item], tab: &str, structhead: bool, + cx: &Context<'_>, ) { write!( w, "{}{}{}", - it.visibility.print_with_space(), + it.visibility.print_with_space(cx.tcx()), if structhead { "struct " } else { "" }, it.name.as_ref().unwrap() ); @@ -3359,7 +3370,7 @@ fn render_struct( w, "\n{} {}{}: {},", tab, - field.visibility.print_with_space(), + field.visibility.print_with_space(cx.tcx()), field.name.as_ref().unwrap(), ty.print() ); @@ -3388,7 +3399,7 @@ fn render_struct( match field.kind { clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), clean::StructFieldItem(ref ty) => { - write!(w, "{}{}", field.visibility.print_with_space(), ty.print()) + write!(w, "{}{}", field.visibility.print_with_space(cx.tcx()), ty.print()) } _ => unreachable!(), } @@ -3416,11 +3427,12 @@ fn render_union( fields: &[clean::Item], tab: &str, structhead: bool, + cx: &Context<'_>, ) { write!( w, "{}{}{}", - it.visibility.print_with_space(), + it.visibility.print_with_space(cx.tcx()), if structhead { "union " } else { "" }, it.name.as_ref().unwrap() ); @@ -3435,7 +3447,7 @@ fn render_union( write!( w, " {}{}: {},\n{}", - field.visibility.print_with_space(), + field.visibility.print_with_space(cx.tcx()), field.name.as_ref().unwrap(), ty.print(), tab @@ -3827,7 +3839,7 @@ fn render_impl( let id = cx.derive_id(format!("{}.{}", item_type, name)); write!(w, "

", id, item_type, extra_class); write!(w, ""); - render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); + render_assoc_item(w, item, link.anchor(&id), ItemType::Impl, cx); write!(w, ""); render_stability_since_raw( w, @@ -3849,7 +3861,7 @@ fn render_impl( clean::AssocConstItem(ref ty, ref default) => { let id = cx.derive_id(format!("{}.{}", item_type, name)); write!(w, "

", id, item_type, extra_class); - assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), ""); + assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "", cx); write!(w, ""); render_stability_since_raw( w, @@ -4074,7 +4086,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, cache: write!( w, " {}type {};\n}}

", - it.visibility.print_with_space(), + it.visibility.print_with_space(cx.tcx()), it.name.as_ref().unwrap(), ); diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 99587f4ec64e..5a8b2cb5da1f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -35,7 +35,7 @@ impl JsonRenderer<'_> { crate_id: def_id.krate.as_u32(), name: name.map(|sym| sym.to_string()), source: self.convert_span(source), - visibility: visibility.into(), + visibility: self.convert_visibility(visibility), docs: attrs.collapsed_doc_value().unwrap_or_default(), links: attrs .links @@ -75,6 +75,19 @@ impl JsonRenderer<'_> { _ => None, } } + + fn convert_visibility(&self, v: clean::Visibility) -> Visibility { + use clean::Visibility::*; + match v { + Public => Visibility::Public, + Inherited => Visibility::Default, + Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate, + Restricted(did) => Visibility::Restricted { + parent: did.into(), + path: self.tcx.def_path(did).to_string_no_crate_verbose(), + }, + } + } } impl From for Deprecation { @@ -85,21 +98,6 @@ impl From for Deprecation { } } -impl From for Visibility { - fn from(v: clean::Visibility) -> Self { - use clean::Visibility::*; - match v { - Public => Visibility::Public, - Inherited => Visibility::Default, - Restricted(did, _) if did.index == CRATE_DEF_INDEX => Visibility::Crate, - Restricted(did, path) => Visibility::Restricted { - parent: did.into(), - path: path.to_string_no_crate_verbose(), - }, - } - } -} - impl From for GenericArgs { fn from(args: clean::GenericArgs) -> Self { use clean::GenericArgs::*; From 35f16c60e7d3fd1b42c90a0fc084689c817345cb Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 1 Dec 2020 17:41:09 -0500 Subject: [PATCH 408/719] Switch compiler/ to intra-doc links rustc_lint and rustc_lint_defs weren't switched because they're included in the compiler book and so can't use intra-doc links. --- compiler/rustc_data_structures/src/graph/iterate/mod.rs | 2 -- compiler/rustc_data_structures/src/sorted_map/index_map.rs | 3 +-- compiler/rustc_errors/src/diagnostic.rs | 2 -- compiler/rustc_index/src/bit_set.rs | 1 - compiler/rustc_mir/src/dataflow/impls/liveness.rs | 2 +- 5 files changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 1634c5863163..09b91083a634 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -149,8 +149,6 @@ struct Event { /// those successors), we will pop off that node's `Settled` event. /// /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms -/// [`NodeStatus`]: ./enum.NodeStatus.html -/// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined pub struct TriColorDepthFirstSearch<'graph, G> where G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index 2bb421a47efa..01cd1cec9245 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -24,8 +24,7 @@ use rustc_index::vec::{Idx, IndexVec}; /// to insert into the middle of the sorted array. Users should avoid mutating this data structure /// in-place. /// -/// [`IndexVec`]: ../../rustc_index/vec/struct.IndexVec.html -/// [`SortedMap`]: ../sorted_map/struct.SortedMap.html +/// [`SortedMap`]: super::SortedMap #[derive(Clone, Debug)] pub struct SortedIndexMultiMap { /// The elements of the map in insertion order. diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 538e1a59ab8d..e61476bf23e1 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -138,8 +138,6 @@ impl Diagnostic { /// /// This span is *not* considered a ["primary span"][`MultiSpan`]; only /// the `Span` supplied when creating the diagnostic is primary. - /// - /// [`MultiSpan`]: ../rustc_span/struct.MultiSpan.html pub fn span_label>(&mut self, span: Span, label: T) -> &mut Self { self.span.push_span_label(span, label.into()); self diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 8e00e54650df..0b501da7cd97 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -27,7 +27,6 @@ pub const WORD_BITS: usize = WORD_BYTES * 8; /// to or greater than the domain size. All operations that involve two bitsets /// will panic if the bitsets have differing domain sizes. /// -/// [`GrowableBitSet`]: struct.GrowableBitSet.html #[derive(Eq, PartialEq, Decodable, Encodable)] pub struct BitSet { domain_size: usize, diff --git a/compiler/rustc_mir/src/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs index a2b0713cd7d0..85aaff5ab729 100644 --- a/compiler/rustc_mir/src/dataflow/impls/liveness.rs +++ b/compiler/rustc_mir/src/dataflow/impls/liveness.rs @@ -11,7 +11,7 @@ use crate::dataflow::{AnalysisDomain, Backward, GenKill, GenKillAnalysis}; /// exist. See [this `mir-dataflow` test][flow-test] for an example. You almost never want to use /// this analysis without also looking at the results of [`MaybeBorrowedLocals`]. /// -/// [`MaybeBorrowedLocals`]: ../struct.MaybeBorrowedLocals.html +/// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals /// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis pub struct MaybeLiveLocals; From 328fcee4af7aed31343244206abb7dff25106d04 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Fri, 18 Dec 2020 13:24:55 -0500 Subject: [PATCH 409/719] Make BoundRegion have a kind of BoungRegionKind --- .../rustc_codegen_cranelift/src/abi/mod.rs | 2 +- .../src/infer/canonical/canonicalizer.rs | 3 +- .../src/infer/canonical/substitute.rs | 2 +- .../src/infer/error_reporting/mod.rs | 6 +- .../nice_region_error/find_anon_type.rs | 8 +-- .../error_reporting/nice_region_error/util.rs | 8 +-- .../src/infer/higher_ranked/mod.rs | 4 +- compiler/rustc_infer/src/infer/mod.rs | 5 +- .../rustc_infer/src/infer/nll_relate/mod.rs | 2 +- compiler/rustc_middle/src/ich/impls_ty.rs | 6 +- compiler/rustc_middle/src/infer/canonical.rs | 7 +- compiler/rustc_middle/src/ty/context.rs | 6 +- compiler/rustc_middle/src/ty/error.rs | 8 +-- compiler/rustc_middle/src/ty/fold.rs | 57 +++++++--------- compiler/rustc_middle/src/ty/layout.rs | 3 +- compiler/rustc_middle/src/ty/mod.rs | 6 +- compiler/rustc_middle/src/ty/print/pretty.rs | 18 ++--- .../rustc_middle/src/ty/structural_impls.rs | 8 +-- compiler/rustc_middle/src/ty/sty.rs | 32 +++++---- compiler/rustc_middle/src/ty/util.rs | 3 +- .../src/borrow_check/diagnostics/mod.rs | 4 +- .../borrow_check/diagnostics/region_errors.rs | 2 +- .../borrow_check/diagnostics/region_name.rs | 6 +- .../src/borrow_check/universal_regions.rs | 4 +- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- compiler/rustc_traits/src/chalk/db.rs | 12 ++-- compiler/rustc_traits/src/chalk/lowering.rs | 66 ++++++++----------- compiler/rustc_traits/src/chalk/mod.rs | 2 +- compiler/rustc_typeck/src/astconv/mod.rs | 10 +-- .../src/check/generator_interior.rs | 3 +- compiler/rustc_typeck/src/check/intrinsic.rs | 19 +++--- compiler/rustc_typeck/src/collect.rs | 2 +- src/librustdoc/clean/mod.rs | 4 +- src/librustdoc/clean/utils.rs | 4 +- .../escape-argument-callee.stderr | 2 +- .../escape-argument.stderr | 2 +- ...pagate-approximated-fail-no-postdom.stderr | 2 +- .../propagate-approximated-ref.stderr | 2 +- ...er-to-static-comparing-against-free.stderr | 4 +- ...oximated-shorter-to-static-no-bound.stderr | 2 +- ...mated-shorter-to-static-wrong-bound.stderr | 2 +- .../propagate-approximated-val.stderr | 2 +- .../propagate-despite-same-free-region.stderr | 2 +- ...ail-to-approximate-longer-no-bounds.stderr | 2 +- ...-to-approximate-longer-wrong-bounds.stderr | 2 +- .../return-wrong-bound-region.stderr | 2 +- ...ram-closure-approximate-lower-bound.stderr | 4 +- 47 files changed, 183 insertions(+), 181 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index aee274ab4a82..76e1987459f8 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -64,7 +64,7 @@ pub(crate) fn fn_sig_for_fn_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let env_region = ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrEnv }); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); let pin_did = tcx.require_lang_item(rustc_hir::LangItem::Pin, None); diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 8a60b196e5e6..9002d251f123 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -625,7 +625,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { let var = self.canonical_var(info, r.into()); - let region = ty::ReLateBound(self.binder_index, ty::BoundRegion::BrAnon(var.as_u32())); + let br = ty::BoundRegion { kind: ty::BrAnon(var.as_u32()) }; + let region = ty::ReLateBound(self.binder_index, br); self.tcx().mk_region(region) } diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index cd4f1fa3bc30..387f480814ae 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -87,6 +87,6 @@ where c => bug!("{:?} is a const but value is {:?}", bound_ct, c), }; - tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c).0 + tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 18e1465c0e6e..6b7edde9a67a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -165,7 +165,9 @@ fn msg_span_from_early_bound_and_free_regions( } (format!("the lifetime `{}` as defined on", br.name), sp) } - ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => { + ty::ReFree(ty::FreeRegion { + bound_region: ty::BoundRegionKind::BrNamed(_, name), .. + }) => { let mut sp = sm.guess_head_span(tcx.hir().span(node)); if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) @@ -2279,7 +2281,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, var_origin: RegionVariableOrigin, ) -> DiagnosticBuilder<'tcx> { - let br_string = |br: ty::BoundRegion| { + let br_string = |br: ty::BoundRegionKind| { let mut s = match br { ty::BrNamed(_, name) => name.to_string(), _ => String::new(), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index eb1521f05657..b014b9832e78 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub(super) fn find_anon_type( &self, region: Region<'tcx>, - br: &ty::BoundRegion, + br: &ty::BoundRegionKind, ) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> { if let Some(anon_reg) = self.tcx().is_suitable_region(region) { let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id); @@ -56,7 +56,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn find_component_for_bound_region( &self, arg: &'tcx hir::Ty<'tcx>, - br: &ty::BoundRegion, + br: &ty::BoundRegionKind, ) -> Option<&'tcx hir::Ty<'tcx>> { let mut nested_visitor = FindNestedTypeVisitor { tcx: self.tcx(), @@ -80,7 +80,7 @@ struct FindNestedTypeVisitor<'tcx> { tcx: TyCtxt<'tcx>, // The bound_region corresponding to the Refree(freeregion) // associated with the anonymous region we are looking for. - bound_region: ty::BoundRegion, + bound_region: ty::BoundRegionKind, // The type where the anonymous lifetime appears // for e.g., Vec<`&u8`> and <`&u8`> found_type: Option<&'tcx hir::Ty<'tcx>>, @@ -207,7 +207,7 @@ impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { struct TyPathVisitor<'tcx> { tcx: TyCtxt<'tcx>, found_it: bool, - bound_region: ty::BoundRegion, + bound_region: ty::BoundRegionKind, current_index: ty::DebruijnIndex, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 61fad8863e7c..17a56046a5cc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -14,8 +14,8 @@ pub(super) struct AnonymousParamInfo<'tcx> { pub param: &'tcx hir::Param<'tcx>, /// The type corresponding to the anonymous region parameter. pub param_ty: Ty<'tcx>, - /// The ty::BoundRegion corresponding to the anonymous region. - pub bound_region: ty::BoundRegion, + /// The ty::BoundRegionKind corresponding to the anonymous region. + pub bound_region: ty::BoundRegionKind, /// The `Span` of the parameter type. pub param_ty_span: Span, /// Signals that the argument is the first parameter in the declaration. @@ -43,7 +43,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), ty::ReEarlyBound(ebr) => ( self.tcx().parent(ebr.def_id).unwrap(), - ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), + ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name), ), _ => return None, // not a free region }; @@ -145,7 +145,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub(super) fn is_return_type_anon( &self, scope_def_id: LocalDefId, - br: ty::BoundRegion, + br: ty::BoundRegionKind, decl: &hir::FnDecl<'_>, ) -> Option { let ret_ty = self.tcx().type_of(scope_def_id); diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 39043980dc4f..e794903fca3a 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -77,10 +77,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // (i.e., if there are no placeholders). let next_universe = self.universe().next_universe(); - let fld_r = |br| { + let fld_r = |br: ty::BoundRegion| { self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion { universe: next_universe, - name: br, + name: br.kind, })) }; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6affe0e5463d..069f708856ea 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -450,7 +450,7 @@ pub enum RegionVariableOrigin { /// Region variables created for bound regions /// in a function or method that is called - LateBoundRegion(Span, ty::BoundRegion, LateBoundRegionConversionTime), + LateBoundRegion(Span, ty::BoundRegionKind, LateBoundRegionConversionTime), UpvarRegion(ty::UpvarId, Span), @@ -1421,7 +1421,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { where T: TypeFoldable<'tcx>, { - let fld_r = |br| self.next_region_var(LateBoundRegion(span, br, lbrct)); + let fld_r = + |br: ty::BoundRegion| self.next_region_var(LateBoundRegion(span, br.kind, lbrct)); let fld_t = |_| { self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 0b2847658f71..971e0e1863bd 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -176,7 +176,7 @@ where universe }); - let placeholder = ty::PlaceholderRegion { universe, name: br }; + let placeholder = ty::PlaceholderRegion { universe, name: br.kind }; delegate.next_placeholder_region(placeholder) } else { delegate.next_existential_region_var(true) diff --git a/compiler/rustc_middle/src/ich/impls_ty.rs b/compiler/rustc_middle/src/ich/impls_ty.rs index 69bb4e23c4c0..573b514e8445 100644 --- a/compiler/rustc_middle/src/ich/impls_ty.rs +++ b/compiler/rustc_middle/src/ich/impls_ty.rs @@ -70,16 +70,16 @@ impl<'a> HashStable> for ty::RegionKind { ty::ReEmpty(universe) => { universe.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BrAnon(i)) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrAnon(i) }) => { db.hash_stable(hcx, hasher); i.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BrNamed(def_id, name)) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrNamed(def_id, name) }) => { db.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BrEnv) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrEnv }) => { db.hash_stable(hcx, hasher); } ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 6e5f95c45274..e106db38b2c9 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -323,9 +323,10 @@ impl<'tcx> CanonicalVarValues<'tcx> { GenericArgKind::Type(..) => { tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into() } - GenericArgKind::Lifetime(..) => tcx - .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))) - .into(), + GenericArgKind::Lifetime(..) => { + let br = ty::BoundRegion { kind: ty::BrAnon(i) }; + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() + } GenericArgKind::Const(ct) => tcx .mk_const(ty::Const { ty: ct.ty, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index adf02412b96d..ed91c4ffd88d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -889,7 +889,7 @@ pub struct FreeRegionInfo { // `LocalDefId` corresponding to FreeRegion pub def_id: LocalDefId, // the bound region corresponding to FreeRegion - pub boundregion: ty::BoundRegion, + pub boundregion: ty::BoundRegionKind, // checks if bound region is in Impl Item pub is_impl_item: bool, } @@ -1411,7 +1411,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - // Returns the `DefId` and the `BoundRegion` corresponding to the given region. + // Returns the `DefId` and the `BoundRegionKind` corresponding to the given region. pub fn is_suitable_region(self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { @@ -1419,7 +1419,7 @@ impl<'tcx> TyCtxt<'tcx> { } ty::ReEarlyBound(ref ebr) => ( self.parent(ebr.def_id).unwrap().expect_local(), - ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), + ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name), ), _ => return None, // not a free region }; diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 97af927dfcba..fc02e78b2fad 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -1,6 +1,6 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::ty::diagnostics::suggest_constraining_type_param; -use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt}; +use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; use rustc_ast as ast; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, DiagnosticBuilder}; @@ -42,8 +42,8 @@ pub enum TypeError<'tcx> { ArgCount, RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), - RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>), - RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>), + RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), + RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>), RegionsPlaceholderMismatch, Sorts(ExpectedFound>), @@ -94,7 +94,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { } } - let br_string = |br: ty::BoundRegion| match br { + let br_string = |br: ty::BoundRegionKind| match br { ty::BrNamed(_, name) => format!(" {}", name), _ => String::new(), }; diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 13c8d6b2bccb..382f3708c3d4 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -534,8 +534,8 @@ impl<'tcx> TyCtxt<'tcx> { /// results returned by the closure; the closure is expected to /// return a free region (relative to this binder), and hence the /// binder is removed in the return type. The closure is invoked - /// once for each unique `BoundRegion`; multiple references to the - /// same `BoundRegion` will reuse the previous result. A map is + /// once for each unique `BoundRegionKind`; multiple references to the + /// same `BoundRegionKind` will reuse the previous result. A map is /// returned at the end with each bound region and the free region /// that replaced it. /// @@ -544,7 +544,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn replace_late_bound_regions( self, value: Binder, - fld_r: F, + mut fld_r: F, ) -> (T, BTreeMap>) where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, @@ -555,7 +555,10 @@ impl<'tcx> TyCtxt<'tcx> { let fld_c = |bound_ct, ty| { self.mk_const(ty::Const { val: ty::ConstKind::Bound(ty::INNERMOST, bound_ct), ty }) }; - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) + let mut region_map = BTreeMap::new(); + let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br)); + let value = self.replace_escaping_bound_vars(value.skip_binder(), real_fld_r, fld_t, fld_c); + (value, region_map) } /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping @@ -567,34 +570,18 @@ impl<'tcx> TyCtxt<'tcx> { mut fld_r: F, mut fld_t: G, mut fld_c: H, - ) -> (T, BTreeMap>) + ) -> T where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx>, { - use rustc_data_structures::fx::FxHashMap; - - let mut region_map = BTreeMap::new(); - let mut type_map = FxHashMap::default(); - let mut const_map = FxHashMap::default(); - if !value.has_escaping_bound_vars() { - (value, region_map) + value } else { - let mut real_fld_r = |br| *region_map.entry(br).or_insert_with(|| fld_r(br)); - - let mut real_fld_t = - |bound_ty| *type_map.entry(bound_ty).or_insert_with(|| fld_t(bound_ty)); - - let mut real_fld_c = - |bound_ct, ty| *const_map.entry(bound_ct).or_insert_with(|| fld_c(bound_ct, ty)); - - let mut replacer = - BoundVarReplacer::new(self, &mut real_fld_r, &mut real_fld_t, &mut real_fld_c); - let result = value.fold_with(&mut replacer); - (result, region_map) + let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t, &mut fld_c); + value.fold_with(&mut replacer) } } @@ -604,7 +591,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn replace_bound_vars( self, value: Binder, - fld_r: F, + mut fld_r: F, fld_t: G, fld_c: H, ) -> (T, BTreeMap>) @@ -614,7 +601,10 @@ impl<'tcx> TyCtxt<'tcx> { H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx>, { - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) + let mut region_map = BTreeMap::new(); + let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br)); + let value = self.replace_escaping_bound_vars(value.skip_binder(), real_fld_r, fld_t, fld_c); + (value, region_map) } /// Replaces any late-bound regions bound in `value` with @@ -626,7 +616,7 @@ impl<'tcx> TyCtxt<'tcx> { self.replace_late_bound_regions(value, |br| { self.mk_region(ty::ReFree(ty::FreeRegion { scope: all_outlive_scope, - bound_region: br, + bound_region: br.kind, })) }) .0 @@ -639,7 +629,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_constrained_late_bound_regions( self, value: &Binder, - ) -> FxHashSet + ) -> FxHashSet where T: TypeFoldable<'tcx>, { @@ -650,7 +640,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_referenced_late_bound_regions( self, value: &Binder, - ) -> FxHashSet + ) -> FxHashSet where T: TypeFoldable<'tcx>, { @@ -661,7 +651,7 @@ impl<'tcx> TyCtxt<'tcx> { self, value: &Binder, just_constraint: bool, - ) -> FxHashSet + ) -> FxHashSet where T: TypeFoldable<'tcx>, { @@ -695,7 +685,8 @@ impl<'tcx> TyCtxt<'tcx> { let mut counter = 0; Binder::bind( self.replace_late_bound_regions(sig, |_| { - let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(counter))); + let br = ty::BoundRegion { kind: ty::BrAnon(counter) }; + let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br)); counter += 1; r }) @@ -955,7 +946,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { /// into a hash set. struct LateBoundRegionsCollector { current_index: ty::DebruijnIndex, - regions: FxHashSet, + regions: FxHashSet, /// `true` if we only want regions that are known to be /// "constrained" when you equate this type with another type. In @@ -1014,7 +1005,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { if let ty::ReLateBound(debruijn, br) = *r { if debruijn == self.current_index { - self.regions.insert(br); + self.regions.insert(br.kind); } } ControlFlow::CONTINUE diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d6b3afb3be3d..b545b92c9252 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2455,7 +2455,8 @@ impl<'tcx> ty::Instance<'tcx> { ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let br = ty::BoundRegion { kind: ty::BrEnv }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); let pin_did = tcx.require_lang_item(LangItem::Pin, None); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7428f34153c8..27a5aacb6749 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -51,13 +51,13 @@ use std::ops::{ControlFlow, Range}; use std::ptr; use std::str; -pub use self::sty::BoundRegion::*; +pub use self::sty::BoundRegionKind::*; pub use self::sty::InferTy::*; pub use self::sty::RegionKind; pub use self::sty::RegionKind::*; pub use self::sty::TyKind::*; pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar}; -pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; +pub use self::sty::{BoundRegion, BoundRegionKind, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts}; pub use self::sty::{ClosureSubstsParts, GeneratorSubstsParts}; @@ -1597,7 +1597,7 @@ where } } -pub type PlaceholderRegion = Placeholder; +pub type PlaceholderRegion = Placeholder; pub type PlaceholderType = Placeholder; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 09ef69e9690a..9b178d9d2bd0 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -125,13 +125,13 @@ pub struct RegionHighlightMode { highlight_regions: [Option<(ty::RegionKind, usize)>; 3], /// If enabled, when printing a "free region" that originated from - /// the given `ty::BoundRegion`, print it as "`'1`". Free regions that would ordinarily + /// the given `ty::BoundRegionKind`, print it as "`'1`". Free regions that would ordinarily /// have names print as normal. /// /// This is used when you have a signature like `fn foo(x: &u32, /// y: &'a u32)` and we want to give a name to the region of the /// reference `x`. - highlight_bound_region: Option<(ty::BoundRegion, usize)>, + highlight_bound_region: Option<(ty::BoundRegionKind, usize)>, } impl RegionHighlightMode { @@ -175,7 +175,7 @@ impl RegionHighlightMode { /// Highlight the given bound region. /// We can only highlight one bound region at a time. See /// the field `highlight_bound_region` for more detailed notes. - pub fn highlighting_bound_region(&mut self, br: ty::BoundRegion, number: usize) { + pub fn highlighting_bound_region(&mut self, br: ty::BoundRegionKind, number: usize) { assert!(self.highlight_bound_region.is_none()); self.highlight_bound_region = Some((br, number)); } @@ -1611,7 +1611,7 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { data.name != kw::Invalid && data.name != kw::UnderscoreLifetime } - ty::ReLateBound(_, br) + ty::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { @@ -1690,7 +1690,7 @@ impl FmtPrinter<'_, '_, F> { return Ok(self); } } - ty::ReLateBound(_, br) + ty::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { @@ -1779,10 +1779,10 @@ impl FmtPrinter<'_, 'tcx, F> { let mut region_index = self.region_index; let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| { let _ = start_or_continue(&mut self, "for<", ", "); - let br = match br { + let kind = match br.kind { ty::BrNamed(_, name) => { let _ = write!(self, "{}", name); - br + br.kind } ty::BrAnon(_) | ty::BrEnv => { let name = loop { @@ -1796,7 +1796,7 @@ impl FmtPrinter<'_, 'tcx, F> { ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name) } }; - self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)) + self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind })) }); start_or_continue(&mut self, "", "> ")?; @@ -1840,7 +1840,7 @@ impl FmtPrinter<'_, 'tcx, F> { struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - if let ty::ReLateBound(_, ty::BrNamed(_, name)) = *r { + if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name) }) = *r { self.0.insert(name); } r.super_visit_with(self) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 8af5792b3fb6..7a1ca6a6c2bf 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -65,7 +65,7 @@ impl fmt::Debug for ty::adjustment::Adjustment<'tcx> { } } -impl fmt::Debug for ty::BoundRegion { +impl fmt::Debug for ty::BoundRegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ty::BrAnon(n) => write!(f, "BrAnon({:?})", n), @@ -308,13 +308,13 @@ TrivialTypeFoldableAndLiftImpls! { crate::traits::Reveal, crate::ty::adjustment::AutoBorrowMutability, crate::ty::AdtKind, - // Including `BoundRegion` is a *bit* dubious, but direct + // Including `BoundRegionKind` is a *bit* dubious, but direct // references to bound region appear in `ty::Error`, and aren't // really meant to be folded. In general, we can only fold a fully // general `Region`. - crate::ty::BoundRegion, + crate::ty::BoundRegionKind, crate::ty::AssocItem, - crate::ty::Placeholder, + crate::ty::Placeholder, crate::ty::ClosureKind, crate::ty::FreeRegion, crate::ty::InferTy, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 62d1dda37d67..81ee05d4b23c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -40,12 +40,12 @@ pub struct TypeAndMut<'tcx> { /// at least as big as the scope `fr.scope`". pub struct FreeRegion { pub scope: DefId, - pub bound_region: BoundRegion, + pub bound_region: BoundRegionKind, } #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] #[derive(HashStable)] -pub enum BoundRegion { +pub enum BoundRegionKind { /// An anonymous region parameter for a given fn (&T) BrAnon(u32), @@ -60,26 +60,34 @@ pub enum BoundRegion { BrEnv, } -impl BoundRegion { - pub fn is_named(&self) -> bool { - match *self { - BoundRegion::BrNamed(_, name) => name != kw::UnderscoreLifetime, - _ => false, - } - } +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] +#[derive(HashStable)] +pub struct BoundRegion { + pub kind: BoundRegionKind, +} +impl BoundRegion { /// When canonicalizing, we replace unbound inference variables and free /// regions with anonymous late bound regions. This method asserts that /// we have an anonymous late bound region, which hence may refer to /// a canonical variable. pub fn assert_bound_var(&self) -> BoundVar { - match *self { - BoundRegion::BrAnon(var) => BoundVar::from_u32(var), + match self.kind { + BoundRegionKind::BrAnon(var) => BoundVar::from_u32(var), _ => bug!("bound region is not anonymous"), } } } +impl BoundRegionKind { + pub fn is_named(&self) -> bool { + match *self { + BoundRegionKind::BrNamed(_, name) => name != kw::UnderscoreLifetime, + _ => false, + } + } +} + /// N.B., if you change this, you'll probably want to change the corresponding /// AST structure in `librustc_ast/ast.rs` as well. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)] @@ -1551,7 +1559,7 @@ impl RegionKind { pub fn has_name(&self) -> bool { match *self { RegionKind::ReEarlyBound(ebr) => ebr.has_name(), - RegionKind::ReLateBound(_, br) => br.is_named(), + RegionKind::ReLateBound(_, br) => br.kind.is_named(), RegionKind::ReFree(fr) => fr.bound_region.is_named(), RegionKind::ReStatic => true, RegionKind::ReVar(..) => false, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 25787f005aa2..a64580336ad6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -503,7 +503,8 @@ impl<'tcx> TyCtxt<'tcx> { closure_substs: SubstsRef<'tcx>, ) -> Option>> { let closure_ty = self.mk_closure(closure_def_id, closure_substs); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let br = ty::BoundRegion { kind: ty::BrEnv }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); let closure_kind_ty = closure_substs.as_closure().kind_ty(); let closure_kind = closure_kind_ty.to_opt_closure_kind()?; let env_ty = match closure_kind { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 41f3edaa4138..81571fd73003 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -496,7 +496,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // lifetimes without names with the value `'0`. match ty.kind() { ty::Ref( - ty::RegionKind::ReLateBound(_, br) + ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), _, _, @@ -517,7 +517,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let region = match ty.kind() { ty::Ref(region, _, _) => { match region { - ty::RegionKind::ReLateBound(_, br) + ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { printer.region_highlight_mode.highlighting_bound_region(*br, counter) } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs index e22dab015170..78da43c31c0f 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// Returns `true` if a closure is inferred to be an `FnMut` closure. fn is_closure_fn_mut(&self, fr: RegionVid) -> bool { if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) { - if let ty::BoundRegion::BrEnv = free_region.bound_region { + if let ty::BoundRegionKind::BrEnv = free_region.bound_region { if let DefiningTy::Closure(_, substs) = self.regioncx.universal_regions().defining_ty { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index 6211cf8a9da8..cbca012824f8 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -281,7 +281,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } ty::ReFree(free_region) => match free_region.bound_region { - ty::BoundRegion::BrNamed(region_def_id, name) => { + ty::BoundRegionKind::BrNamed(region_def_id, name) => { // Get the span to point to, even if we don't use the name. let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP); debug!( @@ -307,7 +307,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } } - ty::BoundRegion::BrEnv => { + ty::BoundRegionKind::BrEnv => { let def_ty = self.regioncx.universal_regions().defining_ty; if let DefiningTy::Closure(_, substs) = def_ty { @@ -349,7 +349,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } } - ty::BoundRegion::BrAnon(_) => None, + ty::BoundRegionKind::BrAnon(_) => None, }, ty::ReLateBound(..) diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs index 7ad38a1f82cd..c1a0d9856b7e 100644 --- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs +++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs @@ -700,7 +700,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br); let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { scope: all_outlive_scope.to_def_id(), - bound_region: br, + bound_region: br.kind, })); let region_vid = self.next_nll_region_var(origin); indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); @@ -795,7 +795,7 @@ fn for_each_late_bound_region_defined_on<'tcx>( let region_def_id = tcx.hir().local_def_id(hir_id); let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion { scope: fn_def_id, - bound_region: ty::BoundRegion::BrNamed(region_def_id.to_def_id(), name), + bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name), })); f(liberated_region); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0294fb23c568..7b6e6ad0696a 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -319,7 +319,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { // Late-bound lifetimes use indices starting at 1, // see `BinderLevel` for more details. - ty::ReLateBound(debruijn, ty::BrAnon(i)) => { + ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i) }) => { let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; let depth = binder.lifetime_depths.start + i; diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index b1b9ef343d5a..1893d74335ab 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -648,7 +648,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t /// Creates a `InternalSubsts` that maps each generic parameter to a higher-ranked /// var bound at index `0`. For types, we use a `BoundVar` index equal to -/// the type parameter index. For regions, we use the `BoundRegion::BrNamed` +/// the type parameter index. For regions, we use the `BoundRegionKind::BrNamed` /// variant (which has a `DefId`). fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { InternalSubsts::for_item(tcx, def_id, |param, substs| match param.kind { @@ -662,12 +662,10 @@ fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { )) .into(), - ty::GenericParamDefKind::Lifetime => tcx - .mk_region(ty::RegionKind::ReLateBound( - ty::INNERMOST, - ty::BoundRegion::BrAnon(substs.len() as u32), - )) - .into(), + ty::GenericParamDefKind::Lifetime => { + let br = ty::BoundRegion { kind: ty::BrAnon(substs.len() as u32) }; + tcx.mk_region(ty::RegionKind::ReLateBound(ty::INNERMOST, br)).into() + } ty::GenericParamDefKind::Const => tcx .mk_const(ty::Const { diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 3a747b09cd4c..8aa68e533a2e 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -35,9 +35,7 @@ use rustc_ast::ast; use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner}; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{ - self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor, -}; +use rustc_middle::ty::{self, Binder, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_span::def_id::DefId; use chalk_ir::{FnSig, ForeignDefId}; @@ -444,15 +442,15 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'t ReEarlyBound(_) => { panic!("Should have already been substituted."); } - ReLateBound(db, br) => match br { - ty::BoundRegion::BrAnon(var) => { + ReLateBound(db, br) => match br.kind { + ty::BoundRegionKind::BrAnon(var) => { chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( chalk_ir::DebruijnIndex::new(db.as_u32()), - *var as usize, + var as usize, )) .intern(interner) } - ty::BoundRegion::BrNamed(_def_id, _name) => unimplemented!(), + ty::BoundRegionKind::BrNamed(_def_id, _name) => unimplemented!(), ty::BrEnv => unimplemented!(), }, ReFree(_) => unimplemented!(), @@ -477,13 +475,13 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime ty::RegionKind::ReLateBound( ty::DebruijnIndex::from_u32(var.debruijn.depth()), - ty::BoundRegion::BrAnon(var.index as u32), + ty::BoundRegion { kind: ty::BrAnon(var.index as u32) }, ), chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), chalk_ir::LifetimeData::Placeholder(p) => { ty::RegionKind::RePlaceholder(ty::Placeholder { universe: ty::UniverseIndex::from_usize(p.ui.counter), - name: ty::BoundRegion::BrAnon(p.idx as u32), + name: ty::BoundRegionKind::BrAnon(p.idx as u32), }) } chalk_ir::LifetimeData::Static => ty::RegionKind::ReStatic, @@ -805,7 +803,7 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound } /// To collect bound vars, we have to do two passes. In the first pass, we -/// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then +/// collect all `BoundRegionKind`s and `ty::Bound`s. In the second pass, we then /// replace `BrNamed` into `BrAnon`. The two separate passes are important, /// since we can only replace `BrNamed` with `BrAnon`s with indices *after* all /// "real" `BrAnon`s. @@ -893,14 +891,14 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow { match r { - ty::ReLateBound(index, br) if *index == self.binder_index => match br { - ty::BoundRegion::BrNamed(def_id, _name) => { - if self.named_parameters.iter().find(|d| *d == def_id).is_none() { - self.named_parameters.push(*def_id); + ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind { + ty::BoundRegionKind::BrNamed(def_id, _name) => { + if self.named_parameters.iter().find(|d| **d == def_id).is_none() { + self.named_parameters.push(def_id); } } - ty::BoundRegion::BrAnon(var) => match self.parameters.entry(*var) { + ty::BoundRegionKind::BrAnon(var) => match self.parameters.entry(var) { Entry::Vacant(entry) => { entry.insert(chalk_ir::VariableKind::Lifetime); } @@ -926,7 +924,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { } } -/// This is used to replace `BoundRegion::BrNamed` with `BoundRegion::BrAnon`. +/// This is used to replace `BoundRegionKind::BrNamed` with `BoundRegionKind::BrAnon`. /// Note: we assume that we will always have room for more bound vars. (i.e. we /// won't ever hit the `u32` limit in `BrAnon`s). struct NamedBoundVarSubstitutor<'a, 'tcx> { @@ -955,20 +953,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { match r { - ty::ReLateBound(index, br) if *index == self.binder_index => match br { - ty::BoundRegion::BrNamed(def_id, _name) => { - match self.named_parameters.get(def_id) { - Some(idx) => { - return self.tcx.mk_region(RegionKind::ReLateBound( - *index, - BoundRegion::BrAnon(*idx), - )); - } - None => panic!("Missing `BrNamed`."), + ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind { + ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { + Some(idx) => { + let new_br = ty::BoundRegion { kind: ty::BrAnon(*idx) }; + return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br)); } - } + None => panic!("Missing `BrNamed`."), + }, ty::BrEnv => unimplemented!(), - ty::BoundRegion::BrAnon(_) => {} + ty::BrAnon(_) => {} }, _ => (), }; @@ -1044,17 +1038,15 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { // FIXME(chalk) - jackh726 - this currently isn't hit in any tests. // This covers any region variables in a goal, right? ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) { - Some(idx) => self.tcx.mk_region(RegionKind::ReLateBound( - self.binder_index, - BoundRegion::BrAnon(*idx), - )), + Some(idx) => { + let br = ty::BoundRegion { kind: ty::BrAnon(*idx) }; + self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)) + } None => { let idx = self.named_regions.len() as u32; + let br = ty::BoundRegion { kind: ty::BrAnon(idx) }; self.named_regions.insert(_re.def_id, idx); - self.tcx.mk_region(RegionKind::ReLateBound( - self.binder_index, - BoundRegion::BrAnon(idx), - )) + self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)) } }, @@ -1096,7 +1088,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow { match r { ty::RePlaceholder(p) if p.universe == self.universe_index => { - if let ty::BoundRegion::BrAnon(anon) = p.name { + if let ty::BoundRegionKind::BrAnon(anon) = p.name { self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon); } } diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index b117e28875e7..f3a55fec9e46 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -44,7 +44,7 @@ crate fn evaluate_goal<'tcx>( let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder { universe: ty::UniverseIndex::ROOT, - name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder + 1), + name: ty::BoundRegionKind::BrAnon(placeholders_collector.next_anon_region_placeholder + 1), })); let mut params_substitutor = diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 693cd236299a..1648c629186b 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -196,11 +196,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Some(rl::Region::LateBound(debruijn, id, _)) => { let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReLateBound(debruijn, ty::BrNamed(id, name))) + let br = ty::BoundRegion { kind: ty::BrNamed(id, name) }; + tcx.mk_region(ty::ReLateBound(debruijn, br)) } Some(rl::Region::LateBoundAnon(debruijn, index)) => { - tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(index))) + let br = ty::BoundRegion { kind: ty::BrAnon(index) }; + tcx.mk_region(ty::ReLateBound(debruijn, br)) } Some(rl::Region::EarlyBound(index, id, _)) => { @@ -2295,8 +2297,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn validate_late_bound_regions( &self, - constrained_regions: FxHashSet, - referenced_regions: FxHashSet, + constrained_regions: FxHashSet, + referenced_regions: FxHashSet, generate_err: impl Fn(&str) -> rustc_errors::DiagnosticBuilder<'tcx>, ) { for br in referenced_regions.difference(&constrained_regions) { diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 5bc40d617d04..b324e6b7f8e4 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -186,7 +186,8 @@ pub fn resolve_interior<'a, 'tcx>( // which means that none of the regions inside relate to any other, even if // typeck had previously found constraints that would cause them to be related. let folded = fcx.tcx.fold_regions(erased, &mut false, |_, current_depth| { - let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter))); + let br = ty::BoundRegion { kind: ty::BrAnon(counter) }; + let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br)); counter += 1; r }); diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index e2712a303399..6bc598693183 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -116,13 +116,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { - let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let region = tcx + .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrAnon(0) })); + let env_region = + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrEnv })); let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); - ( - tcx.mk_ref(tcx.mk_region(env_region), ty::TypeAndMut { ty: va_list_ty, mutbl }), - va_list_ty, - ) + (tcx.mk_ref(env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) }) }; @@ -320,12 +319,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap()); let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id; + let br = ty::BoundRegion { kind: ty::BrAnon(0) }; ( 1, - vec![tcx.mk_imm_ref( - tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))), - param(0), - )], + vec![ + tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0)), + ], tcx.mk_projection(discriminant_def_id, tcx.mk_substs([param(0).into()].iter())), ) } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index c70554cc6272..731a4da244f2 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -461,7 +461,7 @@ fn get_new_lifetime_name<'tcx>( .collect_referenced_late_bound_regions(&poly_trait_ref) .into_iter() .filter_map(|lt| { - if let ty::BoundRegion::BrNamed(_, name) = lt { + if let ty::BoundRegionKind::BrNamed(_, name) = lt { Some(name.as_str().to_string()) } else { None diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2809e85761d4..9f0d111cc376 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -431,7 +431,9 @@ impl Clean> for ty::RegionKind { fn clean(&self, _cx: &DocContext<'_>) -> Option { match *self { ty::ReStatic => Some(Lifetime::statik()), - ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name)), + ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name) }) => { + Some(Lifetime(name)) + } ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)), ty::ReLateBound(..) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 1ae2e5de82c4..4d525d62c52c 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -104,7 +104,9 @@ fn external_generic_args( .iter() .filter_map(|kind| match kind.unpack() { GenericArgKind::Lifetime(lt) => match lt { - ty::ReLateBound(_, ty::BrAnon(_)) => Some(GenericArg::Lifetime(Lifetime::elided())), + ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrAnon(_) }) => { + Some(GenericArg::Lifetime(Lifetime::elided())) + } _ => lt.clean(cx).map(GenericArg::Lifetime), }, GenericArgKind::Type(_) if skip_self => { diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index 799ed89dcce3..4e122d930fc4 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) i32)), + for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) i32)), (), ] diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index a094fc45178f..44d1d2327fcd 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)), + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32)), (), ] diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index c4f4facae1fb..fa9f994c4fae 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index c1450564c45d..0555f79bcb03 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index e7b8dff4e7ec..0115f5412f21 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -10,7 +10,7 @@ LL | | }) | = note: defining type: case1::{closure#0} with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>)), (), ] @@ -49,7 +49,7 @@ LL | | }) | = note: defining type: case2::{closure#0} with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>)), (), ] = note: number of external vids: 2 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index c7e68d02dcf1..e55d033d2c76 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t2)) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) u32>)), (), ] = note: late-bound region is '_#2r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index abbc76eaf4dd..ac4a4579c9cd 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index c91b514a796c..60dca1baa40e 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index 4ddf6f8323f6..cbb10eb187ed 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 6dc6f4568058..f9f1d8bb6fff 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#2r diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 6bcada5c26c8..1587c28e1bef 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 1da6c6d2c685..44f743310b48 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -6,7 +6,7 @@ LL | expect_sig(|a, b| b); // ought to return `a` | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) i32, (), ] diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 7c0d63c368be..dbf76cd1329c 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -6,7 +6,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); | = note: defining type: generic::::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) T)), (), ] = note: number of external vids: 2 @@ -31,7 +31,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); | = note: defining type: generic_fail::::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) T)), (), ] = note: late-bound region is '_#2r From 6c1fc324b2ebec435c8f2815f25698a6c5ad5314 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Fri, 18 Dec 2020 13:24:55 -0500 Subject: [PATCH 410/719] Make BoundRegion have a kind of BoungRegionKind --- src/abi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index aee274ab4a82..76e1987459f8 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -64,7 +64,7 @@ pub(crate) fn fn_sig_for_fn_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let env_region = ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrEnv }); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); let pin_did = tcx.require_lang_item(rustc_hir::LangItem::Pin, None); From cce4c72c5a5517423e1ad1a4087861c49c6ab43a Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Fri, 18 Dec 2020 20:55:46 +0000 Subject: [PATCH 411/719] Update RELEASES.md --- RELEASES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index f9dadbec5772..0cfbb62c85e4 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -76,6 +76,8 @@ Compatibility Notes - [Macros that end with a semi-colon are now treated as statements even if they expand to nothing.][78376] - [Rustc will now check for the validity of some built-in attributes on enum variants.][77015] Previously such invalid or unused attributes could be ignored. +- Leading whitespace is stripped more uniformly in documentation comments, which may change behavior. You + read [this post about the changes][rustdoc-ws-post] for more details. Internal Only ------------- @@ -120,6 +122,7 @@ related tools. [`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html [`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready [`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending +[rustdoc-ws-post]: https://blog.guillaume-gomez.fr/articles/2020-11-11+New+doc+comment+handling+in+rustdoc Version 1.48.0 (2020-11-19) ========================== From af3b1cb0b55ed28c0f4a500e42699603edf199e7 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Wed, 16 Dec 2020 21:13:29 -0500 Subject: [PATCH 412/719] Change potentially_qualified to be defined on Binder --- .../src/infer/canonical/query_response.rs | 11 +++++---- compiler/rustc_middle/src/ty/mod.rs | 24 +++++++++++-------- compiler/rustc_typeck/src/collect.rs | 23 +++++++++++------- compiler/rustc_typeck/src/outlives/mod.rs | 10 ++++---- 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index c8d66cbb695d..71ce50f74537 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -525,10 +525,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { result_subst: &'a CanonicalVarValues<'tcx>, ) -> impl Iterator> + 'a + Captures<'tcx> { unsubstituted_region_constraints.iter().map(move |&constraint| { - let ty::OutlivesPredicate(k1, r2) = - substitute_value(self.tcx, result_subst, constraint).skip_binder(); + let predicate = substitute_value(self.tcx, result_subst, constraint); + let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder(); - let predicate = match k1.unpack() { + let atom = match k1.unpack() { GenericArgKind::Lifetime(r1) => { ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2)) } @@ -540,8 +540,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // encounter this branch. span_bug!(cause.span, "unexpected const outlives {:?}", constraint); } - } - .potentially_quantified(self.tcx, ty::PredicateKind::ForAll); + }; + let predicate = + predicate.rebind(atom).potentially_quantified(self.tcx, ty::PredicateKind::ForAll); Obligation::new(cause.clone(), param_env, predicate) }) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7428f34153c8..b0f02dee59b2 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1149,17 +1149,16 @@ pub enum PredicateAtom<'tcx> { TypeWellFormedFromEnv(Ty<'tcx>), } -impl<'tcx> PredicateAtom<'tcx> { +impl<'tcx> Binder> { /// Wraps `self` with the given qualifier if this predicate has any unbound variables. pub fn potentially_quantified( self, tcx: TyCtxt<'tcx>, qualifier: impl FnOnce(Binder>) -> PredicateKind<'tcx>, ) -> Predicate<'tcx> { - if self.has_escaping_bound_vars() { - qualifier(Binder::bind(self)) - } else { - PredicateKind::Atom(self) + match self.no_bound_vars() { + Some(atom) => PredicateKind::Atom(atom), + None => qualifier(self), } .to_predicate(tcx) } @@ -1252,7 +1251,11 @@ impl<'tcx> Predicate<'tcx> { let substs = trait_ref.skip_binder().substs; let pred = self.skip_binders(); let new = pred.subst(tcx, substs); - if new != pred { new.potentially_quantified(tcx, PredicateKind::ForAll) } else { self } + if new != pred { + trait_ref.rebind(new).potentially_quantified(tcx, PredicateKind::ForAll) + } else { + self + } } } @@ -1403,28 +1406,29 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateAtom::Trait(self.value.skip_binder(), self.constness) + self.value + .map_bound(|value| PredicateAtom::Trait(value, self.constness)) .potentially_quantified(tcx, PredicateKind::ForAll) } } impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateAtom::RegionOutlives(self.skip_binder()) + self.map_bound(|value| PredicateAtom::RegionOutlives(value)) .potentially_quantified(tcx, PredicateKind::ForAll) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateAtom::TypeOutlives(self.skip_binder()) + self.map_bound(|value| PredicateAtom::TypeOutlives(value)) .potentially_quantified(tcx, PredicateKind::ForAll) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateAtom::Projection(self.skip_binder()) + self.map_bound(|value| PredicateAtom::Projection(value)) .potentially_quantified(tcx, PredicateKind::ForAll) } } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index c70554cc6272..3b49c73c7f20 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1919,10 +1919,11 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } else { let span = bound_pred.bounded_ty.span; let re_root_empty = tcx.lifetimes.re_root_empty; - let predicate = ty::OutlivesPredicate(ty, re_root_empty); + let predicate = ty::Binder::bind(ty::PredicateAtom::TypeOutlives( + ty::OutlivesPredicate(ty, re_root_empty), + )); predicates.insert(( - ty::PredicateAtom::TypeOutlives(predicate) - .potentially_quantified(tcx, ty::PredicateKind::ForAll), + predicate.potentially_quantified(tcx, ty::PredicateKind::ForAll), span, )); } @@ -1965,8 +1966,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); predicates.insert(( - ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, region)) - .potentially_quantified(tcx, ty::PredicateKind::ForAll), + ty::Binder::bind(ty::PredicateAtom::TypeOutlives( + ty::OutlivesPredicate(ty, region), + )) + .potentially_quantified(tcx, ty::PredicateKind::ForAll), lifetime.span, )); } @@ -1983,7 +1986,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } _ => bug!(), }; - let pred = ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2)); + let pred = ty::Binder::dummy(ty::PredicateAtom::RegionOutlives( + ty::OutlivesPredicate(r1, r2), + )); (pred.potentially_quantified(icx.tcx, ty::PredicateKind::ForAll), span) })) @@ -2233,8 +2238,10 @@ fn predicates_from_bound<'tcx>( } hir::GenericBound::Outlives(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); - let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region)) - .potentially_quantified(astconv.tcx(), ty::PredicateKind::ForAll); + let pred = ty::Binder::dummy(ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate( + param_ty, region, + ))) + .potentially_quantified(astconv.tcx(), ty::PredicateKind::ForAll); vec![(pred, lifetime.span)] } } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 94926f480e23..d7c084acf50f 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -89,13 +89,15 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CratePredica |(ty::OutlivesPredicate(kind1, region2), &span)| { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( - ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty1, region2)) - .potentially_quantified(tcx, ty::PredicateKind::ForAll), + ty::Binder::dummy(ty::PredicateAtom::TypeOutlives( + ty::OutlivesPredicate(ty1, region2), + )) + .potentially_quantified(tcx, ty::PredicateKind::ForAll), span, )), GenericArgKind::Lifetime(region1) => Some(( - ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate( - region1, region2, + ty::Binder::dummy(ty::PredicateAtom::RegionOutlives( + ty::OutlivesPredicate(region1, region2), )) .potentially_quantified(tcx, ty::PredicateKind::ForAll), span, From 1f58c2bb8a638a63edc1f3503c8771937aa19157 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 18 Dec 2020 21:18:15 +0000 Subject: [PATCH 413/719] Renamed the good first issue label for rustbot See https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Rename.20the.20.22good.20first.20issue.22.20label.20for.20bot.20usage/near/220428018 --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index b7b20b40e68a..b9549be3a8b6 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,7 +1,7 @@ [relabel] allow-unauthenticated = [ "A-*", "C-*", "E-*", "L-*", "M-*", "O-*", "P-*", "S-*", "T-*", - "good first issue" + "good-first-issue" ] [assign] From ced54f28671ddb9ccf9b44131d522f4fdeab7097 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 18 Dec 2020 22:13:22 +0000 Subject: [PATCH 414/719] Renamed the good first issue label in CONTRIBUTING.md --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d2a3c52dab98..4cfeaa153a01 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,7 +49,7 @@ first read the [Basics docs](doc/basics.md).** All issues on Clippy are mentored, if you want help with a bug just ask @Manishearth, @flip1995, @phansch or @yaahc. -Some issues are easier than others. The [`good first issue`] label can be used to find the easy issues. +Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy issues. If you want to work on an issue, please leave a comment so that we can assign it to you! There are also some abandoned PRs, marked with [`S-inactive-closed`]. @@ -68,7 +68,7 @@ To figure out how this syntax structure is encoded in the AST, it is recommended Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting]. But we can make it nest-less by using [if_chain] macro, [like this][nest-less]. -[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good first issue`] +[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`] first. Sometimes they are only somewhat involved code wise, but not difficult per-se. Note that [`E-medium`] issues may require some knowledge of Clippy internals or some debugging to find the actual problem behind the issue. @@ -77,7 +77,7 @@ debugging to find the actual problem behind the issue. lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of an AST expression). `match_def_path()` in Clippy's `utils` module can also be useful. -[`good first issue`]: https://github.com/rust-lang/rust-clippy/labels/good%20first%20issue +[`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue [`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed [`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST [`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle From 28e0d2f234973059bc0dce2aa4da140b2fae1fca Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Fri, 18 Dec 2020 14:53:55 -0800 Subject: [PATCH 415/719] Fix unused import error on wasm --- library/core/tests/mem.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 86990fa0945a..5d0fedd4d9cc 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -1,5 +1,6 @@ use core::mem::*; +#[cfg(panic = "unwind")] use std::rc::Rc; #[test] From a24c6f14fa89dafc879ad76a185f43bc50f0bbb9 Mon Sep 17 00:00:00 2001 From: Andrew Houts Date: Fri, 18 Dec 2020 19:15:05 -0600 Subject: [PATCH 416/719] remove example --- clippy_lints/src/needless_update.rs | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index 1e387b518c3a..41cf541ecf5e 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -8,6 +8,9 @@ declare_clippy_lint! { /// **What it does:** Checks for needlessly including a base struct on update /// when all fields are changed anyway. /// + /// This lint is not applied to structs marked with + /// [non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html). + /// /// **Why is this bad?** This will cost resources (because the base has to be /// somewhere), and make the code less readable. /// @@ -21,14 +24,7 @@ declare_clippy_lint! { /// # z: i32, /// # } /// # let zero_point = Point { x: 0, y: 0, z: 0 }; - /// # - /// # #[non_exhaustive] - /// # struct Options { - /// # a: bool, - /// # b: i32, - /// # } - /// # let default_options = Options { a: false, b: 0 }; - /// # + /// /// // Bad /// Point { /// x: 1, @@ -43,14 +39,6 @@ declare_clippy_lint! { /// y: 1, /// ..zero_point /// }; - /// - /// // this lint is not applied to structs marked with [non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html) - /// // Ok - /// Options { - /// a: true, - /// b: 321, - /// ..default_options - /// }; /// ``` pub NEEDLESS_UPDATE, complexity, From 779580190209cab277facdd8f98c2b16a049762f Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Fri, 18 Dec 2020 16:00:52 -0800 Subject: [PATCH 417/719] rustc_query_system: explicitly register reused dep nodes Register nodes that we've reused from the previous session explicitly with `OnDiskCache`. Previously, we relied on this happening as a side effect of accessing the nodes in the `PreviousDepGraph`. For the sake of performance and avoiding unintended side effects, register explictily. --- compiler/rustc_middle/src/dep_graph/mod.rs | 6 +-- .../src/ty/query/on_disk_cache.rs | 34 +++++++++++---- .../src/dep_graph/dep_node.rs | 5 +-- .../rustc_query_system/src/dep_graph/graph.rs | 24 ++++++++--- .../rustc_query_system/src/dep_graph/mod.rs | 3 +- .../rustc_query_system/src/dep_graph/prev.rs | 41 +------------------ 6 files changed, 51 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index e641c1cd77bd..728bfef9f467 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -5,7 +5,7 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; -use rustc_hir::def_id::{DefPathHash, LocalDefId}; +use rustc_hir::def_id::LocalDefId; mod dep_node; @@ -91,9 +91,9 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { type DepKind = DepKind; type StableHashingContext = StableHashingContext<'tcx>; - fn register_reused_dep_path_hash(&self, hash: DefPathHash) { + fn register_reused_dep_node(&self, dep_node: &DepNode) { if let Some(cache) = self.queries.on_disk_cache.as_ref() { - cache.register_reused_dep_path_hash(*self, hash) + cache.register_reused_dep_node(*self, dep_node) } } diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index e006dfeb6633..8316b4c109b8 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use crate::mir::{self, interpret}; use crate::ty::codec::{OpaqueEncoder, RefDecodable, TyDecoder, TyEncoder}; @@ -264,6 +264,13 @@ impl<'sess> OnDiskCache<'sess> { (file_to_file_index, file_index_to_stable_id) }; + // Register any dep nodes that we reused from the previous session, + // but didn't `DepNode::construct` in this session. This ensures + // that their `DefPathHash` to `RawDefId` mappings are registered + // in 'latest_foreign_def_path_hashes' if necessary, since that + // normally happens in `DepNode::construct`. + tcx.dep_graph.register_reused_dep_nodes(tcx); + // Load everything into memory so we can write it out to the on-disk // cache. The vast majority of cacheable query results should already // be in memory, so this should be a cheap operation. @@ -467,7 +474,7 @@ impl<'sess> OnDiskCache<'sess> { .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); } - /// If the given `hash` still exists in the current compilation, + /// If the given `dep_node`'s hash still exists in the current compilation, /// calls `store_foreign_def_id` with its current `DefId`. /// /// Normally, `store_foreign_def_id_hash` can be called directly by @@ -476,13 +483,22 @@ impl<'sess> OnDiskCache<'sess> { /// session, we only have the `DefPathHash` available. This method is used /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written /// out for usage in the next compilation session. - pub fn register_reused_dep_path_hash(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) { - // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to - // `latest_foreign_def_path_hashes`, since the `RawDefId` might have - // changed in the current compilation session (e.g. we've added/removed crates, - // or added/removed definitions before/after the target definition). - if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { - self.store_foreign_def_id_hash(def_id, hash); + pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) { + // For reused dep nodes, we only need to store the mapping if the node + // is one whose query key we can reconstruct from the hash. We use the + // mapping to aid that reconstruction in the next session. While we also + // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, + // they're already registered during `DefId` encoding. + if dep_node.kind.can_reconstruct_query_key() { + let hash = DefPathHash(dep_node.hash.into()); + + // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to + // `latest_foreign_def_path_hashes`, since the `RawDefId` might have + // changed in the current compilation session (e.g. we've added/removed crates, + // or added/removed definitions before/after the target definition). + if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { + self.store_foreign_def_id_hash(def_id, hash); + } } } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 09e5dc857a75..ff52fdab19c5 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -60,9 +60,8 @@ pub struct DepNode { // * When a `DepNode::construct` is called, `arg.to_fingerprint()` // is responsible for calling `OnDiskCache::store_foreign_def_id_hash` // if needed - // * When a `DepNode` is loaded from the `PreviousDepGraph`, - // then `PreviousDepGraph::index_to_node` is responsible for calling - // `tcx.register_reused_dep_path_hash` + // * When we serialize the on-disk cache, `OnDiskCache::serialize` is + // responsible for calling `DepGraph::register_reused_dep_nodes`. // // FIXME: Enforce this by preventing manual construction of `DefNode` // (e.g. add a `_priv: ()` field) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 956d476d973e..d2f0e39ea6bb 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -554,7 +554,7 @@ impl DepGraph { // We never try to mark eval_always nodes as green debug_assert!(!dep_node.kind.is_eval_always()); - data.previous.debug_assert_eq(prev_dep_node_index, *dep_node); + debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node); let prev_deps = data.previous.edge_targets_from(prev_dep_node_index); @@ -572,7 +572,7 @@ impl DepGraph { "try_mark_previous_green({:?}) --- found dependency {:?} to \ be immediately green", dep_node, - data.previous.debug_dep_node(dep_dep_node_index), + data.previous.index_to_node(dep_dep_node_index) ); current_deps.push(node_index); } @@ -585,12 +585,12 @@ impl DepGraph { "try_mark_previous_green({:?}) - END - dependency {:?} was \ immediately red", dep_node, - data.previous.debug_dep_node(dep_dep_node_index) + data.previous.index_to_node(dep_dep_node_index) ); return None; } None => { - let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index, tcx); + let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); // We don't know the state of this dependency. If it isn't // an eval_always node, let's try to mark it green recursively. @@ -801,7 +801,7 @@ impl DepGraph { for prev_index in data.colors.values.indices() { match data.colors.get(prev_index) { Some(DepNodeColor::Green(_)) => { - let dep_node = data.previous.index_to_node(prev_index, tcx); + let dep_node = data.previous.index_to_node(prev_index); tcx.try_load_from_on_disk_cache(&dep_node); } None | Some(DepNodeColor::Red) => { @@ -813,6 +813,20 @@ impl DepGraph { } } + // Register reused dep nodes (i.e. nodes we've marked red or green) with the context. + pub fn register_reused_dep_nodes>(&self, tcx: Ctxt) { + let data = self.data.as_ref().unwrap(); + for prev_index in data.colors.values.indices() { + match data.colors.get(prev_index) { + Some(DepNodeColor::Red) | Some(DepNodeColor::Green(_)) => { + let dep_node = data.previous.index_to_node(prev_index); + tcx.register_reused_dep_node(&dep_node); + } + None => {} + } + } + } + fn next_virtual_depnode_index(&self) -> DepNodeIndex { let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); DepNodeIndex::from_u32(index) diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 3b4b62ad6be8..da0b5aad6c81 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -15,7 +15,6 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; -use rustc_span::def_id::DefPathHash; use std::fmt; use std::hash::Hash; @@ -33,7 +32,7 @@ pub trait DepContext: Copy { /// Try to force a dep node to execute and see if it's green. fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool; - fn register_reused_dep_path_hash(&self, hash: DefPathHash); + fn register_reused_dep_node(&self, dep_node: &DepNode); /// Return whether the current session is tainted by errors. fn has_errors_or_delayed_span_bugs(&self) -> bool; diff --git a/compiler/rustc_query_system/src/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs index 9298b652da2d..29357ce9449c 100644 --- a/compiler/rustc_query_system/src/dep_graph/prev.rs +++ b/compiler/rustc_query_system/src/dep_graph/prev.rs @@ -1,9 +1,7 @@ use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use super::{DepKind, DepNode}; -use crate::dep_graph::DepContext; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -use rustc_span::def_id::DefPathHash; #[derive(Debug, Encodable, Decodable)] pub struct PreviousDepGraph { @@ -33,44 +31,7 @@ impl PreviousDepGraph { } #[inline] - pub fn index_to_node>( - &self, - dep_node_index: SerializedDepNodeIndex, - tcx: CTX, - ) -> DepNode { - let dep_node = self.data.nodes[dep_node_index]; - // We have just loaded a deserialized `DepNode` from the previous - // compilation session into the current one. If this was a foreign `DefId`, - // then we stored additional information in the incr comp cache when we - // initially created its fingerprint (see `DepNodeParams::to_fingerprint`) - // We won't be calling `to_fingerprint` again for this `DepNode` (we no longer - // have the original value), so we need to copy over this additional information - // from the old incremental cache into the new cache that we serialize - // and the end of this compilation session. - if dep_node.kind.can_reconstruct_query_key() { - tcx.register_reused_dep_path_hash(DefPathHash(dep_node.hash.into())); - } - dep_node - } - - /// When debug assertions are enabled, asserts that the dep node at `dep_node_index` is equal to `dep_node`. - /// This method should be preferred over manually calling `index_to_node`. - /// Calls to `index_to_node` may affect global state, so gating a call - /// to `index_to_node` on debug assertions could cause behavior changes when debug assertions - /// are enabled. - #[inline] - pub fn debug_assert_eq(&self, dep_node_index: SerializedDepNodeIndex, dep_node: DepNode) { - debug_assert_eq!(self.data.nodes[dep_node_index], dep_node); - } - - /// Obtains a debug-printable version of the `DepNode`. - /// See `debug_assert_eq` for why this should be preferred over manually - /// calling `dep_node_index` - pub fn debug_dep_node(&self, dep_node_index: SerializedDepNodeIndex) -> impl std::fmt::Debug { - // We're returning the `DepNode` without calling `register_reused_dep_path_hash`, - // but `impl Debug` return type means that it can only be used for debug printing. - // So, there's no risk of calls trying to create new dep nodes that have this - // node as a dependency + pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { self.data.nodes[dep_node_index] } From 55ae3b3a79a44f154334fed077c511b17aef9913 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Fri, 18 Dec 2020 18:40:16 -0800 Subject: [PATCH 418/719] OnDiskCache: avoid storing local def id hashes in foreign def id collection --- compiler/rustc_middle/src/ty/query/on_disk_cache.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 8316b4c109b8..f6aaeecd6e37 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -475,7 +475,7 @@ impl<'sess> OnDiskCache<'sess> { } /// If the given `dep_node`'s hash still exists in the current compilation, - /// calls `store_foreign_def_id` with its current `DefId`. + /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. /// /// Normally, `store_foreign_def_id_hash` can be called directly by /// the dependency graph when we construct a `DepNode`. However, @@ -497,7 +497,9 @@ impl<'sess> OnDiskCache<'sess> { // changed in the current compilation session (e.g. we've added/removed crates, // or added/removed definitions before/after the target definition). if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { - self.store_foreign_def_id_hash(def_id, hash); + if !def_id.is_local() { + self.store_foreign_def_id_hash(def_id, hash); + } } } } From dfb4ea588c2af7633b2d01d2dfa3d6ffc7d07ee7 Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Sat, 19 Dec 2020 08:25:42 +0100 Subject: [PATCH 419/719] Fix blessing of new reference files Adding of new reference files wasn't handled correctly. It was trying to read a file that didn't exist yet. Instead of unwrapping, we now treat a missing reference file as empty (`Vec::new`). This makes the following conditional work. We then also have to re-read the reference file after it was being copied. This second read is technically the same as in the old shell script, but wasn't really obvious. The shell script did a `-s` test which reads the file. --- clippy_dev/src/bless.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs index 8d5c2e95055d..645098e4cfcd 100644 --- a/clippy_dev/src/bless.rs +++ b/clippy_dev/src/bless.rs @@ -46,13 +46,16 @@ fn update_reference_file(reference_file_path: PathBuf) { } let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file"); - let reference_file = fs::read(&reference_file_path).expect("Unable to read reference file"); + let reference_file = fs::read(&reference_file_path).unwrap_or_default(); if test_output_file != reference_file { // If a test run caused an output file to change, update the reference file println!("updating {}", &relative_reference_file_path.display()); fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file"); + // We need to re-read the file now because it was potentially updated from copying + let reference_file = fs::read(&reference_file_path).unwrap_or_default(); + if reference_file.is_empty() { // If we copied over an empty output file, we remove the now empty reference file println!("removing {}", &relative_reference_file_path.display()); From 5e7095850c3577666a6b8e628760dea7cccb46b7 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Wed, 16 Dec 2020 22:36:14 -0500 Subject: [PATCH 420/719] More rebinds --- compiler/rustc_infer/src/infer/combine.rs | 4 +- .../rustc_infer/src/infer/nll_relate/mod.rs | 2 +- compiler/rustc_middle/src/ty/_match.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 5 ++- compiler/rustc_middle/src/ty/mod.rs | 16 ++++--- .../src/traits/error_reporting/suggestions.rs | 34 +++++++-------- .../src/traits/object_safety.rs | 4 +- .../src/traits/project.rs | 6 ++- .../src/traits/select/confirmation.rs | 6 +-- .../src/traits/select/mod.rs | 35 ++++++++-------- .../rustc_trait_selection/src/traits/util.rs | 8 ++-- compiler/rustc_typeck/src/astconv/mod.rs | 6 +-- compiler/rustc_typeck/src/bounds.rs | 10 +++-- compiler/rustc_typeck/src/check/callee.rs | 2 +- compiler/rustc_typeck/src/check/closure.rs | 42 ++++++++++--------- .../rustc_typeck/src/check/compare_method.rs | 5 +-- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 7 ++-- .../src/check/generator_interior.rs | 3 +- compiler/rustc_typeck/src/check/intrinsic.rs | 36 +++++++--------- compiler/rustc_typeck/src/collect.rs | 13 +++--- compiler/rustc_typeck/src/lib.rs | 20 +++++---- compiler/rustc_typeck/src/outlives/mod.rs | 14 +++---- src/librustdoc/clean/mod.rs | 18 ++++---- .../clippy_lints/src/await_holding_invalid.rs | 2 +- 24 files changed, 152 insertions(+), 148 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 6a1715ef8189..7770f2bd9115 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -551,7 +551,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } fn relate_item_substs( @@ -833,7 +833,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 0b2847658f71..b9bd66e4b929 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -1008,6 +1008,6 @@ where self.first_free_index.shift_in(1); let result = self.relate(a.skip_binder(), a.skip_binder())?; self.first_free_index.shift_out(1); - Ok(ty::Binder::bind(result)) + Ok(a.rebind(result)) } } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index 27bccc0bcafa..a5962e3b3ba5 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -118,6 +118,6 @@ impl TypeRelation<'tcx> for Match<'tcx> { where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index adf02412b96d..615972ae45c9 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -299,6 +299,7 @@ pub struct ResolvedOpaqueTy<'tcx> { /// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for /// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`. #[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)] +#[derive(TypeFoldable)] pub struct GeneratorInteriorTypeCause<'tcx> { /// Type of the captured binding. pub ty: Ty<'tcx>, @@ -423,7 +424,7 @@ pub struct TypeckResults<'tcx> { /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). - pub generator_interior_types: Vec>, + pub generator_interior_types: ty::Binder>>, /// We sometimes treat byte string literals (which are of type `&[u8; N]`) /// as `&[u8]`, depending on the pattern in which they are used. @@ -455,7 +456,7 @@ impl<'tcx> TypeckResults<'tcx> { concrete_opaque_types: Default::default(), closure_captures: Default::default(), closure_min_captures: Default::default(), - generator_interior_types: Default::default(), + generator_interior_types: ty::Binder::dummy(Default::default()), treat_byte_string_as_slice: Default::default(), } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b0f02dee59b2..98602d6a459b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1252,7 +1252,7 @@ impl<'tcx> Predicate<'tcx> { let pred = self.skip_binders(); let new = pred.subst(tcx, substs); if new != pred { - trait_ref.rebind(new).potentially_quantified(tcx, PredicateKind::ForAll) + ty::Binder::bind(new).potentially_quantified(tcx, PredicateKind::ForAll) } else { self } @@ -1282,6 +1282,10 @@ impl<'tcx> PolyTraitPredicate<'tcx> { // Ok to skip binder since trait `DefId` does not care about regions. self.skip_binder().def_id() } + + pub fn self_ty(self) -> ty::Binder> { + self.map_bound(|trait_ref| trait_ref.self_ty()) + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] @@ -1435,9 +1439,10 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_ref(self) -> Option>> { - match self.skip_binders() { + let predicate = self.bound_atom(); + match predicate.skip_binder() { PredicateAtom::Trait(t, constness) => { - Some(ConstnessAnd { constness, value: ty::Binder::bind(t.trait_ref) }) + Some(ConstnessAnd { constness, value: predicate.rebind(t.trait_ref) }) } PredicateAtom::Projection(..) | PredicateAtom::Subtype(..) @@ -1453,8 +1458,9 @@ impl<'tcx> Predicate<'tcx> { } pub fn to_opt_type_outlives(self) -> Option> { - match self.skip_binders() { - PredicateAtom::TypeOutlives(data) => Some(ty::Binder::bind(data)), + let predicate = self.bound_atom(); + match predicate.skip_binder() { + PredicateAtom::TypeOutlives(data) => Some(predicate.rebind(data)), PredicateAtom::Trait(..) | PredicateAtom::Projection(..) | PredicateAtom::Subtype(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5c185dc4a9f1..b4b71a48ce9d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1151,9 +1151,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> DiagnosticBuilder<'tcx> { crate fn build_fn_sig_string<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, ) -> String { - let inputs = trait_ref.substs.type_at(1); + let inputs = trait_ref.skip_binder().substs.type_at(1); let sig = if let ty::Tuple(inputs) = inputs.kind() { tcx.mk_fn_sig( inputs.iter().map(|k| k.expect_ty()), @@ -1171,7 +1171,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { abi::Abi::Rust, ) }; - ty::Binder::bind(sig).to_string() + trait_ref.rebind(sig).to_string() } let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure(); @@ -1183,17 +1183,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if argument_is_closure { "closure" } else { "function" } ); - let found_str = format!( - "expected signature of `{}`", - build_fn_sig_string(self.tcx, found.skip_binder()) - ); + let found_str = format!("expected signature of `{}`", build_fn_sig_string(self.tcx, found)); err.span_label(span, found_str); let found_span = found_span.unwrap_or(span); - let expected_str = format!( - "found signature of `{}`", - build_fn_sig_string(self.tcx, expected_ref.skip_binder()) - ); + let expected_str = + format!("found signature of `{}`", build_fn_sig_string(self.tcx, expected_ref)); err.span_label(found_span, expected_str); err @@ -1422,7 +1417,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // generator frame. Bound regions are preserved by // `erase_regions` and so we must also call // `erase_late_bound_regions`. - let ty_erased = self.tcx.erase_late_bound_regions(ty::Binder::bind(ty)); + let ty_erased = self.tcx.erase_late_bound_regions(ty); let ty_erased = self.tcx.erase_regions(ty_erased); let eq = ty::TyS::same_type(ty_erased, target_ty_erased); debug!( @@ -1440,7 +1435,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| { let upvar_ty = typeck_results.node_type(*upvar_id); let upvar_ty = self.resolve_vars_if_possible(upvar_ty); - if ty_matches(&upvar_ty) { + if ty_matches(ty::Binder::dummy(upvar_ty)) { Some(GeneratorInteriorOrUpvar::Upvar(upvar.span)) } else { None @@ -1448,10 +1443,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); }; - if let Some(cause) = typeck_results - .generator_interior_types - .iter() - .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty_matches(ty)) + // The generator interior types share the same binders + if let Some(cause) = + typeck_results.generator_interior_types.as_ref().skip_binder().iter().find( + |ty::GeneratorInteriorTypeCause { ty, .. }| { + ty_matches(typeck_results.generator_interior_types.rebind(ty)) + }, + ) { // Check to see if any awaited expressions have the target type. let from_awaited_ty = visitor @@ -1464,7 +1462,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { "maybe_note_obligation_cause_for_async_await: await_expr={:?}", await_expr ); - ty_matches(ty) + ty_matches(ty::Binder::dummy(ty)) }) .map(|expr| expr.span); let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause; diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 8b275db89f19..8b6e30f34fd4 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -418,11 +418,11 @@ fn virtual_call_violation_for_method<'tcx>( } for (i, &input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() { - if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) { + if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) { return Some(MethodViolationCode::ReferencesSelfInput(i)); } } - if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) { + if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { return Some(MethodViolationCode::ReferencesSelfOutput); } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index df472e6ed7e9..a11499e43209 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -951,7 +951,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + let poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); let _ = selcx.infcx().commit_if_ok(|_| { let impl_source = match selcx.select(&trait_obligation) { @@ -1247,7 +1247,9 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>( ty: self_ty.discriminant_ty(tcx), }; - confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false) + // We get here from `poly_project_and_unify_type` which replaces bound vars + // with placeholders, so dummy is okay here. + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) } fn confirm_fn_pointer_candidate<'cx, 'tcx>( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index ab09fcfd8cc7..81de6dc71f46 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -259,10 +259,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> ImplSourceAutoImplData> { debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate"); - let types = obligation.predicate.map_bound(|inner| { - let self_ty = self.infcx.shallow_resolve(inner.self_ty()); - self.constituent_types_for_ty(self_ty) - }); + let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty()); + let types = self.constituent_types_for_ty(self_ty); self.vtable_auto_impl(obligation, trait_def_id, types) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 74b6652981a8..f1c86eab0956 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1276,7 +1276,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // FIXME(generic_associated_types): Compare the whole projections let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx())); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + let obligation_poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref); self.infcx .at(&obligation.cause, obligation.param_env) .sup(obligation_poly_trait_ref, data_poly_trait_ref) @@ -1648,8 +1648,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` - fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { - match *t.kind() { + fn constituent_types_for_ty(&self, t: ty::Binder>) -> ty::Binder>> { + match *t.skip_binder().kind() { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -1660,7 +1660,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never - | ty::Char => Vec::new(), + | ty::Char => ty::Binder::dummy(Vec::new()), ty::Placeholder(..) | ty::Dynamic(..) @@ -1673,44 +1673,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { - vec![element_ty] + t.rebind(vec![element_ty]) } - ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty], + ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]), ty::Tuple(ref tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - tys.iter().map(|k| k.expect_ty()).collect() + t.rebind(tys.iter().map(|k| k.expect_ty()).collect()) } ty::Closure(_, ref substs) => { let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); - vec![ty] + t.rebind(vec![ty]) } ty::Generator(_, ref substs, _) => { let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); let witness = substs.as_generator().witness(); - vec![ty].into_iter().chain(iter::once(witness)).collect() + t.rebind(vec![ty].into_iter().chain(iter::once(witness)).collect()) } ty::GeneratorWitness(types) => { - // This is sound because no regions in the witness can refer to - // the binder outside the witness. So we'll effectivly reuse - // the implicit binder around the witness. - types.skip_binder().to_vec() + debug_assert!(!types.has_escaping_bound_vars()); + types.map_bound(|types| types.to_vec()) } // For `PhantomData`, we pass `T`. - ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(), + ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()), - ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(), + ty::Adt(def, substs) => { + t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect()) + } ty::Opaque(def_id, substs) => { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] + t.rebind(vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)]) } } } @@ -1738,10 +1738,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy` types + .as_ref() .skip_binder() // binder moved -\ .iter() .flat_map(|ty| { - let ty: ty::Binder> = ty::Binder::bind(ty); // <----/ + let ty: ty::Binder> = types.rebind(ty); // <----/ self.infcx.commit_unconditionally(|_| { let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index ab4a81c7d152..8888ea2c8490 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -6,7 +6,7 @@ use smallvec::SmallVec; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef}; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; pub use rustc_infer::traits::util::*; @@ -333,11 +333,12 @@ pub fn closure_trait_ref_and_return_type( TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), }; + debug_assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]), }; - ty::Binder::bind((trait_ref, sig.skip_binder().output())) + sig.map_bound(|sig| (trait_ref, sig.output())) } pub fn generator_trait_ref_and_outputs( @@ -346,11 +347,12 @@ pub fn generator_trait_ref_and_outputs( self_ty: Ty<'tcx>, sig: ty::PolyGenSig<'tcx>, ) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { + debug_assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]), }; - ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) + sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty)) } pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 693cd236299a..c470659e18a4 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -837,9 +837,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .instantiate_lang_item_trait_ref( lang_item, span, hir_id, args, param_ty, bounds, ), - hir::GenericBound::Outlives(ref l) => { - bounds.region_bounds.push((self.ast_region_to_region(l, None), l.span)) - } + hir::GenericBound::Outlives(ref l) => bounds + .region_bounds + .push((ty::Binder::bind(self.ast_region_to_region(l, None)), l.span)), } } } diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 497754f20e4c..7ba90ad88193 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -26,7 +26,7 @@ pub struct Bounds<'tcx> { /// A list of region bounds on the (implicit) self type. So if you /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but /// the `T` is not explicitly included). - pub region_bounds: Vec<(ty::Region<'tcx>, Span)>, + pub region_bounds: Vec<(ty::Binder>, Span)>, /// A list of trait bounds. So if you had `T: Debug` this would be /// `T: Debug`. Note that the self-type is explicit here. @@ -68,8 +68,12 @@ impl<'tcx> Bounds<'tcx> { sized_predicate .into_iter() .chain(self.region_bounds.iter().map(|&(region_bound, span)| { - let outlives = ty::OutlivesPredicate(param_ty, region_bound); - (ty::Binder::bind(outlives).to_predicate(tcx), span) + ( + region_bound + .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound)) + .to_predicate(tcx), + span, + ) })) .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index ebfb401fcf3a..22e287320d84 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -389,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // In that case, we check each argument against "error" in order to // set up all the node type bindings. ( - ty::Binder::bind(self.tcx.mk_fn_sig( + ty::Binder::dummy(self.tcx.mk_fn_sig( self.err_args(arg_exprs.len()).into_iter(), self.tcx.ty_error(), false, diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 8082a230216e..7470c1a76a94 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -24,7 +24,7 @@ use std::iter; struct ExpectedSig<'tcx> { /// Span that gave us this expectation, if we know that. cause_span: Option, - sig: ty::FnSig<'tcx>, + sig: ty::PolyFnSig<'tcx>, } struct ClosureSignatures<'tcx> { @@ -174,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), ty::FnPtr(sig) => { - let expected_sig = ExpectedSig { cause_span: None, sig: sig.skip_binder() }; + let expected_sig = ExpectedSig { cause_span: None, sig }; (Some(expected_sig), Some(ty::ClosureKind::Fn)) } _ => (None, None), @@ -274,13 +274,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty); debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty); - let sig = self.tcx.mk_fn_sig( + let sig = projection.rebind(self.tcx.mk_fn_sig( input_tys.iter(), &ret_param_ty, false, hir::Unsafety::Normal, Abi::Rust, - ); + )); debug!("deduce_sig_from_projection: sig={:?}", sig); Some(ExpectedSig { cause_span, sig }) @@ -374,9 +374,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Watch out for some surprises and just ignore the // expectation if things don't see to match up with what we // expect. - if expected_sig.sig.c_variadic != decl.c_variadic { + if expected_sig.sig.c_variadic() != decl.c_variadic { return self.sig_of_closure_no_expectation(expr_def_id, decl, body); - } else if expected_sig.sig.inputs_and_output.len() != decl.inputs.len() + 1 { + } else if expected_sig.sig.skip_binder().inputs_and_output.len() != decl.inputs.len() + 1 { return self.sig_of_closure_with_mismatched_number_of_arguments( expr_def_id, decl, @@ -388,14 +388,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a `PolyFnSig`. Note the oddity that late bound // regions appearing free in `expected_sig` are now bound up // in this binder we are creating. - assert!(!expected_sig.sig.has_vars_bound_above(ty::INNERMOST)); - let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig( - expected_sig.sig.inputs().iter().cloned(), - expected_sig.sig.output(), - decl.c_variadic, - hir::Unsafety::Normal, - Abi::RustCall, - )); + assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST)); + let bound_sig = expected_sig.sig.map_bound(|sig| { + self.tcx.mk_fn_sig( + sig.inputs().iter().cloned(), + sig.output(), + sig.c_variadic, + hir::Unsafety::Normal, + Abi::RustCall, + ) + }); // `deduce_expectations_from_expected_type` introduces // late-bound lifetimes defined elsewhere, which we now @@ -428,6 +430,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr_map_node = hir.get_if_local(expr_def_id).unwrap(); let expected_args: Vec<_> = expected_sig .sig + .skip_binder() .inputs() .iter() .map(|ty| ArgKind::from_expected_ty(ty, None)) @@ -500,7 +503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (supplied_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars( hir_ty.span, LateBoundRegionConversionTime::FnCall, - ty::Binder::bind(supplied_ty), + supplied_sig.inputs().rebind(supplied_ty), ); // recreated from (*) above // Check that E' = S'. @@ -619,12 +622,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // where R is the return type we are expecting. This type `T` // will be our output. let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| { - if let ty::PredicateAtom::Projection(proj_predicate) = - obligation.predicate.skip_binders() - { + let bound_predicate = obligation.predicate.bound_atom(); + if let ty::PredicateAtom::Projection(proj_predicate) = bound_predicate.skip_binder() { self.deduce_future_output_from_projection( obligation.cause.span, - ty::Binder::bind(proj_predicate), + bound_predicate.rebind(proj_predicate), ) } else { None @@ -704,7 +706,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { astconv.ast_ty_to_ty(&output); } - let result = ty::Binder::bind(self.tcx.mk_fn_sig( + let result = ty::Binder::dummy(self.tcx.mk_fn_sig( supplied_arguments, self.tcx.ty_error(), decl.c_variadic, diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 20090d376060..bb324d0d8bc1 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -494,12 +494,11 @@ fn compare_self_type<'tcx>( ty::ImplContainer(_) => impl_trait_ref.self_ty(), ty::TraitContainer(_) => tcx.types.self_param, }; - let self_arg_ty = tcx.fn_sig(method.def_id).input(0).skip_binder(); + let self_arg_ty = tcx.fn_sig(method.def_id).input(0); let param_env = ty::ParamEnv::reveal_all(); tcx.infer_ctxt().enter(|infcx| { - let self_arg_ty = - tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(self_arg_ty)); + let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok(); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { ExplicitSelf::ByValue => "self".to_owned(), diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index e1a2f593b8d9..41a403a010ee 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -764,12 +764,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .pending_obligations() .into_iter() .filter_map(move |obligation| { - match obligation.predicate.skip_binders() { + let bound_predicate = obligation.predicate.bound_atom(); + match bound_predicate.skip_binder() { ty::PredicateAtom::Projection(data) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation)) + Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation)) } ty::PredicateAtom::Trait(data, _) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation)) + Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation)) } ty::PredicateAtom::Subtype(..) => None, ty::PredicateAtom::RegionOutlives(..) => None, diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 5bc40d617d04..54710e12a746 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -204,7 +204,8 @@ pub fn resolve_interior<'a, 'tcx>( let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list)); // Store the generator types and spans into the typeck results for this generator. - visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types = type_causes; + visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types = + ty::Binder::bind(type_causes); debug!( "types in generator after region replacement {:?}, span = {:?}", diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index e2712a303399..dd629980ab4d 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -12,7 +12,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::spec::abi::Abi; @@ -23,10 +23,7 @@ fn equate_intrinsic_type<'tcx>( it: &hir::ForeignItem<'_>, def_id: DefId, n_tps: usize, - abi: Abi, - safety: hir::Unsafety, - inputs: Vec>, - output: Ty<'tcx>, + sig: ty::PolyFnSig<'tcx>, ) { match it.kind { hir::ForeignItemKind::Fn(..) => {} @@ -53,13 +50,7 @@ fn equate_intrinsic_type<'tcx>( return; } - let fty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( - inputs.into_iter(), - output, - false, - safety, - abi, - ))); + let fty = tcx.mk_fn_ptr(sig); let cause = ObligationCause::new(it.span, it.hir_id, ObligationCauseCode::IntrinsicType); require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty); } @@ -380,7 +371,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { }; (n_tps, inputs, output, unsafety) }; - equate_intrinsic_type(tcx, it, def_id, n_tps, Abi::RustIntrinsic, unsafety, inputs, output) + let sig = tcx.mk_fn_sig(inputs.into_iter(), output, false, unsafety, Abi::RustIntrinsic); + let sig = ty::Binder::bind(sig); + equate_intrinsic_type(tcx, it, def_id, n_tps, sig) } /// Type-check `extern "platform-intrinsic" { ... }` functions. @@ -466,14 +459,13 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) } }; - equate_intrinsic_type( - tcx, - it, - def_id, - n_tps, - Abi::PlatformIntrinsic, - hir::Unsafety::Unsafe, - inputs, + let sig = tcx.mk_fn_sig( + inputs.into_iter(), output, - ) + false, + hir::Unsafety::Unsafe, + Abi::PlatformIntrinsic, + ); + let sig = ty::Binder::dummy(sig); + equate_intrinsic_type(tcx, it, def_id, n_tps, sig) } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 3b49c73c7f20..543e39af6694 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1986,11 +1986,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } _ => bug!(), }; - let pred = ty::Binder::dummy(ty::PredicateAtom::RegionOutlives( - ty::OutlivesPredicate(r1, r2), - )); + let pred = ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2)) + .to_predicate(icx.tcx); - (pred.potentially_quantified(icx.tcx, ty::PredicateKind::ForAll), span) + (pred, span) })) } @@ -2238,10 +2237,8 @@ fn predicates_from_bound<'tcx>( } hir::GenericBound::Outlives(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); - let pred = ty::Binder::dummy(ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate( - param_ty, region, - ))) - .potentially_quantified(astconv.tcx(), ty::PredicateKind::ForAll); + let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region)) + .to_predicate(astconv.tcx()); vec![(pred, lifetime.span)] } } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 929c88455f04..dde4a62ffbf3 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -226,19 +226,21 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) { 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() + actual.output() } else { // standard () main return type - tcx.mk_unit() + ty::Binder::dummy(tcx.mk_unit()) }; - let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( - iter::empty(), - expected_return_type, - false, - hir::Unsafety::Normal, - Abi::Rust, - ))); + let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| { + tcx.mk_fn_sig( + iter::empty(), + expected_return_type, + false, + hir::Unsafety::Normal, + Abi::Rust, + ) + })); require_same_types( tcx, diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index d7c084acf50f..b1f79331d5f6 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; +use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -89,17 +89,15 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CratePredica |(ty::OutlivesPredicate(kind1, region2), &span)| { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( - ty::Binder::dummy(ty::PredicateAtom::TypeOutlives( - ty::OutlivesPredicate(ty1, region2), - )) - .potentially_quantified(tcx, ty::PredicateKind::ForAll), + ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty1, region2)) + .to_predicate(tcx), span, )), GenericArgKind::Lifetime(region1) => Some(( - ty::Binder::dummy(ty::PredicateAtom::RegionOutlives( - ty::OutlivesPredicate(region1, region2), + ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate( + region1, region2, )) - .potentially_quantified(tcx, ty::PredicateKind::ForAll), + .to_predicate(tcx), span, )), GenericArgKind::Const(_) => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2809e85761d4..a5f23dac0447 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -469,8 +469,9 @@ impl Clean for hir::WherePredicate<'_> { impl<'a> Clean> for ty::Predicate<'a> { fn clean(&self, cx: &DocContext<'_>) -> Option { - match self.skip_binders() { - ty::PredicateAtom::Trait(pred, _) => Some(ty::Binder::bind(pred).clean(cx)), + let bound_predicate = self.bound_atom(); + match bound_predicate.skip_binder() { + ty::PredicateAtom::Trait(pred, _) => Some(bound_predicate.rebind(pred).clean(cx)), ty::PredicateAtom::RegionOutlives(pred) => pred.clean(cx), ty::PredicateAtom::TypeOutlives(pred) => pred.clean(cx), ty::PredicateAtom::Projection(pred) => Some(pred.clean(cx)), @@ -733,7 +734,8 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx .flat_map(|(p, _)| { let mut projection = None; let param_idx = (|| { - match p.skip_binders() { + let bound_p = p.bound_atom(); + match bound_p.skip_binder() { ty::PredicateAtom::Trait(pred, _constness) => { if let ty::Param(param) = pred.self_ty().kind() { return Some(param.index); @@ -746,7 +748,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx } ty::PredicateAtom::Projection(p) => { if let ty::Param(param) = p.projection_ty.self_ty().kind() { - projection = Some(ty::Binder::bind(p)); + projection = Some(bound_p.rebind(p)); return Some(param.index); } } @@ -1659,12 +1661,10 @@ impl<'tcx> Clean for Ty<'tcx> { .filter_map(|bound| { // Note: The substs of opaque types can contain unbound variables, // meaning that we have to use `ignore_quantifiers_with_unbound_vars` here. - let trait_ref = match bound - .bound_atom_with_opt_escaping(cx.tcx) - .skip_binder() - { + let bound_predicate = bound.bound_atom_with_opt_escaping(cx.tcx); + let trait_ref = match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(tr, _constness) => { - ty::Binder::bind(tr.trait_ref) + bound_predicate.rebind(tr.trait_ref) } ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => { if let Some(r) = reg.clean(cx) { diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index 58892024ce24..cfade9cbc469 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -99,7 +99,7 @@ impl LateLintPass<'_> for AwaitHolding { }; let def_id = cx.tcx.hir().body_owner_def_id(body_id); let typeck_results = cx.tcx.typeck(def_id); - check_interior_types(cx, &typeck_results.generator_interior_types, body.value.span); + check_interior_types(cx, &typeck_results.generator_interior_types.as_ref().skip_binder(), body.value.span); } } } From f00b6ac24e0decaa182b717172f2caf97c6b08bf Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Wed, 16 Dec 2020 22:36:14 -0500 Subject: [PATCH 421/719] More rebinds --- clippy_lints/src/await_holding_invalid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 58892024ce24..cfade9cbc469 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -99,7 +99,7 @@ impl LateLintPass<'_> for AwaitHolding { }; let def_id = cx.tcx.hir().body_owner_def_id(body_id); let typeck_results = cx.tcx.typeck(def_id); - check_interior_types(cx, &typeck_results.generator_interior_types, body.value.span); + check_interior_types(cx, &typeck_results.generator_interior_types.as_ref().skip_binder(), body.value.span); } } } From 830ceaa41908bd428e36b1a804dd93c9a257aea8 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Sun, 6 Dec 2020 13:57:37 +0100 Subject: [PATCH 422/719] Remap instrument-coverage line numbers in doctests This uses the `SourceMap::doctest_offset_line` method to re-map line numbers from doctests. Remapping columns is not yet done. Part of issue #79417. --- .../rustc_mir/src/transform/coverage/mod.rs | 6 +- compiler/rustc_span/src/lib.rs | 2 +- src/librustdoc/doctest.rs | 75 +++++--- src/librustdoc/doctest/tests.rs | 69 +++++-- src/librustdoc/html/markdown.rs | 2 +- .../coverage-reports/Makefile | 22 ++- .../expected_show_coverage.doctest.txt | 79 ++++++++ .../expected_show_coverage.uses_crate.txt | 4 +- .../coverage-reports/normalize_paths.py | 10 + ...est.main.-------.InstrumentCoverage.0.html | 127 +++++++++++++ ...doctests.-------.InstrumentCoverage.0.html | 173 ++++++++++++++++++ .../coverage/compiletest-ignore-dir | 4 +- .../coverage/coverage_tools.mk | 4 +- .../run-make-fulldeps/coverage/doctest.rs | 66 +++++++ .../coverage/lib/doctest_crate.rs | 9 + 15 files changed, 596 insertions(+), 56 deletions(-) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/normalize_paths.py create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage/doctest.rs create mode 100644 src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 4590d37c182e..93133e9b7f06 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -30,6 +30,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; +use rustc_span::source_map::SourceMap; use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol}; /// A simple error message wrapper for `coverage::Error`s. @@ -311,7 +312,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { self.mir_body, counter_kind, self.bcb_leader_bb(bcb), - Some(make_code_region(file_name, &self.source_file, span, body_span)), + Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)), ); } } @@ -489,6 +490,7 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: Co /// Convert the Span into its file name, start line and column, and end line and column fn make_code_region( + source_map: &SourceMap, file_name: Symbol, source_file: &Lrc, span: Span, @@ -508,6 +510,8 @@ fn make_code_region( } else { source_file.lookup_file_pos(span.hi()) }; + let start_line = source_map.doctest_offset_line(&source_file.name, start_line); + let end_line = source_map.doctest_offset_line(&source_file.name, end_line); CodeRegion { file_name, start_line: start_line as u32, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f63a73acbf4b..fbef4d06709e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -182,7 +182,7 @@ impl std::fmt::Display for FileName { use FileName::*; match *self { Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()), - // FIXME: might be nice to display both compoments of Devirtualized. + // FIXME: might be nice to display both components of Devirtualized. // But for now (to backport fix for issue #70924), best to not // perturb diagnostics so its obvious test suite still works. Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 37fe13c32ce7..a08ded926402 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -247,9 +247,10 @@ fn run_test( edition: Edition, outdir: DirState, path: PathBuf, + test_id: &str, ) -> Result<(), TestFailure> { let (test, line_offset, supports_color) = - make_test(test, Some(cratename), as_test_harness, opts, edition); + make_test(test, Some(cratename), as_test_harness, opts, edition, Some(test_id)); let output_file = outdir.path().join("rust_out"); @@ -387,6 +388,7 @@ crate fn make_test( dont_insert_main: bool, opts: &TestOptions, edition: Edition, + test_id: Option<&str>, ) -> (String, usize, bool) { let (crate_attrs, everything_else, crates) = partition_source(s); let everything_else = everything_else.trim(); @@ -542,16 +544,40 @@ crate fn make_test( prog.push_str(everything_else); } else { let returns_result = everything_else.trim_end().ends_with("(())"); + // Give each doctest main function a unique name. + // This is for example needed for the tooling around `-Z instrument-coverage`. + let inner_fn_name = if let Some(test_id) = test_id { + format!("_doctest_main_{}", test_id) + } else { + "_inner".into() + }; let (main_pre, main_post) = if returns_result { ( - "fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {", - "}\n_inner().unwrap() }", + format!( + "fn main() {{ fn {}() -> Result<(), impl core::fmt::Debug> {{\n", + inner_fn_name + ), + format!("\n}}; {}().unwrap() }}", inner_fn_name), + ) + } else if test_id.is_some() { + ( + format!("fn main() {{ fn {}() {{\n", inner_fn_name), + format!("\n}}; {}() }}", inner_fn_name), ) } else { - ("fn main() {\n", "\n}") + ("fn main() {\n".into(), "\n}".into()) }; - prog.extend([main_pre, everything_else, main_post].iter().cloned()); + // Note on newlines: We insert a line/newline *before*, and *after* + // the doctest and adjust the `line_offset` accordingly. + // In the case of `-Z instrument-coverage`, this means that the generated + // inner `main` function spans from the doctest opening codeblock to the + // closing one. For example + // /// ``` <- start of the inner main + // /// <- code under doctest + // /// ``` <- end of the inner main line_offset += 1; + + prog.extend([&main_pre, everything_else, &main_post].iter().cloned()); } debug!("final doctest:\n{}", prog); @@ -749,28 +775,24 @@ impl Tester for Collector { _ => PathBuf::from(r"doctest.rs"), }; + // For example `module/file.rs` would become `module_file_rs` + let file = filename + .to_string() + .chars() + .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' }) + .collect::(); + let test_id = format!( + "{file}_{line}_{number}", + file = file, + line = line, + number = { + // Increases the current test number, if this file already + // exists or it creates a new entry with a test number of 0. + self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0) + }, + ); let outdir = if let Some(mut path) = options.persist_doctests.clone() { - // For example `module/file.rs` would become `module_file_rs` - let folder_name = filename - .to_string() - .chars() - .map(|c| if c == '\\' || c == '/' || c == '.' { '_' } else { c }) - .collect::(); - - path.push(format!( - "{krate}_{file}_{line}_{number}", - krate = cratename, - file = folder_name, - line = line, - number = { - // Increases the current test number, if this file already - // exists or it creates a new entry with a test number of 0. - self.visited_tests - .entry((folder_name.clone(), line)) - .and_modify(|v| *v += 1) - .or_insert(0) - }, - )); + path.push(&test_id); std::fs::create_dir_all(&path) .expect("Couldn't create directory for doctest executables"); @@ -817,6 +839,7 @@ impl Tester for Collector { edition, outdir, path, + &test_id, ); if let Err(err) = res { diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index a024e9c72a43..7c0df673c1b9 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -11,7 +11,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -26,7 +26,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -44,7 +44,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 3)); } @@ -61,7 +61,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -79,7 +79,7 @@ use std::*; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -98,7 +98,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -115,7 +115,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -134,7 +134,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 3)); // Adding more will also bump the returned line offset. @@ -147,7 +147,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 4)); } @@ -164,7 +164,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -180,7 +180,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } @@ -196,7 +196,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -210,7 +210,7 @@ assert_eq!(2+2, 4);"; //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);" .to_string(); - let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } @@ -224,7 +224,7 @@ fn make_test_display_warnings() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } @@ -242,7 +242,7 @@ assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); let input = "extern crate hella_qwop; @@ -256,7 +256,7 @@ assert_eq!(asdf::foo, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 3)); } @@ -274,6 +274,41 @@ test_wrapper! { }" .to_string(); - let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } + +#[test] +fn make_test_returns_result() { + // creates an inner function and unwraps it + let opts = TestOptions::default(); + let input = "use std::io; +let mut input = String::new(); +io::stdin().read_line(&mut input)?; +Ok::<(), io:Error>(())"; + let expected = "#![allow(unused)] +fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> { +use std::io; +let mut input = String::new(); +io::stdin().read_line(&mut input)?; +Ok::<(), io:Error>(()) +}; _inner().unwrap() }" + .to_string(); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); + assert_eq!((output, len), (expected, 2)); +} + +#[test] +fn make_test_named_wrapper() { + // creates an inner function with a specific name + let opts = TestOptions::default(); + let input = "assert_eq!(2+2, 4);"; + let expected = "#![allow(unused)] +fn main() { fn _doctest_main_some_unique_name() { +assert_eq!(2+2, 4); +}; _doctest_main_some_unique_name() }" + .to_string(); + let (output, len, _) = + make_test(input, None, false, &opts, DEFAULT_EDITION, Some("some_unique_name")); + assert_eq!((output, len), (expected, 2)); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 22096203d4ce..f911a2ce3fc7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -248,7 +248,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .join("\n"); let krate = krate.as_ref().map(|s| &**s); let (test, _, _) = - doctest::make_test(&test, krate, false, &Default::default(), edition); + doctest::make_test(&test, krate, false, &Default::default(), edition, None); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let edition_string = format!("&edition={}", edition); diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 5c24f909130c..c4700b317efa 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -98,7 +98,7 @@ endif # Run it in order to generate some profiling data, # with `LLVM_PROFILE_FILE=` environment variable set to # output the coverage stats for this run. - LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \ + LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \ $(call RUN,$@) || \ ( \ status=$$?; \ @@ -108,9 +108,16 @@ endif ) \ ) + # Run it through rustdoc as well to cover doctests + LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \ + $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \ + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && echo "--edition=2018" ) \ + -L "$(TMPDIR)" -Zinstrument-coverage \ + -Z unstable-options --persist-doctests=$(TMPDIR)/rustdoc-$@ + # Postprocess the profiling data so it can be used by the llvm-cov tool "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \ - "$(TMPDIR)"/$@.profraw \ + "$(TMPDIR)"/$@-*.profraw \ -o "$(TMPDIR)"/$@.profdata # Generate a coverage report using `llvm-cov show`. @@ -121,8 +128,15 @@ endif --show-line-counts-or-regions \ --instr-profile="$(TMPDIR)"/$@.profdata \ $(call BIN,"$(TMPDIR)"/$@) \ - > "$(TMPDIR)"/actual_show_coverage.$@.txt \ - 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt || \ + $$( \ + for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \ + do \ + [[ -x $$file ]] && printf "%s %s " -object $$file; \ + done \ + ) \ + 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \ + | "$(PYTHON)" $(BASEDIR)/normalize_paths.py \ + > "$(TMPDIR)"/actual_show_coverage.$@.txt || \ ( status=$$? ; \ >&2 cat "$(TMPDIR)"/show_coverage_stderr.$@.txt ; \ exit $$status \ diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt new file mode 100644 index 000000000000..e1731c7223c5 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt @@ -0,0 +1,79 @@ +../coverage/doctest.rs: + 1| |//! This test ensures that code from doctests is properly re-mapped. + 2| |//! See for more info. + 3| |//! + 4| |//! Just some random code: + 5| 1|//! ``` + 6| 1|//! if true { + 7| |//! // this is executed! + 8| 1|//! assert_eq!(1, 1); + 9| |//! } else { + 10| |//! // this is not! + 11| |//! assert_eq!(1, 2); + 12| |//! } + 13| 1|//! ``` + 14| |//! + 15| |//! doctest testing external code: + 16| |//! ``` + 17| 1|//! extern crate doctest_crate; + 18| 1|//! doctest_crate::fn_run_in_doctests(1); + 19| 1|//! ``` + 20| |//! + 21| |//! doctest returning a result: + 22| 1|//! ``` + 23| 1|//! #[derive(Debug)] + 24| 1|//! struct SomeError; + 25| 1|//! let mut res = Err(SomeError); + 26| 1|//! if res.is_ok() { + 27| 0|//! res?; + 28| 1|//! } else { + 29| 1|//! res = Ok(0); + 30| 1|//! } + 31| |//! // need to be explicit because rustdoc cant infer the return type + 32| 1|//! Ok::<(), SomeError>(()) + 33| 1|//! ``` + 34| |//! + 35| |//! doctest with custom main: + 36| |//! ``` + 37| |//! #[derive(Debug)] + 38| |//! struct SomeError; + 39| |//! + 40| |//! extern crate doctest_crate; + 41| |//! + 42| 1|//! fn doctest_main() -> Result<(), SomeError> { + 43| 1|//! doctest_crate::fn_run_in_doctests(2); + 44| 1|//! Ok(()) + 45| 1|//! } + 46| |//! + 47| |//! // this `main` is not shown as covered, as it clashes with all the other + 48| |//! // `main` functions that were automatically generated for doctests + 49| |//! fn main() -> Result<(), SomeError> { + 50| |//! doctest_main() + 51| |//! } + 52| |//! ``` + 53| | + 54| |/// doctest attached to fn testing external code: + 55| |/// ``` + 56| 1|/// extern crate doctest_crate; + 57| 1|/// doctest_crate::fn_run_in_doctests(3); + 58| 1|/// ``` + 59| |/// + 60| 1|fn main() { + 61| 1| if true { + 62| 1| assert_eq!(1, 1); + 63| | } else { + 64| | assert_eq!(1, 2); + 65| | } + 66| 1|} + +../coverage/lib/doctest_crate.rs: + 1| |/// A function run only from within doctests + 2| 3|pub fn fn_run_in_doctests(conditional: usize) { + 3| 3| match conditional { + 4| 1| 1 => assert_eq!(1, 1), // this is run, + 5| 1| 2 => assert_eq!(1, 1), // this, + 6| 1| 3 => assert_eq!(1, 1), // and this too + 7| 0| _ => assert_eq!(1, 2), // however this is not + 8| | } + 9| 3|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index e14e733fff6d..4c03e950af02 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -19,12 +19,12 @@ 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 19| 2|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_crate::used_only_from_bin_crate_generic_function::<&str>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py new file mode 100644 index 000000000000..05fb412cdb63 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +import sys + +# Normalize file paths in output +for line in sys.stdin: + if line.startswith("..") and line.rstrip().endswith(".rs:"): + print(line.replace("\\", "/"), end='') + else: + print(line, end='') diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..8d074558aae2 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,127 @@ + + + + +doctest.main - Coverage Spans + + + +
@0⦊fn main() ⦉@0{ + if @0⦊true⦉@0 { + @5⦊@4,6,7,8,9⦊assert_eq!(1, 1);⦉@4,6,7,8,9⦉@5 + } else { + @11⦊@10,12,13,14,15⦊assert_eq!(1, 2);⦉@10,12,13,14,15⦉@11 + } +}@16⦊⦉@16
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..ae119d9ca9f2 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html @@ -0,0 +1,173 @@ + + + + +doctest_crate.fn_run_in_doctests - Coverage Spans + + + +
@0⦊pub fn fn_run_in_doctests(conditional: usize) ⦉@0{ + match @0⦊conditional⦉@0 { + 1 => @7⦊@6,8,9,10,11⦊assert_eq!(1, 1)⦉@6,8,9,10,11⦉@7, // this is run, + 2 => @14⦊@13,15,16,17,18⦊assert_eq!(1, 1)⦉@13,15,16,17,18⦉@14, // this, + 3 => @21⦊@20,22,23,24,25⦊assert_eq!(1, 1)⦉@20,22,23,24,25⦉@21, // and this too + _ => @27⦊@26,28,29,30,31⦊assert_eq!(1, 2)⦉@26,28,29,30,31⦉@27, // however this is not + } +}@32⦊⦉@32
+ + diff --git a/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir b/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir index abf8df8fdc9e..d1824d189e38 100644 --- a/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir +++ b/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir @@ -1,3 +1,3 @@ -# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-* +# Directory "coverage" supports the tests at prefix ../coverage-* -# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests. +# Use ./x.py [options] test src/test/run-make-fulldeps/coverage to run all related tests. diff --git a/src/test/run-make-fulldeps/coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk index 7dc485cd94d6..4d340d4b1dad 100644 --- a/src/test/run-make-fulldeps/coverage/coverage_tools.mk +++ b/src/test/run-make-fulldeps/coverage/coverage_tools.mk @@ -1,7 +1,7 @@ -# Common Makefile include for Rust `run-make-fulldeps/instrument-coverage-* tests. Include this +# Common Makefile include for Rust `run-make-fulldeps/coverage-* tests. Include this # file with the line: # -# -include ../instrument-coverage/coverage_tools.mk +# -include ../coverage/coverage_tools.mk -include ../tools.mk diff --git a/src/test/run-make-fulldeps/coverage/doctest.rs b/src/test/run-make-fulldeps/coverage/doctest.rs new file mode 100644 index 000000000000..e41d669bf0c7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/doctest.rs @@ -0,0 +1,66 @@ +//! This test ensures that code from doctests is properly re-mapped. +//! See for more info. +//! +//! Just some random code: +//! ``` +//! if true { +//! // this is executed! +//! assert_eq!(1, 1); +//! } else { +//! // this is not! +//! assert_eq!(1, 2); +//! } +//! ``` +//! +//! doctest testing external code: +//! ``` +//! extern crate doctest_crate; +//! doctest_crate::fn_run_in_doctests(1); +//! ``` +//! +//! doctest returning a result: +//! ``` +//! #[derive(Debug)] +//! struct SomeError; +//! let mut res = Err(SomeError); +//! if res.is_ok() { +//! res?; +//! } else { +//! res = Ok(0); +//! } +//! // need to be explicit because rustdoc cant infer the return type +//! Ok::<(), SomeError>(()) +//! ``` +//! +//! doctest with custom main: +//! ``` +//! #[derive(Debug)] +//! struct SomeError; +//! +//! extern crate doctest_crate; +//! +//! fn doctest_main() -> Result<(), SomeError> { +//! doctest_crate::fn_run_in_doctests(2); +//! Ok(()) +//! } +//! +//! // this `main` is not shown as covered, as it clashes with all the other +//! // `main` functions that were automatically generated for doctests +//! fn main() -> Result<(), SomeError> { +//! doctest_main() +//! } +//! ``` + +/// doctest attached to fn testing external code: +/// ``` +/// extern crate doctest_crate; +/// doctest_crate::fn_run_in_doctests(3); +/// ``` +/// +fn main() { + if true { + assert_eq!(1, 1); + } else { + assert_eq!(1, 2); + } +} diff --git a/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs b/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs new file mode 100644 index 000000000000..c3210146d69b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs @@ -0,0 +1,9 @@ +/// A function run only from within doctests +pub fn fn_run_in_doctests(conditional: usize) { + match conditional { + 1 => assert_eq!(1, 1), // this is run, + 2 => assert_eq!(1, 1), // this, + 3 => assert_eq!(1, 1), // and this too + _ => assert_eq!(1, 2), // however this is not + } +} From 8ddf4ce87a1a0a50d015e40bf9cebede68f64d0a Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Sat, 19 Dec 2020 13:54:38 +0100 Subject: [PATCH 423/719] UI Tests: Separate suspicious_else_formatting tests --- tests/ui/formatting.rs | 87 +-------------------- tests/ui/formatting.stderr | 89 ++-------------------- tests/ui/suspicious_else_formatting.rs | 79 +++++++++++++++++++ tests/ui/suspicious_else_formatting.stderr | 77 +++++++++++++++++++ 4 files changed, 164 insertions(+), 168 deletions(-) create mode 100644 tests/ui/suspicious_else_formatting.rs create mode 100644 tests/ui/suspicious_else_formatting.stderr diff --git a/tests/ui/formatting.rs b/tests/ui/formatting.rs index f54b3f2bfe28..0d14807ff1cf 100644 --- a/tests/ui/formatting.rs +++ b/tests/ui/formatting.rs @@ -10,91 +10,6 @@ fn foo() -> bool { #[rustfmt::skip] fn main() { - // weird `else` formatting: - if foo() { - } { - } - - if foo() { - } if foo() { - } - - let _ = { // if as the last expression - let _ = 0; - - if foo() { - } if foo() { - } - else { - } - }; - - let _ = { // if in the middle of a block - if foo() { - } if foo() { - } - else { - } - - let _ = 0; - }; - - if foo() { - } else - { - } - - if foo() { - } - else - { - } - - if foo() { - } else - if foo() { // the span of the above error should continue here - } - - if foo() { - } - else - if foo() { // the span of the above error should continue here - } - - // those are ok: - if foo() { - } - { - } - - if foo() { - } else { - } - - if foo() { - } - else { - } - - if foo() { - } - if foo() { - } - - if foo() { - } else if foo() { - } - - if foo() { - } - else if foo() { - } - - if foo() { - } - else if - foo() {} - // weird op_eq formatting: let mut a = 42; a =- 35; @@ -146,7 +61,7 @@ fn main() { // don't lint if the indentation suggests not to let _ = &[ - 1 + 2, 3 + 1 + 2, 3 - 4, 5 ]; // lint if it doesn't diff --git a/tests/ui/formatting.stderr b/tests/ui/formatting.stderr index e2095cc125bb..bde434c7e2e7 100644 --- a/tests/ui/formatting.stderr +++ b/tests/ui/formatting.stderr @@ -1,80 +1,5 @@ -error: this looks like an `else {..}` but the `else` is missing - --> $DIR/formatting.rs:15:6 - | -LL | } { - | ^ - | - = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings` - = note: to remove this lint, add the missing `else` or add a new line before the next block - -error: this looks like an `else if` but the `else` is missing - --> $DIR/formatting.rs:19:6 - | -LL | } if foo() { - | ^ - | - = note: to remove this lint, add the missing `else` or add a new line before the second `if` - -error: this looks like an `else if` but the `else` is missing - --> $DIR/formatting.rs:26:10 - | -LL | } if foo() { - | ^ - | - = note: to remove this lint, add the missing `else` or add a new line before the second `if` - -error: this looks like an `else if` but the `else` is missing - --> $DIR/formatting.rs:34:10 - | -LL | } if foo() { - | ^ - | - = note: to remove this lint, add the missing `else` or add a new line before the second `if` - -error: this is an `else {..}` but the formatting might hide it - --> $DIR/formatting.rs:43:6 - | -LL | } else - | ______^ -LL | | { - | |____^ - | - = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` - -error: this is an `else {..}` but the formatting might hide it - --> $DIR/formatting.rs:48:6 - | -LL | } - | ______^ -LL | | else -LL | | { - | |____^ - | - = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` - -error: this is an `else if` but the formatting might hide it - --> $DIR/formatting.rs:54:6 - | -LL | } else - | ______^ -LL | | if foo() { // the span of the above error should continue here - | |____^ - | - = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` - -error: this is an `else if` but the formatting might hide it - --> $DIR/formatting.rs:59:6 - | -LL | } - | ______^ -LL | | else -LL | | if foo() { // the span of the above error should continue here - | |____^ - | - = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` - error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)` - --> $DIR/formatting.rs:100:6 + --> $DIR/formatting.rs:15:6 | LL | a =- 35; | ^^^^ @@ -83,7 +8,7 @@ LL | a =- 35; = note: to remove this lint, use either `-=` or `= -` error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)` - --> $DIR/formatting.rs:101:6 + --> $DIR/formatting.rs:16:6 | LL | a =* &191; | ^^^^ @@ -91,7 +16,7 @@ LL | a =* &191; = note: to remove this lint, use either `*=` or `= *` error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)` - --> $DIR/formatting.rs:104:6 + --> $DIR/formatting.rs:19:6 | LL | b =! false; | ^^^^ @@ -99,7 +24,7 @@ LL | b =! false; = note: to remove this lint, use either `!=` or `= !` error: possibly missing a comma here - --> $DIR/formatting.rs:113:19 + --> $DIR/formatting.rs:28:19 | LL | -1, -2, -3 // <= no comma here | ^ @@ -108,7 +33,7 @@ LL | -1, -2, -3 // <= no comma here = note: to remove this lint, add a comma or write the expr in a single line error: possibly missing a comma here - --> $DIR/formatting.rs:117:19 + --> $DIR/formatting.rs:32:19 | LL | -1, -2, -3 // <= no comma here | ^ @@ -116,12 +41,12 @@ LL | -1, -2, -3 // <= no comma here = note: to remove this lint, add a comma or write the expr in a single line error: possibly missing a comma here - --> $DIR/formatting.rs:154:11 + --> $DIR/formatting.rs:69:11 | LL | -1 | ^ | = note: to remove this lint, add a comma or write the expr in a single line -error: aborting due to 14 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/suspicious_else_formatting.rs b/tests/ui/suspicious_else_formatting.rs new file mode 100644 index 000000000000..226010ec6df3 --- /dev/null +++ b/tests/ui/suspicious_else_formatting.rs @@ -0,0 +1,79 @@ +#![warn(clippy::suspicious_else_formatting)] + +fn foo() -> bool { + true +} + +#[rustfmt::skip] +fn main() { + // weird `else` formatting: + if foo() { + } { + } + + if foo() { + } if foo() { + } + + let _ = { // if as the last expression + let _ = 0; + + if foo() { + } if foo() { + } + else { + } + }; + + let _ = { // if in the middle of a block + if foo() { + } if foo() { + } + else { + } + + let _ = 0; + }; + + if foo() { + } else + { + } + + if foo() { + } + else + { + } + + if foo() { + } else + if foo() { // the span of the above error should continue here + } + + if foo() { + } + else + if foo() { // the span of the above error should continue here + } + + // those are ok: + if foo() { + } + { + } + + if foo() { + } else { + } + + if foo() { + } + else { + } + + if foo() { + } + if foo() { + } +} diff --git a/tests/ui/suspicious_else_formatting.stderr b/tests/ui/suspicious_else_formatting.stderr new file mode 100644 index 000000000000..bbc036d376fe --- /dev/null +++ b/tests/ui/suspicious_else_formatting.stderr @@ -0,0 +1,77 @@ +error: this looks like an `else {..}` but the `else` is missing + --> $DIR/suspicious_else_formatting.rs:11:6 + | +LL | } { + | ^ + | + = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings` + = note: to remove this lint, add the missing `else` or add a new line before the next block + +error: this looks like an `else if` but the `else` is missing + --> $DIR/suspicious_else_formatting.rs:15:6 + | +LL | } if foo() { + | ^ + | + = note: to remove this lint, add the missing `else` or add a new line before the second `if` + +error: this looks like an `else if` but the `else` is missing + --> $DIR/suspicious_else_formatting.rs:22:10 + | +LL | } if foo() { + | ^ + | + = note: to remove this lint, add the missing `else` or add a new line before the second `if` + +error: this looks like an `else if` but the `else` is missing + --> $DIR/suspicious_else_formatting.rs:30:10 + | +LL | } if foo() { + | ^ + | + = note: to remove this lint, add the missing `else` or add a new line before the second `if` + +error: this is an `else {..}` but the formatting might hide it + --> $DIR/suspicious_else_formatting.rs:39:6 + | +LL | } else + | ______^ +LL | | { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` + +error: this is an `else {..}` but the formatting might hide it + --> $DIR/suspicious_else_formatting.rs:44:6 + | +LL | } + | ______^ +LL | | else +LL | | { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` + +error: this is an `else if` but the formatting might hide it + --> $DIR/suspicious_else_formatting.rs:50:6 + | +LL | } else + | ______^ +LL | | if foo() { // the span of the above error should continue here + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` + +error: this is an `else if` but the formatting might hide it + --> $DIR/suspicious_else_formatting.rs:55:6 + | +LL | } + | ______^ +LL | | else +LL | | if foo() { // the span of the above error should continue here + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` + +error: aborting due to 8 previous errors + From 1a7d00a529503ac38a6b1ae28e8e779e434e02e0 Mon Sep 17 00:00:00 2001 From: mark Date: Tue, 10 Nov 2020 18:00:53 -0600 Subject: [PATCH 424/719] implement edition-specific :pat behavior for 2015/18 --- compiler/rustc_expand/src/mbe/macro_parser.rs | 33 ++++++++++--- compiler/rustc_parse/src/parser/expr.rs | 8 ++-- compiler/rustc_parse/src/parser/mod.rs | 1 + .../rustc_parse/src/parser/nonterminal.rs | 23 +++++++-- compiler/rustc_parse/src/parser/pat.rs | 17 +++++-- compiler/rustc_parse/src/parser/stmt.rs | 4 +- src/test/ui/macros/macro-pat-follow-2018.rs | 15 ++++++ src/test/ui/macros/macro-pat-follow.rs | 16 ++----- .../or-patterns-syntactic-fail-2018.rs | 15 ++++++ .../or-patterns-syntactic-fail-2018.stderr | 20 ++++++++ .../or-patterns/or-patterns-syntactic-fail.rs | 10 ---- .../or-patterns-syntactic-fail.stderr | 48 ++++++------------- .../or-patterns-syntactic-pass-2021.rs | 14 ++++++ src/test/ui/pattern/or-pattern-macro-pat.rs | 44 +++++++++++++++++ 14 files changed, 193 insertions(+), 75 deletions(-) create mode 100644 src/test/ui/macros/macro-pat-follow-2018.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs create mode 100644 src/test/ui/pattern/or-pattern-macro-pat.rs diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index c37f91256757..3cf2d8f8ac1e 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -77,9 +77,9 @@ use TokenTreeOrTokenTreeSlice::*; use crate::mbe::{self, TokenTree}; use rustc_ast::token::{self, DocComment, Nonterminal, Token}; -use rustc_parse::parser::Parser; +use rustc_parse::parser::{OrPatNonterminalMode, Parser}; use rustc_session::parse::ParseSess; -use rustc_span::symbol::MacroRulesNormalizedIdent; +use rustc_span::{edition::Edition, symbol::MacroRulesNormalizedIdent}; use smallvec::{smallvec, SmallVec}; @@ -414,6 +414,18 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { } } +/// In edition 2015/18, `:pat` can only match `pat` because otherwise, we have +/// breakage. As of edition 2021, `:pat` matches `top_pat`. +/// +/// See for more info. +fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode { + match edition { + Edition::Edition2015 | Edition::Edition2018 => OrPatNonterminalMode::NoTopAlt, + // FIXME(mark-i-m): uncomment this when edition 2021 machinery is added. + // Edition::Edition2021 => OrPatNonterminalMode::TopPat, + } +} + /// Process the matcher positions of `cur_items` until it is empty. In the process, this will /// produce more items in `next_items`, `eof_items`, and `bb_items`. /// @@ -553,10 +565,14 @@ fn inner_parse_loop<'root, 'tt>( // We need to match a metavar with a valid ident... call out to the black-box // parser by adding an item to `bb_items`. - TokenTree::MetaVarDecl(_, _, kind) => { - // Built-in nonterminals never start with these tokens, - // so we can eliminate them from consideration. - if Parser::nonterminal_may_begin_with(kind, token) { + TokenTree::MetaVarDecl(span, _, kind) => { + // Built-in nonterminals never start with these tokens, so we can eliminate + // them from consideration. + // + // We use the span of the metavariable declaration to determine any + // edition-specific matching behavior for non-terminals. + if Parser::nonterminal_may_begin_with(kind, token, or_pat_mode(span.edition())) + { bb_items.push(item); } } @@ -717,7 +733,10 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na let mut item = bb_items.pop().unwrap(); if let TokenTree::MetaVarDecl(span, _, kind) = item.top_elts.get_tt(item.idx) { let match_cur = item.match_cur; - let nt = match parser.to_mut().parse_nonterminal(kind) { + // We use the span of the metavariable declaration to determine any + // edition-specific matching behavior for non-terminals. + let nt = match parser.to_mut().parse_nonterminal(kind, or_pat_mode(span.edition())) + { Err(mut err) => { err.span_label( span, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4d2167442bed..eed3e9947b2a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,4 +1,4 @@ -use super::pat::{GateOr, PARAM_EXPECTED}; +use super::pat::{GateOr, RecoverComma, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; @@ -1729,7 +1729,7 @@ impl<'a> Parser<'a> { /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::No)?; + let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?; self.expect(&token::Eq)?; let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| { this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) @@ -1792,7 +1792,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_pat(GateOr::Yes)?; + let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; if !self.eat_keyword(kw::In) { self.error_missing_in_for_loop(); } @@ -1902,7 +1902,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - let pat = self.parse_top_pat(GateOr::No)?; + let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?; let guard = if self.eat_keyword(kw::If) { let if_span = self.prev_token.span; let cond = self.parse_expr()?; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d51a0fcbf09e..e19ebb8fd2fb 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -12,6 +12,7 @@ mod ty; use crate::lexer::UnmatchedBrace; pub use diagnostics::AttemptLocalParseRecovery; use diagnostics::Error; +pub use pat::OrPatNonterminalMode; pub use path::PathStyle; use rustc_ast::ptr::P; diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 76ad5acd5303..a6b9ac1014e8 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -4,6 +4,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; +use crate::parser::pat::{GateOr, OrPatNonterminalMode, RecoverComma}; use crate::parser::{FollowedByType, Parser, PathStyle}; impl<'a> Parser<'a> { @@ -11,7 +12,11 @@ impl<'a> Parser<'a> { /// /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that /// token. Be conservative (return true) if not sure. - pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool { + pub fn nonterminal_may_begin_with( + kind: NonterminalKind, + token: &Token, + or_pat_mode: OrPatNonterminalMode, + ) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { match *nt { @@ -70,6 +75,8 @@ impl<'a> Parser<'a> { token::ModSep | // path token::Lt | // path (UFCS constant) token::BinOp(token::Shl) => true, // path (double UFCS) + // leading vert `|` or-pattern + token::BinOp(token::Or) => matches!(or_pat_mode, OrPatNonterminalMode::TopPat), token::Interpolated(ref nt) => may_be_ident(nt), _ => false, }, @@ -86,7 +93,12 @@ impl<'a> Parser<'a> { } } - pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonterminal> { + /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). + pub fn parse_nonterminal( + &mut self, + kind: NonterminalKind, + or_pat_mode: OrPatNonterminalMode, + ) -> PResult<'a, Nonterminal> { // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`) // needs to have them force-captured here. // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, @@ -130,7 +142,12 @@ impl<'a> Parser<'a> { } } NonterminalKind::Pat => { - let (mut pat, tokens) = self.collect_tokens(|this| this.parse_pat(None))?; + let (mut pat, tokens) = self.collect_tokens(|this| match or_pat_mode { + OrPatNonterminalMode::TopPat => { + this.parse_top_pat(GateOr::Yes, RecoverComma::No) + } + OrPatNonterminalMode::NoTopAlt => this.parse_pat(None), + })?; // We have have eaten an NtPat, which could already have tokens if pat.tokens.is_none() { pat.tokens = tokens; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index b62c73738008..1da371e0b729 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -26,11 +26,18 @@ pub(super) enum GateOr { /// Whether or not to recover a `,` when parsing or-patterns. #[derive(PartialEq, Copy, Clone)] -enum RecoverComma { +pub(super) enum RecoverComma { Yes, No, } +/// Used when parsing a non-terminal (see `parse_nonterminal`) to determine if `:pat` should match +/// `top_pat` or `pat`. See issue . +pub enum OrPatNonterminalMode { + TopPat, + NoTopAlt, +} + impl<'a> Parser<'a> { /// Parses a pattern. /// @@ -43,13 +50,17 @@ impl<'a> Parser<'a> { /// Entry point to the main pattern parser. /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. - pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { + pub(super) fn parse_top_pat( + &mut self, + gate_or: GateOr, + rc: RecoverComma, + ) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes; let leading_vert_span = self.prev_token.span; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; + let pat = self.parse_pat_with_or(None, gate_or, rc)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index e974556f43a4..2942747991a1 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -1,7 +1,7 @@ use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN; use super::diagnostics::{AttemptLocalParseRecovery, Error}; use super::expr::LhsExpr; -use super::pat::GateOr; +use super::pat::{GateOr, RecoverComma}; use super::path::PathStyle; use super::{BlockMode, Parser, Restrictions, SemiColonMode}; use crate::maybe_whole; @@ -185,7 +185,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::Yes)?; + let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; let (err, ty) = if self.eat(&token::Colon) { // Save the state of the parser before parsing type normally, in case there is a `:` diff --git a/src/test/ui/macros/macro-pat-follow-2018.rs b/src/test/ui/macros/macro-pat-follow-2018.rs new file mode 100644 index 000000000000..ce2911de986d --- /dev/null +++ b/src/test/ui/macros/macro-pat-follow-2018.rs @@ -0,0 +1,15 @@ +// run-pass +// edition:2018 + +macro_rules! pat_bar { + ($p:pat | $p2:pat) => {{ + match Some(1u8) { + $p | $p2 => {} + _ => {} + } + }}; +} + +fn main() { + pat_bar!(Some(1u8) | None); +} diff --git a/src/test/ui/macros/macro-pat-follow.rs b/src/test/ui/macros/macro-pat-follow.rs index 8673cf794678..8e02789fdd8d 100644 --- a/src/test/ui/macros/macro-pat-follow.rs +++ b/src/test/ui/macros/macro-pat-follow.rs @@ -3,29 +3,19 @@ macro_rules! pat_in { ($p:pat in $e:expr) => {{ let mut iter = $e.into_iter(); while let $p = iter.next() {} - }} + }}; } macro_rules! pat_if { ($p:pat if $e:expr) => {{ match Some(1u8) { - $p if $e => {}, + $p if $e => {} _ => {} } - }} -} - -macro_rules! pat_bar { - ($p:pat | $p2:pat) => {{ - match Some(1u8) { - $p | $p2 => {}, - _ => {} - } - }} + }}; } fn main() { pat_in!(Some(_) in 0..10); pat_if!(Some(x) if x > 0); - pat_bar!(Some(1u8) | None); } diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs new file mode 100644 index 000000000000..9c3c5dd360e0 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs @@ -0,0 +1,15 @@ +// Test that :pat doesn't accept top-level or-patterns in edition 2018. + +// edition:2018 + +#![feature(or_patterns)] + +fn main() {} + +// Test the `pat` macro fragment parser: +macro_rules! accept_pat { + ($p:pat) => {}; +} + +accept_pat!(p | q); //~ ERROR no rules expected the token `|` +accept_pat!(|p| q); //~ ERROR no rules expected the token `|` diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr new file mode 100644 index 000000000000..7dbc30876634 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr @@ -0,0 +1,20 @@ +error: no rules expected the token `|` + --> $DIR/or-patterns-syntactic-fail-2018.rs:14:15 + | +LL | macro_rules! accept_pat { + | ----------------------- when calling this macro +... +LL | accept_pat!(p | q); + | ^ no rules expected this token in macro call + +error: no rules expected the token `|` + --> $DIR/or-patterns-syntactic-fail-2018.rs:15:13 + | +LL | macro_rules! accept_pat { + | ----------------------- when calling this macro +... +LL | accept_pat!(|p| q); + | ^ no rules expected this token in macro call + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs index d23220056524..efe90b3e3c60 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -5,16 +5,6 @@ fn main() {} -// Test the `pat` macro fragment parser: -macro_rules! accept_pat { - ($p:pat) => {} -} - -accept_pat!(p | q); //~ ERROR no rules expected the token `|` -accept_pat!(| p | q); //~ ERROR no rules expected the token `|` - -// Non-macro tests: - enum E { A, B } use E::*; diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 861d274ab5c7..989aeb520064 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -1,53 +1,53 @@ error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:27:13 + --> $DIR/or-patterns-syntactic-fail.rs:17:13 | LL | fn fun1(A | B: E) {} | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` error: a leading `|` is not allowed in a parameter pattern - --> $DIR/or-patterns-syntactic-fail.rs:29:13 + --> $DIR/or-patterns-syntactic-fail.rs:19:13 | LL | fn fun2(| A | B: E) {} | ^ help: remove the `|` error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:29:15 + --> $DIR/or-patterns-syntactic-fail.rs:19:15 | LL | fn fun2(| A | B: E) {} | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:40:11 + --> $DIR/or-patterns-syntactic-fail.rs:30:11 | LL | let ( | A | B) = E::A; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:41:11 + --> $DIR/or-patterns-syntactic-fail.rs:31:11 | LL | let ( | A | B,) = (E::B,); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:42:11 + --> $DIR/or-patterns-syntactic-fail.rs:32:11 | LL | let [ | A | B ] = [E::A]; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:43:13 + --> $DIR/or-patterns-syntactic-fail.rs:33:13 | LL | let TS( | A | B ); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:44:17 + --> $DIR/or-patterns-syntactic-fail.rs:34:17 | LL | let NS { f: | A | B }; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:46:11 + --> $DIR/or-patterns-syntactic-fail.rs:36:11 | LL | let ( || A | B) = E::A; | ^^ help: remove the `||` @@ -55,7 +55,7 @@ LL | let ( || A | B) = E::A; = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:47:11 + --> $DIR/or-patterns-syntactic-fail.rs:37:11 | LL | let [ || A | B ] = [E::A]; | ^^ help: remove the `||` @@ -63,7 +63,7 @@ LL | let [ || A | B ] = [E::A]; = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:48:13 + --> $DIR/or-patterns-syntactic-fail.rs:38:13 | LL | let TS( || A | B ); | ^^ help: remove the `||` @@ -71,33 +71,15 @@ LL | let TS( || A | B ); = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:49:17 + --> $DIR/or-patterns-syntactic-fail.rs:39:17 | LL | let NS { f: || A | B }; | ^^ help: remove the `||` | = note: alternatives in or-patterns are separated with `|`, not `||` -error: no rules expected the token `|` - --> $DIR/or-patterns-syntactic-fail.rs:13:15 - | -LL | macro_rules! accept_pat { - | ----------------------- when calling this macro -... -LL | accept_pat!(p | q); - | ^ no rules expected this token in macro call - -error: no rules expected the token `|` - --> $DIR/or-patterns-syntactic-fail.rs:14:13 - | -LL | macro_rules! accept_pat { - | ----------------------- when calling this macro -... -LL | accept_pat!(| p | q); - | ^ no rules expected this token in macro call - error[E0369]: no implementation for `E | ()` - --> $DIR/or-patterns-syntactic-fail.rs:23:22 + --> $DIR/or-patterns-syntactic-fail.rs:13:22 | LL | let _ = |A | B: E| (); | ----^ -- () @@ -107,7 +89,7 @@ LL | let _ = |A | B: E| (); = note: an implementation of `std::ops::BitOr` might be missing for `E` error[E0308]: mismatched types - --> $DIR/or-patterns-syntactic-fail.rs:51:36 + --> $DIR/or-patterns-syntactic-fail.rs:41:36 | LL | let recovery_witness: String = 0; | ------ ^ @@ -116,7 +98,7 @@ LL | let recovery_witness: String = 0; | | help: try using a conversion method: `0.to_string()` | expected due to this -error: aborting due to 16 previous errors +error: aborting due to 14 previous errors Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs new file mode 100644 index 000000000000..f0ce7597aeed --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs @@ -0,0 +1,14 @@ +// Tests that :pat in macros in edition 2021 allows top-level or-patterns. + +// run-pass +// ignore-test +// edition:2021 +// FIXME(mark-i-m): unignore when 2021 machinery is in place. + +macro_rules! accept_pat { + ($p:pat) => {}; +} + +accept_pat!(p | q); + +fn main() {} diff --git a/src/test/ui/pattern/or-pattern-macro-pat.rs b/src/test/ui/pattern/or-pattern-macro-pat.rs new file mode 100644 index 000000000000..8749407675b3 --- /dev/null +++ b/src/test/ui/pattern/or-pattern-macro-pat.rs @@ -0,0 +1,44 @@ +// run-pass +// edition:2021 +// ignore-test +// FIXME(mark-i-m): enable this test again when 2021 machinery is available + +#![feature(or_patterns)] + +use Foo::*; + +#[derive(Eq, PartialEq, Debug)] +enum Foo { + A(u64), + B(u64), + C, + D, +} + +macro_rules! foo { + ($orpat:pat, $val:expr) => { + match $val { + x @ ($orpat) => x, // leading vert would not be allowed in $orpat + _ => B(0xDEADBEEFu64), + } + }; +} + +macro_rules! bar { + ($orpat:pat, $val:expr) => { + match $val { + $orpat => 42, // leading vert allowed here + _ => 0xDEADBEEFu64, + } + }; +} + +fn main() { + // Test or-pattern. + let y = foo!(A(_)|B(_), A(32)); + assert_eq!(y, A(32)); + + // Leading vert in or-pattern. + let y = bar!(|C| D, C); + assert_eq!(y, 42u64); +} From 2814ee4840c775fcc546c709ffcc63c692eaf548 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sat, 19 Dec 2020 16:12:36 +0000 Subject: [PATCH 425/719] Adapted the website search for better matching * Formatting --- util/gh-pages/index.html | 42 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index e11f2eeba3b3..428708136cb6 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -89,7 +89,7 @@
+ ng-repeat="lint in data | filter:byLevels | filter:byGroups | filter:bySearch | orderBy:'id' track by lint.id">

@@ -215,6 +215,46 @@ return $scope.groups[lint.group]; }; + $scope.bySearch = function (lint, index, array) { + let search_str = $scope.search; + // It can be `null` I haven't missed this value + if (search_str == null || search_str.length == 0) { + return true; + } + search_str = search_str.toLowerCase(); + + // Search by id + let id_search = search_str.trim().replace(/(\-| )/g, "_"); + if (lint.id.includes(id_search)) { + return true; + } + + // Search the description + // The use of `for`-loops instead of `foreach` enables us to return early + let search_lint = (lint, therm) => { + for (const field in lint.docs) { + // Continue if it's not a property + if (!lint.docs.hasOwnProperty(field)) { + continue; + } + + // Return if not found + if (lint.docs[field].toLowerCase().includes(therm)) { + return true; + } + } + return false; + }; + let therms = search_str.split(" "); + for (index = 0; index < therms.length; index++) { + if (!search_lint(lint, therms[index])) { + return false; + } + } + + return true; + } + // Get data $scope.open = {}; $scope.loading = true; From 5b6c175566e55e29c0d2c39cb0dab2119ac40c82 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 19 Dec 2020 17:48:31 +0000 Subject: [PATCH 426/719] Tweak diagnostics --- .../src/thir/pattern/deconstruct_pat.rs | 5 ++--- .../overlapping_range_endpoints.stderr | 16 ++++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 5b1dbabe9a17..94083289cabd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -309,9 +309,7 @@ impl IntRange { pcx.span, |lint| { let mut err = lint.build("multiple patterns overlap on their endpoints"); - err.span_label(pcx.span, "... with this range"); for (int_range, span) in overlaps { - // Use the real type for user display of the ranges: err.span_label( span, &format!( @@ -320,7 +318,8 @@ impl IntRange { ), ); } - err.note("this is likely to be a mistake"); + err.span_label(pcx.span, "... with this range"); + err.note("you likely meant to write mutually exclusive ranges"); err.emit(); }, ); diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr index 045c487873a3..24c0419e1dde 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![deny(overlapping_range_endpoints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this is likely to be a mistake + = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:16:22 @@ -21,7 +21,7 @@ LL | m!(0u8, 30..=40, 20..=30); | | | this range overlaps on `30_u8`... | - = note: this is likely to be a mistake + = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:19:22 @@ -31,7 +31,7 @@ LL | m!(0u8, 20.. 30, 29..=40); | | | this range overlaps on `29_u8`... | - = note: this is likely to be a mistake + = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:23:22 @@ -41,7 +41,7 @@ LL | m!(0u8, 20..=30, 30..=31); | | | this range overlaps on `30_u8`... | - = note: this is likely to be a mistake + = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:27:22 @@ -51,7 +51,7 @@ LL | m!(0u8, 20..=30, 19..=20); | | | this range overlaps on `20_u8`... | - = note: this is likely to be a mistake + = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:39:9 @@ -63,7 +63,7 @@ LL | 20..=30 => {} LL | 10..=20 => {} | ^^^^^^^ ... with this range | - = note: this is likely to be a mistake + = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:50:16 @@ -73,7 +73,7 @@ LL | (true, 0..=10) => {} LL | (true, 10..20) => {} | ^^^^^^ ... with this range | - = note: this is likely to be a mistake + = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints --> $DIR/overlapping_range_endpoints.rs:56:14 @@ -83,7 +83,7 @@ LL | Some(0..=10) => {} LL | Some(10..20) => {} | ^^^^^^ ... with this range | - = note: this is likely to be a mistake + = note: you likely meant to write mutually exclusive ranges error: aborting due to 8 previous errors From f4085f0d3a4f1ff77153eabf8fa9cf6d0dafae1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Dec 2020 20:25:27 +0100 Subject: [PATCH 427/719] also const-check FakeRead --- .../src/transform/check_consts/validation.rs | 11 +++++----- .../const_refers_to_static_cross_crate.stderr | 5 +++++ src/test/ui/error-codes/E0396.rs | 11 ++++++++++ src/test/ui/error-codes/E0396.stderr | 20 ++++++++++++++++++- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index d00038f345c9..90688ebbd0ac 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -722,17 +722,16 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { trace!("visit_statement: statement={:?} location={:?}", statement, location); - match statement.kind { - StatementKind::Assign(..) | StatementKind::SetDiscriminant { .. } => { - self.super_statement(statement, location); - } + self.super_statement(statement, location); + match statement.kind { StatementKind::LlvmInlineAsm { .. } => { - self.super_statement(statement, location); self.check_op(ops::InlineAsm); } - StatementKind::FakeRead(..) + StatementKind::Assign(..) + | StatementKind::SetDiscriminant { .. } + | StatementKind::FakeRead(..) | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Retag { .. } diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr index 52662ef9eaf5..b65e50eb9f41 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr @@ -146,6 +146,11 @@ help: skipping check that does not even have a feature gate | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:32:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check for `const_panic` feature --> $DIR/const_refers_to_static_cross_crate.rs:32:77 | diff --git a/src/test/ui/error-codes/E0396.rs b/src/test/ui/error-codes/E0396.rs index b32853e483d6..58ed3c2c7227 100644 --- a/src/test/ui/error-codes/E0396.rs +++ b/src/test/ui/error-codes/E0396.rs @@ -5,5 +5,16 @@ const REG_ADDR: *const u8 = 0x5f3759df as *const u8; const VALUE: u8 = unsafe { *REG_ADDR }; //~^ ERROR dereferencing raw pointers in constants is unstable +const unsafe fn unreachable() -> ! { + use std::convert::Infallible; + + const INFALLIBLE: *const Infallible = [].as_ptr(); + match *INFALLIBLE {} + //~^ ERROR dereferencing raw pointers in constant functions is unstable + + const BAD: () = unsafe { match *INFALLIBLE {} }; + //~^ ERROR dereferencing raw pointers in constants is unstable +} + fn main() { } diff --git a/src/test/ui/error-codes/E0396.stderr b/src/test/ui/error-codes/E0396.stderr index 7d2544f939f7..20dad1b983c1 100644 --- a/src/test/ui/error-codes/E0396.stderr +++ b/src/test/ui/error-codes/E0396.stderr @@ -7,6 +7,24 @@ LL | const VALUE: u8 = unsafe { *REG_ADDR }; = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: dereferencing raw pointers in constant functions is unstable + --> $DIR/E0396.rs:12:11 + | +LL | match *INFALLIBLE {} + | ^^^^^^^^^^^ + | + = note: see issue #51911 for more information + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error[E0658]: dereferencing raw pointers in constants is unstable + --> $DIR/E0396.rs:15:36 + | +LL | const BAD: () = unsafe { match *INFALLIBLE {} }; + | ^^^^^^^^^^^ + | + = note: see issue #51911 for more information + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. From 52b717f8264baf1044a001035d20c77f545b6abf Mon Sep 17 00:00:00 2001 From: pierwill Date: Sat, 19 Dec 2020 14:08:41 -0800 Subject: [PATCH 428/719] Edit rustc_middle::lint::LintSource docs Edit punctuation in doc comment for rustc_middle::lint::LintSource::CommandLine. --- compiler/rustc_middle/src/lint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index a61d37cc90eb..0724d5034078 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -22,8 +22,8 @@ pub enum LintSource { Node(Symbol, Span, Option /* RFC 2383 reason */), /// Lint level was set by a command-line flag. - /// The provided `Level` is the level specified on the command line - - /// the actual level may be lower due to `--cap-lints` + /// The provided `Level` is the level specified on the command line. + /// (The actual level may be lower due to `--cap-lints`.) CommandLine(Symbol, Level), } From 4fffa742d70c81f7414d02f55808d22eeeb77bb2 Mon Sep 17 00:00:00 2001 From: pierwill Date: Sat, 19 Dec 2020 14:25:24 -0800 Subject: [PATCH 429/719] docs: Edit rustc_middle::ty::query::on_disk_cache Expand abbreviations for "incremental compliation". Also added the word "to" to the description of CacheEncoder. --- compiler/rustc_middle/src/ty/query/on_disk_cache.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index e006dfeb6633..98fc32f34c88 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -648,7 +648,7 @@ impl<'sess> OnDiskCache<'sess> { //- DECODING ------------------------------------------------------------------- -/// A decoder that can read from the incr. comp. cache. It is similar to the one +/// A decoder that can read from the incremental compilation cache. It is similar to the one /// we use for crate metadata decoding in that it can rebase spans and eventually /// will also handle things that contain `Ty` instances. crate struct CacheDecoder<'a, 'tcx> { @@ -936,7 +936,7 @@ impl<'a, 'tcx> Decodable> for &'tcx [Span] { //- ENCODING ------------------------------------------------------------------- -/// An encoder that can write the incr. comp. cache. +/// An encoder that can write to the incremental compilation cache. struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> { tcx: TyCtxt<'tcx>, encoder: &'a mut E, From 74bd2eae3335e74663d25a6a2142bc904007a499 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 20 Dec 2020 00:21:42 +0100 Subject: [PATCH 430/719] impl Default for LangString, replacing all_false by default --- src/librustdoc/html/markdown.rs | 20 ++++++----- src/librustdoc/html/markdown/tests.rs | 48 ++++++++++----------------- 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 22096203d4ce..82982a1b43ec 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -204,7 +204,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { CodeBlockKind::Fenced(ref lang) => { LangString::parse_without_check(&lang, self.check_error_codes, false) } - CodeBlockKind::Indented => LangString::all_false(), + CodeBlockKind::Indented => Default::default(), }; if !parse_result.rust { return Some(Event::Start(Tag::CodeBlock(kind))); @@ -665,7 +665,7 @@ crate fn find_testable_code( let block_info = match kind { CodeBlockKind::Fenced(ref lang) => { if lang.is_empty() { - LangString::all_false() + Default::default() } else { LangString::parse( lang, @@ -675,7 +675,7 @@ crate fn find_testable_code( ) } } - CodeBlockKind::Indented => LangString::all_false(), + CodeBlockKind::Indented => Default::default(), }; if !block_info.rust { continue; @@ -778,14 +778,14 @@ crate enum Ignore { Some(Vec), } -impl LangString { - fn all_false() -> LangString { - LangString { +impl Default for LangString { + fn default() -> Self { + Self { original: String::new(), should_panic: false, no_run: false, ignore: Ignore::None, - rust: true, // NB This used to be `notrust = false` + rust: true, test_harness: false, compile_fail: false, error_codes: Vec::new(), @@ -793,7 +793,9 @@ impl LangString { edition: None, } } +} +impl LangString { fn parse_without_check( string: &str, allow_error_code_check: ErrorCodes, @@ -811,7 +813,7 @@ impl LangString { let allow_error_code_check = allow_error_code_check.as_bool(); let mut seen_rust_tags = false; let mut seen_other_tags = false; - let mut data = LangString::all_false(); + let mut data = LangString::default(); let mut ignores = vec![]; data.original = string.to_owned(); @@ -1233,7 +1235,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_, '_>) -> Vec { let syntax = syntax.as_ref(); let lang_string = if syntax.is_empty() { - LangString::all_false() + Default::default() } else { LangString::parse(&*syntax, ErrorCodes::Yes, false, Some(extra_info)) }; diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 75ff3c5af2fd..9da3072ec282 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -56,71 +56,59 @@ fn test_lang_string_parse() { assert_eq!(LangString::parse(s, ErrorCodes::Yes, true, None), lg) } - t(LangString::all_false()); - t(LangString { original: "rust".into(), ..LangString::all_false() }); - t(LangString { original: "sh".into(), rust: false, ..LangString::all_false() }); - t(LangString { original: "ignore".into(), ignore: Ignore::All, ..LangString::all_false() }); + t(Default::default()); + t(LangString { original: "rust".into(), ..Default::default() }); + t(LangString { original: "sh".into(), rust: false, ..Default::default() }); + t(LangString { original: "ignore".into(), ignore: Ignore::All, ..Default::default() }); t(LangString { original: "ignore-foo".into(), ignore: Ignore::Some(vec!["foo".to_string()]), - ..LangString::all_false() - }); - t(LangString { - original: "should_panic".into(), - should_panic: true, - ..LangString::all_false() - }); - t(LangString { original: "no_run".into(), no_run: true, ..LangString::all_false() }); - t(LangString { - original: "test_harness".into(), - test_harness: true, - ..LangString::all_false() + ..Default::default() }); + t(LangString { original: "should_panic".into(), should_panic: true, ..Default::default() }); + t(LangString { original: "no_run".into(), no_run: true, ..Default::default() }); + t(LangString { original: "test_harness".into(), test_harness: true, ..Default::default() }); t(LangString { original: "compile_fail".into(), no_run: true, compile_fail: true, - ..LangString::all_false() - }); - t(LangString { original: "allow_fail".into(), allow_fail: true, ..LangString::all_false() }); - t(LangString { - original: "{.no_run .example}".into(), - no_run: true, - ..LangString::all_false() + ..Default::default() }); + t(LangString { original: "allow_fail".into(), allow_fail: true, ..Default::default() }); + t(LangString { original: "{.no_run .example}".into(), no_run: true, ..Default::default() }); t(LangString { original: "{.sh .should_panic}".into(), should_panic: true, rust: false, - ..LangString::all_false() + ..Default::default() }); - t(LangString { original: "{.example .rust}".into(), ..LangString::all_false() }); + t(LangString { original: "{.example .rust}".into(), ..Default::default() }); t(LangString { original: "{.test_harness .rust}".into(), test_harness: true, - ..LangString::all_false() + ..Default::default() }); t(LangString { original: "text, no_run".into(), no_run: true, rust: false, - ..LangString::all_false() + ..Default::default() }); t(LangString { original: "text,no_run".into(), no_run: true, rust: false, - ..LangString::all_false() + ..Default::default() }); t(LangString { original: "edition2015".into(), edition: Some(Edition::Edition2015), - ..LangString::all_false() + ..Default::default() }); t(LangString { original: "edition2018".into(), edition: Some(Edition::Edition2018), - ..LangString::all_false() + ..Default::default() }); } From 01d7f87d8ee16915d8f663f44a5587ec45f54f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 20 Dec 2020 00:50:06 +0100 Subject: [PATCH 431/719] Reserve necessary space for params in generics_of --- compiler/rustc_typeck/src/collect.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 543e39af6694..8f4f4fdcbe78 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1369,7 +1369,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { generics.parent_count + generics.params.len() }); - let mut params: Vec<_> = opt_self.into_iter().collect(); + let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize); + + if let Some(opt_self) = opt_self { + params.push(opt_self); + } let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics); params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef { From 4ad53dc9f5b43e0fa27622e3e40faeac15f00f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 20 Dec 2020 00:00:00 +0000 Subject: [PATCH 432/719] Use pointer type in AtomicPtr::swap implementation --- compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 15 +++++++++++++-- library/core/src/sync/atomic.rs | 10 +++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 34022643101b..80e3ed75b858 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -524,8 +524,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let ty = substs.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() { - bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order) + if int_type_width_signed(ty, bx.tcx()).is_some() + || (ty.is_unsafe_ptr() && op == "xchg") + { + let mut ptr = args[0].immediate(); + let mut val = args[1].immediate(); + if ty.is_unsafe_ptr() { + // Some platforms do not support atomic operations on pointers, + // so we cast to integer first. + let ptr_llty = bx.type_ptr_to(bx.type_isize()); + ptr = bx.pointercast(ptr, ptr_llty); + val = bx.ptrtoint(val, bx.type_isize()); + } + bx.atomic_rmw(atom_op, ptr, val, order) } else { return invalid_monomorphization(ty); } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index be6c86b51761..a96da9aa6dc7 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1040,8 +1040,16 @@ impl AtomicPtr { #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "ptr")] pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { + #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T } + unsafe { + atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T + } + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_swap(self.p.get(), ptr, order) + } } /// Stores a value into the pointer if the current value is the same as the `current` value. From b76c9be7f5fa10b95fe4f872400b4388b67a4733 Mon Sep 17 00:00:00 2001 From: William Bain Date: Sat, 19 Dec 2020 16:52:19 -0500 Subject: [PATCH 433/719] Handle desugaring in impl trait bound suggestion --- .../src/traits/error_reporting/suggestions.rs | 18 ++++------ .../impl-trait-with-missing-bounds.rs | 8 +++++ .../impl-trait-with-missing-bounds.stderr | 17 +++++++++- ...l-trait-with-missing-bounds-on-async-fn.rs | 32 ++++++++++++++++++ ...ait-with-missing-bounds-on-async-fn.stderr | 33 +++++++++++++++++++ 5 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs create mode 100644 src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index b4b71a48ce9d..79fea83a6674 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -254,27 +254,21 @@ fn suggest_restriction( let pred = trait_ref.without_const().to_predicate(tcx).to_string(); let pred = pred.replace(&impl_trait_str, &type_param_name); let mut sugg = vec![ + // Find the last of the generic parameters contained within the span of + // the generics match generics .params .iter() - .filter(|p| match p.kind { - hir::GenericParamKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => false, - _ => true, - }) - .last() + .map(|p| p.bounds_span().unwrap_or(p.span)) + .filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none()) + .max_by_key(|span| span.hi()) { // `fn foo(t: impl Trait)` // ^ suggest `` here None => (generics.span, format!("<{}>", type_param)), // `fn foo(t: impl Trait)` // ^^^ suggest `` here - Some(param) => ( - param.bounds_span().unwrap_or(param.span).shrink_to_hi(), - format!(", {}", type_param), - ), + Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)), }, // `fn foo(t: impl Trait)` // ^ suggest `where ::A: Bound` diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs index d401328077aa..949b23600715 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs @@ -39,6 +39,14 @@ fn bak(constraints: impl Iterator + std::fmt::Debug) { } } +#[rustfmt::skip] +fn baw<>(constraints: impl Iterator) { + for constraint in constraints { + qux(constraint); +//~^ ERROR `::Item` doesn't implement `Debug` + } +} + fn qux(_: impl std::fmt::Debug) {} fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr index 099eb1c9d005..0de3b9aec19e 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -73,6 +73,21 @@ help: introduce a type parameter with a trait bound instead of using `impl Trait LL | fn bak(constraints: I) where ::Item: Debug { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0277]: `::Item` doesn't implement `Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:45:13 + | +LL | qux(constraint); + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` +... +LL | fn qux(_: impl std::fmt::Debug) {} + | --------------- required by this bound in `qux` + | + = help: the trait `Debug` is not implemented for `::Item` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn baw(constraints: I) where ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs new file mode 100644 index 000000000000..3cd6d336e134 --- /dev/null +++ b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs @@ -0,0 +1,32 @@ +// Regression test: if we suggest replacing an `impl Trait` argument to an async +// fn with a named type parameter in order to add bounds, the suggested function +// signature should be well-formed. +// +// edition:2018 + +trait Foo { + type Bar; + fn bar(&self) -> Self::Bar; +} + +async fn run(_: &(), foo: impl Foo) -> std::io::Result<()> { + let bar = foo.bar(); + assert_is_send(&bar); +//~^ ERROR: `::Bar` cannot be sent between threads safely + + Ok(()) +} + +// Test our handling of cases where there is a generic parameter list in the +// source, but only synthetic generic parameters +async fn run2< >(_: &(), foo: impl Foo) -> std::io::Result<()> { + let bar = foo.bar(); + assert_is_send(&bar); +//~^ ERROR: `::Bar` cannot be sent between threads safely + + Ok(()) +} + +fn assert_is_send(_: &T) {} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr new file mode 100644 index 000000000000..9404c3bb5831 --- /dev/null +++ b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr @@ -0,0 +1,33 @@ +error[E0277]: `::Bar` cannot be sent between threads safely + --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:14:20 + | +LL | assert_is_send(&bar); + | ^^^^ `::Bar` cannot be sent between threads safely +... +LL | fn assert_is_send(_: &T) {} + | ---- required by this bound in `assert_is_send` + | + = help: the trait `Send` is not implemented for `::Bar` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | async fn run(_: &(), foo: F) -> std::io::Result<()> where ::Bar: Send { + | ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `::Bar` cannot be sent between threads safely + --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:24:20 + | +LL | assert_is_send(&bar); + | ^^^^ `::Bar` cannot be sent between threads safely +... +LL | fn assert_is_send(_: &T) {} + | ---- required by this bound in `assert_is_send` + | + = help: the trait `Send` is not implemented for `::Bar` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | async fn run2(_: &(), foo: F) -> std::io::Result<()> where ::Bar: Send { + | ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From e628fcfcb591ce78673d2736ebe936873ea5111d Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Sun, 20 Dec 2020 02:49:18 +0000 Subject: [PATCH 434/719] Skip `dsymutil` by default for compiler bootstrap `dsymutil` adds time to builds on Apple platforms for no clear benefit, and also makes it more difficult for debuggers to find debug info. The compiler currently defaults to running `dsymutil` to preserve its historical default, but when compiling the compiler itself, we skip it by default since we know it's safe to do so in that case. --- config.toml.example | 8 ++++++++ src/bootstrap/builder.rs | 13 +++++++++++++ src/bootstrap/config.rs | 3 +++ 3 files changed, 24 insertions(+) diff --git a/config.toml.example b/config.toml.example index 5b045d4e32d8..b1fb8904ca98 100644 --- a/config.toml.example +++ b/config.toml.example @@ -426,6 +426,14 @@ changelog-seen = 2 # FIXME(#61117): Some tests fail when this option is enabled. #debuginfo-level-tests = 0 +# Whether to run `dsymutil` on Apple platforms to gather debug info into .dSYM +# bundles. `dsymutil` adds time to builds for no clear benefit, and also makes +# it more difficult for debuggers to find debug info. The compiler currently +# defaults to running `dsymutil` to preserve its historical default, but when +# compiling the compiler itself, we skip it by default since we know it's safe +# to do so in that case. +#run-dsymutil = false + # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) #backtrace = true diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 9af79e20630d..ab0c4a5c31b0 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1126,6 +1126,19 @@ impl<'a> Builder<'a> { }, ); + // `dsymutil` adds time to builds on Apple platforms for no clear benefit, and also makes + // it more difficult for debuggers to find debug info. The compiler currently defaults to + // running `dsymutil` to preserve its historical default, but when compiling the compiler + // itself, we skip it by default since we know it's safe to do so in that case. + // See https://github.com/rust-lang/rust/issues/79361 for more info on this flag. + if target.contains("apple") { + if self.config.rust_run_dsymutil { + rustflags.arg("-Zrun-dsymutil=yes"); + } else { + rustflags.arg("-Zrun-dsymutil=no"); + } + } + if self.config.cmd.bless() { // Bless `expect!` tests. cargo.env("UPDATE_EXPECT", "1"); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index fb2c6d1f92a8..ece8a7494b50 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -123,6 +123,7 @@ pub struct Config { pub rust_debuginfo_level_std: u32, pub rust_debuginfo_level_tools: u32, pub rust_debuginfo_level_tests: u32, + pub rust_run_dsymutil: bool, pub rust_rpath: bool, pub rustc_parallel: bool, pub rustc_default_linker: Option, @@ -466,6 +467,7 @@ struct Rust { debuginfo_level_std: Option, debuginfo_level_tools: Option, debuginfo_level_tests: Option, + run_dsymutil: Option, backtrace: Option, incremental: Option, parallel_compiler: Option, @@ -830,6 +832,7 @@ impl Config { debuginfo_level_std = rust.debuginfo_level_std; debuginfo_level_tools = rust.debuginfo_level_tools; debuginfo_level_tests = rust.debuginfo_level_tests; + config.rust_run_dsymutil = rust.run_dsymutil.unwrap_or(false); optimize = rust.optimize; ignore_git = rust.ignore_git; set(&mut config.rust_new_symbol_mangling, rust.new_symbol_mangling); From c127530be76bd8aebc7b61f3b4a54f1be577f74c Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 19 Dec 2020 20:47:57 -0800 Subject: [PATCH 435/719] Fix labels for 'Library Tracking Issue' template Each label needs to be separated by a comma (see the ICE issue template for an example of correct usage). --- .github/ISSUE_TEMPLATE/library_tracking_issue.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/library_tracking_issue.md b/.github/ISSUE_TEMPLATE/library_tracking_issue.md index b8544e6a4e0f..3e42594c8280 100644 --- a/.github/ISSUE_TEMPLATE/library_tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/library_tracking_issue.md @@ -2,7 +2,7 @@ name: Library Tracking Issue about: A tracking issue for an unstable library feature. title: Tracking Issue for XXX -labels: C-tracking-issue T-libs +labels: C-tracking-issue, T-libs --- $DIR/issue-80186-mut-binding-help-suggestion.rs:5:9 + | +LL | let mut &x = &0; + | ^^^^^^ help: add `mut` to each binding: `&(mut x)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: aborting due to previous error + From 4eb28c358c189c9fa35cc4ed22c2c0d230fbe9b2 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Sun, 20 Dec 2020 21:45:23 +0800 Subject: [PATCH 444/719] Update compiler/rustc_typeck/src/check/op.rs Co-authored-by: lcnr --- compiler/rustc_typeck/src/check/op.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 6305bafcd94d..9ab056c0d74b 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -503,7 +503,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !self.tcx.has_typeck_results(def_id) { return false; } - // We're emitting a suggestion, so we can just ignore regions // FIXME: Instead of exiting early when encountering bound vars in // the function signature, consider keeping the binder here and // propagating it downwards. From 54a3ed3114c5fcacfa9ec15e89935c105b4c00a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Nov 2020 17:42:03 +0100 Subject: [PATCH 445/719] use exhaustive match for checking Rvalue::Repeat --- .../src/borrow_check/type_check/mod.rs | 76 ++++++++++--------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 543b7e7ebaa7..42cd050abc5d 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1988,44 +1988,48 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // If the length is larger than 1, the repeat expression will need to copy the // element, so we require the `Copy` trait. if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { - if let Operand::Move(_) = operand { - // While this is located in `nll::typeck` this error is not an NLL error, it's - // a required check to make sure that repeated elements implement `Copy`. - let span = body.source_info(location).span; - let ty = operand.ty(body, tcx); - if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { - let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env); - // To determine if `const_in_array_repeat_expressions` feature gate should - // be mentioned, need to check if the rvalue is promotable. - let should_suggest = - should_suggest_const_in_array_repeat_expressions_attribute( - &ccx, operand, - ); - debug!("check_rvalue: should_suggest={:?}", should_suggest); + match operand { + Operand::Copy(..) | Operand::Constant(..) => { + // These are always okay: direct use of a const, or a value that can evidently be copied. + } + Operand::Move(_) => { + // Make sure that repeated elements implement `Copy`. + let span = body.source_info(location).span; + let ty = operand.ty(body, tcx); + if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { + let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env); + // To determine if `const_in_array_repeat_expressions` feature gate should + // be mentioned, need to check if the rvalue is promotable. + let should_suggest = + should_suggest_const_in_array_repeat_expressions_attribute( + &ccx, operand, + ); + debug!("check_rvalue: should_suggest={:?}", should_suggest); - let def_id = body.source.def_id().expect_local(); - self.infcx.report_selection_error( - &traits::Obligation::new( - ObligationCause::new( - span, - self.tcx().hir().local_def_id_to_hir_id(def_id), - traits::ObligationCauseCode::RepeatVec(should_suggest), - ), - self.param_env, - ty::Binder::bind(ty::TraitRef::new( - self.tcx().require_lang_item( - LangItem::Copy, - Some(self.last_span), + let def_id = body.source.def_id().expect_local(); + self.infcx.report_selection_error( + &traits::Obligation::new( + ObligationCause::new( + span, + self.tcx().hir().local_def_id_to_hir_id(def_id), + traits::ObligationCauseCode::RepeatVec(should_suggest), ), - tcx.mk_substs_trait(ty, &[]), - )) - .without_const() - .to_predicate(self.tcx()), - ), - &traits::SelectionError::Unimplemented, - false, - false, - ); + self.param_env, + ty::Binder::bind(ty::TraitRef::new( + self.tcx().require_lang_item( + LangItem::Copy, + Some(self.last_span), + ), + tcx.mk_substs_trait(ty, &[]), + )) + .without_const() + .to_predicate(self.tcx()), + ), + &traits::SelectionError::Unimplemented, + false, + false, + ); + } } } } From f8d4883dbebf71348abe1134c6f26d48a36256b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Nov 2020 18:05:29 +0100 Subject: [PATCH 446/719] add test that repeating non-Copy constants works --- .../const-repeat.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs new file mode 100644 index 000000000000..11611a949187 --- /dev/null +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs @@ -0,0 +1,13 @@ +// check-pass + +// Repeating a *constant* of non-Copy type (not just a constant expression) is already stable. + +const EMPTY: Vec = Vec::new(); + +pub fn bar() -> [Vec; 2] { + [EMPTY; 2] +} + +fn main() { + let x = bar(); +} From 7f3e18cc2b24214e10df5434972f4f7cd461fa98 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Nov 2020 17:32:48 +0100 Subject: [PATCH 447/719] make sure [CONST; N] drops N times --- .../const-repeat.rs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs index 11611a949187..65d02317d34c 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs @@ -1,4 +1,4 @@ -// check-pass +// run-pass // Repeating a *constant* of non-Copy type (not just a constant expression) is already stable. @@ -8,6 +8,20 @@ pub fn bar() -> [Vec; 2] { [EMPTY; 2] } -fn main() { - let x = bar(); +struct Bomb; + +impl Drop for Bomb { + fn drop(&mut self) { + panic!("BOOM!"); + } +} + +const BOOM: Bomb = Bomb; + +fn main() { + let _x = bar(); + + // Make sure the destructor does not get called for empty arrays. `[CONST; N]` should + // instantiate (and then later drop) the const exactly `N` times. + let _x = [BOOM; 0]; } From 06ca7b700cae83324b4bad8be3286da4f964bb58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Dec 2020 15:49:08 +0100 Subject: [PATCH 448/719] validate promoteds --- .../rustc_mir/src/const_eval/eval_queries.rs | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index f13b4b7b9192..3a3117d5ccf7 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -383,25 +383,15 @@ pub fn eval_to_allocation_raw_provider<'tcx>( Ok(mplace) => { // Since evaluation had no errors, valiate the resulting constant: let validation = try { - // FIXME do not validate promoteds until a decision on - // https://github.com/rust-lang/rust/issues/67465 and - // https://github.com/rust-lang/rust/issues/67534 is made. - // Promoteds can contain unexpected `UnsafeCell` and reference `static`s, but their - // otherwise restricted form ensures that this is still sound. We just lose the - // extra safety net of some of the dynamic checks. They can also contain invalid - // values, but since we do not usually check intermediate results of a computation - // for validity, it might be surprising to do that here. - if cid.promoted.is_none() { - let mut ref_tracking = RefTracking::new(mplace); - let mut inner = false; - while let Some((mplace, path)) = ref_tracking.todo.pop() { - let mode = match tcx.static_mutability(cid.instance.def_id()) { - Some(_) => CtfeValidationMode::Regular, // a `static` - None => CtfeValidationMode::Const { inner }, - }; - ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; - inner = true; - } + let mut ref_tracking = RefTracking::new(mplace); + let mut inner = false; + while let Some((mplace, path)) = ref_tracking.todo.pop() { + let mode = match tcx.static_mutability(cid.instance.def_id()) { + Some(_) if cid.promoted.is_none() => CtfeValidationMode::Regular, // a `static` + _ => CtfeValidationMode::Const { inner }, + }; + ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; + inner = true; } }; if let Err(error) = validation { From 53d6e0caaa5769e543e85ad629b73e0ba2c20486 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 20 Dec 2020 16:48:26 +0100 Subject: [PATCH 449/719] Bump nightly to 2020-12-20 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index ac51154f8a9d..d2e84132f4ed 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2020-12-14" +channel = "nightly-2020-12-20" components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] From 00bb2935fcfb54dcd2b770ff451bd0a4c97738a0 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Sun, 20 Dec 2020 23:39:25 +0800 Subject: [PATCH 450/719] Move test from compile-fail to ui/binop --- .../binop}/issue-77910-1.rs | 0 src/test/ui/binop/issue-77910-1.stderr | 26 +++++++++++++++++++ .../binop}/issue-77910-2.rs | 0 src/test/ui/binop/issue-77910-2.stderr | 11 ++++++++ 4 files changed, 37 insertions(+) rename src/test/{compile-fail => ui/binop}/issue-77910-1.rs (100%) create mode 100644 src/test/ui/binop/issue-77910-1.stderr rename src/test/{compile-fail => ui/binop}/issue-77910-2.rs (100%) create mode 100644 src/test/ui/binop/issue-77910-2.stderr diff --git a/src/test/compile-fail/issue-77910-1.rs b/src/test/ui/binop/issue-77910-1.rs similarity index 100% rename from src/test/compile-fail/issue-77910-1.rs rename to src/test/ui/binop/issue-77910-1.rs diff --git a/src/test/ui/binop/issue-77910-1.stderr b/src/test/ui/binop/issue-77910-1.stderr new file mode 100644 index 000000000000..e48d3e19996f --- /dev/null +++ b/src/test/ui/binop/issue-77910-1.stderr @@ -0,0 +1,26 @@ +error[E0369]: binary operation `==` cannot be applied to type `for<'r> fn(&'r i32) -> &'r i32 {foo}` + --> $DIR/issue-77910-1.rs:8:5 + | +LL | assert_eq!(foo, y); + | ^^^^^^^^^^^^^^^^^^^ + | | + | for<'r> fn(&'r i32) -> &'r i32 {foo} + | _ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `for<'r> fn(&'r i32) -> &'r i32 {foo}` doesn't implement `Debug` + --> $DIR/issue-77910-1.rs:8:5 + | +LL | assert_eq!(foo, y); + | ^^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}` + = note: required because of the requirements on the impl of `Debug` for `&for<'r> fn(&'r i32) -> &'r i32 {foo}` + = note: required by `std::fmt::Debug::fmt` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/compile-fail/issue-77910-2.rs b/src/test/ui/binop/issue-77910-2.rs similarity index 100% rename from src/test/compile-fail/issue-77910-2.rs rename to src/test/ui/binop/issue-77910-2.rs diff --git a/src/test/ui/binop/issue-77910-2.stderr b/src/test/ui/binop/issue-77910-2.stderr new file mode 100644 index 000000000000..5477a5762a8f --- /dev/null +++ b/src/test/ui/binop/issue-77910-2.stderr @@ -0,0 +1,11 @@ +error[E0369]: binary operation `==` cannot be applied to type `for<'r> fn(&'r i32) -> &'r i32 {foo}` + --> $DIR/issue-77910-2.rs:7:12 + | +LL | if foo == y {} + | --- ^^ - _ + | | + | for<'r> fn(&'r i32) -> &'r i32 {foo} + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0369`. From b228be20c224ab6dfa9498935515bf925d4503b3 Mon Sep 17 00:00:00 2001 From: pierwill Date: Fri, 18 Dec 2020 14:17:23 -0800 Subject: [PATCH 451/719] Edit rustc_middle::ty::TyKind docs - Add a definition for this enum. - Fix typo and missing punctuation. - Spell out "algebraic data type". --- compiler/rustc_middle/src/ty/sty.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 81ee05d4b23c..dc72a713a7d8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -88,6 +88,8 @@ impl BoundRegionKind { } } +/// Defines the kinds of types. +/// /// N.B., if you change this, you'll probably want to change the corresponding /// AST structure in `librustc_ast/ast.rs` as well. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)] @@ -110,7 +112,7 @@ pub enum TyKind<'tcx> { /// A primitive floating-point type. For example, `f64`. Float(ast::FloatTy), - /// Structures, enumerations and unions. + /// Algebraic data types (ADT). For example: structures, enumerations and unions. /// /// InternalSubsts here, possibly against intuition, *may* contain `Param`s. /// That is, even after substitution it is possible that there are type @@ -170,11 +172,11 @@ pub enum TyKind<'tcx> { /// `|a| yield a`. Generator(DefId, SubstsRef<'tcx>, hir::Movability), - /// A type representin the types stored inside a generator. + /// A type representing the types stored inside a generator. /// This should only appear in GeneratorInteriors. GeneratorWitness(Binder<&'tcx List>>), - /// The never type `!` + /// The never type `!`. Never, /// A tuple type. For example, `(i32, bool)`. From fbc9d50d752ab298aea2844d236095b198e96fe6 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sun, 20 Dec 2020 17:16:02 +0000 Subject: [PATCH 452/719] make sure installer only creates directories in DESTDIR Fixes #80238 Signed-off-by: Yuxuan Shui --- src/bootstrap/install.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 074f5cd73f32..8f2b128b3688 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -73,12 +73,7 @@ fn install_sh( let docdir_default = datadir_default.join("doc/rust"); let libdir_default = PathBuf::from("lib"); let mandir_default = datadir_default.join("man"); - let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| { - fs::create_dir_all(p) - .unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err)); - fs::canonicalize(p) - .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err)) - }); + let prefix = builder.config.prefix.as_ref().unwrap_or(&prefix_default); let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default); let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default); let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default); @@ -103,6 +98,13 @@ fn install_sh( let libdir = add_destdir(&libdir, &destdir); let mandir = add_destdir(&mandir, &destdir); + let prefix = { + fs::create_dir_all(&prefix) + .unwrap_or_else(|err| panic!("could not create {}: {}", prefix.display(), err)); + fs::canonicalize(&prefix) + .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", prefix.display(), err)) + }; + let empty_dir = builder.out.join("tmp/empty_dir"); t!(fs::create_dir_all(&empty_dir)); From 32baf233c53f3aaddec43457b87753bdb5e8c7b2 Mon Sep 17 00:00:00 2001 From: pierwill <19642016+pierwill@users.noreply.github.com> Date: Sun, 20 Dec 2020 09:53:26 -0800 Subject: [PATCH 453/719] Fix typo Fix typo in rustc_middle::ty::inhabitedness::DefIdForest docs. --- compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs index ee6b06a1cc80..d9aebfc8293b 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs @@ -17,7 +17,7 @@ pub struct DefIdForest { /// If A and B are DefIds in the `DefIdForest`, and A is a descendant /// of B, then only B will be in `root_ids`. /// We use a `SmallVec` here because (for its use for caching inhabitedness) - /// its rare that this will contain even two IDs. + /// it's rare that this will contain even two IDs. root_ids: SmallVec<[DefId; 1]>, } From 77fce67733d2a1403f17b382dfbd3802003172a6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 20 Dec 2020 18:11:11 +0000 Subject: [PATCH 454/719] Make recursion limit fatal in project This avoid the hang/oom from #79714 --- compiler/rustc_trait_selection/src/traits/project.rs | 9 ++++++++- src/test/ui/issues/issue-23122-2.stderr | 3 +-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a11499e43209..7fa070caa275 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -734,7 +734,14 @@ fn project_type<'cx, 'tcx>( if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); - return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); + match selcx.query_mode() { + super::TraitQueryMode::Standard => { + selcx.infcx().report_overflow_error(&obligation, true); + } + super::TraitQueryMode::Canonical => { + return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); + } + } } let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index ce3bffe602ca..ff7e884ea6f8 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,11 +1,10 @@ -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next` --> $DIR/issue-23122-2.rs:9:5 | LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) - = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error: aborting due to previous error From 97cae9c555016cfa02a3aa1e41a41157525f8cf4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Dec 2020 19:34:29 +0100 Subject: [PATCH 455/719] promoteds in statics may refer to statics --- .../rustc_mir/src/const_eval/eval_queries.rs | 8 ++++++-- compiler/rustc_mir/src/interpret/validity.rs | 20 +++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 3a3117d5ccf7..df163f656284 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -387,8 +387,12 @@ pub fn eval_to_allocation_raw_provider<'tcx>( let mut inner = false; while let Some((mplace, path)) = ref_tracking.todo.pop() { let mode = match tcx.static_mutability(cid.instance.def_id()) { - Some(_) if cid.promoted.is_none() => CtfeValidationMode::Regular, // a `static` - _ => CtfeValidationMode::Const { inner }, + Some(_) if cid.promoted.is_some() => { + // Promoteds in statics are allowed to point to statics. + CtfeValidationMode::Const { inner, allow_static_ptrs: true } + } + Some(_) => CtfeValidationMode::Regular, // a `static` + None => CtfeValidationMode::Const { inner, allow_static_ptrs: false }, }; ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; inner = true; diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 2d235d65c4d3..57aec0953b8c 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -117,11 +117,12 @@ pub enum PathElem { pub enum CtfeValidationMode { /// Regular validation, nothing special happening. Regular, - /// Validation of a `const`. `inner` says if this is an inner, indirect allocation (as opposed - /// to the top-level const allocation). - /// Being an inner allocation makes a difference because the top-level allocation of a `const` - /// is copied for each use, but the inner allocations are implicitly shared. - Const { inner: bool }, + /// Validation of a `const`. + /// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const + /// allocation). Being an inner allocation makes a difference because the top-level allocation + /// of a `const` is copied for each use, but the inner allocations are implicitly shared. + /// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics). + Const { inner: bool, allow_static_ptrs: bool }, } /// State for tracking recursive validation of references @@ -437,7 +438,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); assert!(self.ecx.tcx.is_static(did)); - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { + if matches!( + self.ctfe_mode, + Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. }) + ) { // See const_eval::machine::MemoryExtra::can_access_statics for why // this check is so important. // This check is reachable when the const just referenced the static, @@ -742,9 +746,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // Sanity check: `builtin_deref` does not know any pointers that are not primitive. assert!(op.layout.ty.builtin_deref(true).is_none()); - // Special check preventing `UnsafeCell` in constants + // Special check preventing `UnsafeCell` in the inner part of constants if let Some(def) = op.layout.ty.ty_adt_def() { - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true })) + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) && Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() { throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); From f318f0211238abc4053fb6ce5ebfd0e229d3bf27 Mon Sep 17 00:00:00 2001 From: pierwill Date: Fri, 18 Dec 2020 11:15:27 -0800 Subject: [PATCH 456/719] Edit rustc_middle docs Re-word doc comment for rustc_middle::hir::place::Projection. Also adds: - Missing end stop punctuation, and - Documentation links to `rustc_middle::mir::Place`. --- compiler/rustc_middle/src/hir/place.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 143b3867d9fc..1e2e9df88c58 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -17,13 +17,13 @@ use rustc_target::abi::VariantIdx; HashStable )] pub enum PlaceBase { - /// A temporary variable + /// A temporary variable. Rvalue, - /// A named `static` item + /// A named `static` item. StaticItem, - /// A named local variable + /// A named local variable. Local(HirId), - /// An upvar referenced by closure env + /// An upvar referenced by closure env. Upvar(ty::UpvarId), } @@ -40,7 +40,7 @@ pub enum PlaceBase { HashStable )] pub enum ProjectionKind { - /// A dereference of a pointer, reference or `Box` of the given type + /// A dereference of a pointer, reference or `Box` of the given type. Deref, /// `B.F` where `B` is the base expression and `F` is @@ -71,16 +71,16 @@ pub enum ProjectionKind { HashStable )] pub struct Projection<'tcx> { - /// Type after the projection is being applied. + /// Type after the projection is applied. pub ty: Ty<'tcx>, - /// Defines the type of access + /// Defines the kind of access made by the projection. pub kind: ProjectionKind, } /// A `Place` represents how a value is located in memory. /// -/// This is an HIR version of `mir::Place` +/// This is an HIR version of [`rustc_middle::mir::Place`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct Place<'tcx> { /// The type of the `PlaceBase` @@ -93,13 +93,13 @@ pub struct Place<'tcx> { /// A `PlaceWithHirId` represents how a value is located in memory. /// -/// This is an HIR version of `mir::Place` +/// This is an HIR version of [`rustc_middle::mir::Place`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct PlaceWithHirId<'tcx> { /// `HirId` of the expression or pattern producing this value. pub hir_id: HirId, - /// Information about the `Place` + /// Information about the `Place`. pub place: Place<'tcx>, } From 65f4f39dd8d9a1c1f4a817da36c38b30e4369f9e Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 20 Dec 2020 14:28:20 -0500 Subject: [PATCH 457/719] Get rid of `locate()` in markdown handling This function was unfortunate for several reasons: - It used `unsafe` because it wanted to tell whether a string came from the same *allocation* as another, not just whether it was a textual match. - It recalculated spans even though they were already available from pulldown - It sometimes *failed* to calculate the span, which meant it was always possible for the span to be `None`, even though in practice that should never happen. This commit has several cleanups: - Make the span required - Pass through the span from pulldown in the `HeadingLinks` and `Footnotes` iterators - Only add iterator bounds on the `impl Iterator`, not on `new` and the struct itself. --- src/librustdoc/html/markdown.rs | 126 +++++++++--------- .../passes/collect_intra_doc_links.rs | 60 ++++----- 2 files changed, 87 insertions(+), 99 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 22096203d4ce..7600b63bb885 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -447,21 +447,23 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { } /// Make headings links with anchor IDs and build up TOC. -struct HeadingLinks<'a, 'b, 'ids, I: Iterator>> { +struct HeadingLinks<'a, 'b, 'ids, I> { inner: I, toc: Option<&'b mut TocBuilder>, - buf: VecDeque>, + buf: VecDeque<(Event<'a>, Range)>, id_map: &'ids mut IdMap, } -impl<'a, 'b, 'ids, I: Iterator>> HeadingLinks<'a, 'b, 'ids, I> { +impl<'a, 'b, 'ids, I> HeadingLinks<'a, 'b, 'ids, I> { fn new(iter: I, toc: Option<&'b mut TocBuilder>, ids: &'ids mut IdMap) -> Self { HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids } } } -impl<'a, 'b, 'ids, I: Iterator>> Iterator for HeadingLinks<'a, 'b, 'ids, I> { - type Item = Event<'a>; +impl<'a, 'b, 'ids, I: Iterator, Range)>> Iterator + for HeadingLinks<'a, 'b, 'ids, I> +{ + type Item = (Event<'a>, Range); fn next(&mut self) -> Option { if let Some(e) = self.buf.pop_front() { @@ -469,31 +471,28 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator for HeadingLinks<'a, } let event = self.inner.next(); - if let Some(Event::Start(Tag::Heading(level))) = event { + if let Some((Event::Start(Tag::Heading(level)), _)) = event { let mut id = String::new(); for event in &mut self.inner { - match &event { + match event.0 { Event::End(Tag::Heading(..)) => break, Event::Text(text) | Event::Code(text) => { id.extend(text.chars().filter_map(slugify)); } - _ => {} - } - match event { Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {} - event => self.buf.push_back(event), + _ => self.buf.push_back(event), } } let id = self.id_map.derive(id); if let Some(ref mut builder) = self.toc { let mut html_header = String::new(); - html::push_html(&mut html_header, self.buf.iter().cloned()); + html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone())); let sec = builder.push(level as u32, html_header, id.clone()); - self.buf.push_front(Event::Html(format!("{} ", sec).into())); + self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0)); } - self.buf.push_back(Event::Html(format!("", level).into())); + self.buf.push_back((Event::Html(format!("", level).into()), 0..0)); let start_tags = format!( "\ @@ -501,7 +500,7 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator for HeadingLinks<'a, id = id, level = level ); - return Some(Event::Html(start_tags.into())); + return Some((Event::Html(start_tags.into()), 0..0)); } event } @@ -575,15 +574,16 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { /// Moves all footnote definitions to the end and add back links to the /// references. -struct Footnotes<'a, I: Iterator>> { +struct Footnotes<'a, I> { inner: I, footnotes: FxHashMap>, u16)>, } -impl<'a, I: Iterator>> Footnotes<'a, I> { +impl<'a, I> Footnotes<'a, I> { fn new(iter: I) -> Self { Footnotes { inner: iter, footnotes: FxHashMap::default() } } + fn get_entry(&mut self, key: &str) -> &mut (Vec>, u16) { let new_id = self.footnotes.keys().count() + 1; let key = key.to_owned(); @@ -591,23 +591,23 @@ impl<'a, I: Iterator>> Footnotes<'a, I> { } } -impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { - type Item = Event<'a>; +impl<'a, I: Iterator, Range)>> Iterator for Footnotes<'a, I> { + type Item = (Event<'a>, Range); fn next(&mut self) -> Option { loop { match self.inner.next() { - Some(Event::FootnoteReference(ref reference)) => { + Some((Event::FootnoteReference(ref reference), range)) => { let entry = self.get_entry(&reference); let reference = format!( "{0}", (*entry).1 ); - return Some(Event::Html(reference.into())); + return Some((Event::Html(reference.into()), range)); } - Some(Event::Start(Tag::FootnoteDefinition(def))) => { + Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => { let mut content = Vec::new(); - for event in &mut self.inner { + for (event, _) in &mut self.inner { if let Event::End(Tag::FootnoteDefinition(..)) = event { break; } @@ -638,7 +638,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { ret.push_str(""); } ret.push_str("
"); - return Some(Event::Html(ret.into())); + return Some((Event::Html(ret.into()), 0..0)); } else { return None; } @@ -946,13 +946,14 @@ impl Markdown<'_> { }; let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); + let p = p.into_offset_iter(); let mut s = String::with_capacity(md.len() * 3 / 2); let p = HeadingLinks::new(p, None, &mut ids); - let p = LinkReplacer::new(p, links); - let p = CodeBlocks::new(p, codes, edition, playground); let p = Footnotes::new(p); + let p = LinkReplacer::new(p.map(|(ev, _)| ev), links); + let p = CodeBlocks::new(p, codes, edition, playground); html::push_html(&mut s, p); s @@ -963,7 +964,7 @@ impl MarkdownWithToc<'_> { crate fn into_string(self) -> String { let MarkdownWithToc(md, mut ids, codes, edition, playground) = self; - let p = Parser::new_ext(md, opts()); + let p = Parser::new_ext(md, opts()).into_offset_iter(); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -971,8 +972,8 @@ impl MarkdownWithToc<'_> { { let p = HeadingLinks::new(p, Some(&mut toc), &mut ids); - let p = CodeBlocks::new(p, codes, edition, playground); let p = Footnotes::new(p); + let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground); html::push_html(&mut s, p); } @@ -988,19 +989,19 @@ impl MarkdownHtml<'_> { if md.is_empty() { return String::new(); } - let p = Parser::new_ext(md, opts()); + let p = Parser::new_ext(md, opts()).into_offset_iter(); // Treat inline HTML as plain text. - let p = p.map(|event| match event { - Event::Html(text) => Event::Text(text), + let p = p.map(|event| match event.0 { + Event::Html(text) => (Event::Text(text), event.1), _ => event, }); let mut s = String::with_capacity(md.len() * 3 / 2); let p = HeadingLinks::new(p, None, &mut ids); - let p = CodeBlocks::new(p, codes, edition, playground); let p = Footnotes::new(p); + let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground); html::push_html(&mut s, p); s @@ -1153,7 +1154,7 @@ crate fn plain_text_summary(md: &str) -> String { s } -crate fn markdown_links(md: &str) -> Vec<(String, Option>)> { +crate fn markdown_links(md: &str) -> Vec<(String, Range)> { if md.is_empty() { return vec![]; } @@ -1161,42 +1162,35 @@ crate fn markdown_links(md: &str) -> Vec<(String, Option>)> { let mut links = vec![]; let mut shortcut_links = vec![]; - { - let locate = |s: &str| unsafe { - let s_start = s.as_ptr(); - let s_end = s_start.add(s.len()); - let md_start = md.as_ptr(); - let md_end = md_start.add(md.len()); - if md_start <= s_start && s_end <= md_end { - let start = s_start.offset_from(md_start) as usize; - let end = s_end.offset_from(md_start) as usize; - Some(start..end) - } else { - None + let span_for_link = |link: &str, span: Range| { + // Pulldown includes the `[]` as well as the URL. Only highlight the relevant span. + // NOTE: uses `rfind` in case the title and url are the same: `[Ok][Ok]` + match md[span.clone()].rfind(link) { + Some(start) => { + let start = span.start + start; + start..start + link.len() } - }; + // This can happen for things other than intra-doc links, like `#1` expanded to `https://github.com/rust-lang/rust/issues/1`. + None => span, + } + }; + let mut push = |link: BrokenLink<'_>| { + let span = span_for_link(link.reference, link.span); + shortcut_links.push((link.reference.to_owned(), span)); + None + }; + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)); - let mut push = |link: BrokenLink<'_>| { - // FIXME: use `link.span` instead of `locate` - // (doing it now includes the `[]` as well as the text) - shortcut_links.push((link.reference.to_owned(), locate(link.reference))); - None - }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)); + // There's no need to thread an IdMap through to here because + // the IDs generated aren't going to be emitted anywhere. + let mut ids = IdMap::new(); + let iter = Footnotes::new(HeadingLinks::new(p.into_offset_iter(), None, &mut ids)); - // There's no need to thread an IdMap through to here because - // the IDs generated aren't going to be emitted anywhere. - let mut ids = IdMap::new(); - let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids)); - - for ev in iter { - if let Event::Start(Tag::Link(_, dest, _)) = ev { - debug!("found link: {}", dest); - links.push(match dest { - CowStr::Borrowed(s) => (s.to_owned(), locate(s)), - s @ (CowStr::Boxed(..) | CowStr::Inlined(..)) => (s.into_string(), None), - }); - } + for ev in iter { + if let Event::Start(Tag::Link(_, dest, _)) = ev.0 { + debug!("found link: {}", dest); + let span = span_for_link(&dest, ev.1); + links.push((dest.into_string(), span)); } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ea5bf94689bc..a8adfe08b256 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -180,7 +180,7 @@ struct DiagnosticInfo<'a> { item: &'a Item, dox: &'a str, ori_link: &'a str, - link_range: Option>, + link_range: Range, } #[derive(Clone, Debug, Hash)] @@ -920,7 +920,7 @@ impl LinkCollector<'_, '_> { parent_node: Option, krate: CrateNum, ori_link: String, - link_range: Option>, + link_range: Range, ) -> Option { trace!("considering link '{}'", ori_link); @@ -1566,7 +1566,7 @@ fn report_diagnostic( msg: &str, item: &Item, dox: &str, - link_range: &Option>, + link_range: &Range, decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option), ) { let hir_id = match cx.as_local_hir_id(item.def_id) { @@ -1584,31 +1584,26 @@ fn report_diagnostic( cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |lint| { let mut diag = lint.build(msg); - let span = link_range - .as_ref() - .and_then(|range| super::source_span_for_markdown_range(cx, dox, range, attrs)); + let span = super::source_span_for_markdown_range(cx, dox, link_range, attrs); + if let Some(sp) = span { + diag.set_span(sp); + } else { + // blah blah blah\nblah\nblah [blah] blah blah\nblah blah + // ^ ~~~~ + // | link_range + // last_new_line_offset + let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); + let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); - if let Some(link_range) = link_range { - if let Some(sp) = span { - diag.set_span(sp); - } else { - // blah blah blah\nblah\nblah [blah] blah blah\nblah blah - // ^ ~~~~ - // | link_range - // last_new_line_offset - let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); - let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); - - // Print the line containing the `link_range` and manually mark it with '^'s. - diag.note(&format!( - "the link appears in this line:\n\n{line}\n\ - {indicator: , dox: &str, - link_range: Option>, + link_range: Range, kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { report_diagnostic( @@ -1862,7 +1857,7 @@ fn anchor_failure( item: &Item, path_str: &str, dox: &str, - link_range: Option>, + link_range: Range, failure: AnchorFailure, ) { let msg = match failure { @@ -1887,7 +1882,7 @@ fn ambiguity_error( item: &Item, path_str: &str, dox: &str, - link_range: Option>, + link_range: Range, candidates: Vec, ) { let mut msg = format!("`{}` is ", path_str); @@ -1936,13 +1931,12 @@ fn suggest_disambiguator( path_str: &str, dox: &str, sp: Option, - link_range: &Option>, + link_range: &Range, ) { let suggestion = disambiguator.suggestion(); let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr()); if let Some(sp) = sp { - let link_range = link_range.as_ref().expect("must have a link range if we have a span"); let msg = if dox.bytes().nth(link_range.start) == Some(b'`') { format!("`{}`", suggestion.as_help(path_str)) } else { @@ -1961,7 +1955,7 @@ fn privacy_error( item: &Item, path_str: &str, dox: &str, - link_range: Option>, + link_range: Range, ) { let sym; let item_name = match item.name { From 1e15c2fde5dd456d879b90259c414a73d5804550 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 20 Dec 2020 14:33:58 -0500 Subject: [PATCH 458/719] Remove unnecessary scope --- src/librustdoc/html/markdown.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 7600b63bb885..e4a0d80674fb 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1160,6 +1160,8 @@ crate fn markdown_links(md: &str) -> Vec<(String, Range)> { } let mut links = vec![]; + // Used to avoid mutable borrow issues in the `push` closure + // Probably it would be more efficient to use a `RefCell` but it doesn't seem worth the churn. let mut shortcut_links = vec![]; let span_for_link = |link: &str, span: Range| { From 93d5a8025dd53469c0ea80b645a3087a1d87bb57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 20 Dec 2020 21:08:55 +0100 Subject: [PATCH 459/719] Clean up with_generic_param_rib, avoid double hashing --- compiler/rustc_resolve/src/late.rs | 41 +++++++++++++----------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f156caf23ba9..02a7bc0b622e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -29,7 +29,7 @@ use rustc_span::Span; use smallvec::{smallvec, SmallVec}; use rustc_span::source_map::{respan, Spanned}; -use std::collections::BTreeSet; +use std::collections::{hash_map::Entry, BTreeSet}; use std::mem::{replace, take}; use tracing::debug; @@ -1060,36 +1060,29 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { continue; } - let def_kind = match param.kind { - GenericParamKind::Type { .. } => DefKind::TyParam, - GenericParamKind::Const { .. } => DefKind::ConstParam, - _ => unreachable!(), - }; - let ident = param.ident.normalize_to_macros_2_0(); debug!("with_generic_param_rib: {}", param.id); - if seen_bindings.contains_key(&ident) { - let span = seen_bindings.get(&ident).unwrap(); - let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, *span); - self.report_error(param.ident.span, err); + match seen_bindings.entry(ident) { + Entry::Occupied(entry) => { + let span = *entry.get(); + let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span); + self.report_error(param.ident.span, err); + } + Entry::Vacant(entry) => { + entry.insert(param.ident.span); + } } - seen_bindings.entry(ident).or_insert(param.ident.span); // Plain insert (no renaming). - let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id()); - - match param.kind { - GenericParamKind::Type { .. } => { - function_type_rib.bindings.insert(ident, res); - self.r.record_partial_res(param.id, PartialRes::new(res)); - } - GenericParamKind::Const { .. } => { - function_value_rib.bindings.insert(ident, res); - self.r.record_partial_res(param.id, PartialRes::new(res)); - } + let (rib, def_kind) = match param.kind { + GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam), + GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam), _ => unreachable!(), - } + }; + let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id()); + self.r.record_partial_res(param.id, PartialRes::new(res)); + rib.bindings.insert(ident, res); } self.ribs[ValueNS].push(function_value_rib); From 62f593bda9eff51efdbc3172c3ee768cb3528b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 20 Dec 2020 21:38:41 +0100 Subject: [PATCH 460/719] Precompute vector length in smart_resolve_path_fragment --- compiler/rustc_resolve/src/late.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 02a7bc0b622e..4beaf6bfa809 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1891,8 +1891,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.r.trait_map.insert(id, traits); } - let mut std_path = vec![Segment::from_ident(Ident::with_dummy_span(sym::std))]; + let mut std_path = Vec::with_capacity(1 + path.len()); + std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std))); std_path.extend(path); if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { From 91ea623f49bb28a770b2283cfbd5ed457ee3c48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 20 Dec 2020 21:41:15 +0100 Subject: [PATCH 461/719] Remove unnecessary cloned --- compiler/rustc_resolve/src/late.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 4beaf6bfa809..f33952bd3a97 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1977,7 +1977,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ) -> Result, Spanned>> { let mut fin_res = None; - for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() { + for (i, &ns) in [primary_ns, TypeNS, ValueNS].iter().enumerate() { if i == 0 || ns != primary_ns { match self.resolve_qpath(id, qself, path, ns, span, crate_lint)? { Some(partial_res) From 89bc399d56ead5b00028193708d26fc60ac607e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 20 Dec 2020 21:41:35 +0100 Subject: [PATCH 462/719] Add missing semicolon --- compiler/rustc_resolve/src/late.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f33952bd3a97..a45c5ccea9c6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1987,7 +1987,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } partial_res => { if fin_res.is_none() { - fin_res = partial_res + fin_res = partial_res; } } } From 60d55671602fcff089a7b9199608a1b397877836 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 20 Dec 2020 15:57:43 -0500 Subject: [PATCH 463/719] Fix incorrect logic when merging matches --- src/librustdoc/html/markdown.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e4a0d80674fb..0e87dd72ef1f 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -474,12 +474,13 @@ impl<'a, 'b, 'ids, I: Iterator, Range)>> Iterator if let Some((Event::Start(Tag::Heading(level)), _)) = event { let mut id = String::new(); for event in &mut self.inner { - match event.0 { + match &event.0 { Event::End(Tag::Heading(..)) => break, + Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {} Event::Text(text) | Event::Code(text) => { id.extend(text.chars().filter_map(slugify)); + self.buf.push_back(event); } - Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {} _ => self.buf.push_back(event), } } From 2e92b13a606ba2f073c789dfd6c33f889f04c8cf Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 20 Dec 2020 18:13:05 +0000 Subject: [PATCH 464/719] Prevent caching projections in the case of cycles When normalizing a projection which results in a cycle, we would cache the result of `project_type` without the nested obligations (because they're not needed for inference). This would result in the nested obligations only being handled once in fulfill, which would avoid the cycle error. Fixes #79714, a regresion from #79305 caused by the removal of `get_paranoid_cache_value_obligation`. --- compiler/rustc_infer/src/traits/project.rs | 16 +++++++- .../src/traits/project.rs | 14 ++++--- .../src/traits/select/mod.rs | 4 ++ .../defaults-cyclic-fail-1.rs | 4 +- .../defaults-cyclic-fail-1.stderr | 10 ++--- .../defaults-cyclic-fail-2.rs | 4 +- .../defaults-cyclic-fail-2.stderr | 10 ++--- .../ui/associated-types/impl-wf-cycle-1.rs | 29 ++++++++++++++ .../associated-types/impl-wf-cycle-1.stderr | 39 +++++++++++++++++++ .../ui/associated-types/impl-wf-cycle-2.rs | 16 ++++++++ .../associated-types/impl-wf-cycle-2.stderr | 25 ++++++++++++ 11 files changed, 150 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/associated-types/impl-wf-cycle-1.rs create mode 100644 src/test/ui/associated-types/impl-wf-cycle-1.stderr create mode 100644 src/test/ui/associated-types/impl-wf-cycle-2.rs create mode 100644 src/test/ui/associated-types/impl-wf-cycle-2.stderr diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index 65284bcee912..33bddf1dedc1 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -90,6 +90,7 @@ impl ProjectionCacheKey<'tcx> { pub enum ProjectionCacheEntry<'tcx> { InProgress, Ambiguous, + Recur, Error, NormalizedTy(NormalizedTy<'tcx>), } @@ -143,7 +144,12 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", key, value ); - let fresh_key = self.map().insert(key, ProjectionCacheEntry::NormalizedTy(value)); + let mut map = self.map(); + if let Some(ProjectionCacheEntry::Recur) = map.get(&key) { + debug!("Not overwriting Recur"); + return; + } + let fresh_key = map.insert(key, ProjectionCacheEntry::NormalizedTy(value)); assert!(!fresh_key, "never started projecting `{:?}`", key); } @@ -197,6 +203,14 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { assert!(!fresh, "never started projecting `{:?}`", key); } + /// Indicates that while trying to normalize `key`, `key` was required to + /// be normalized again. Selection or evaluation should eventually report + /// an error here. + pub fn recur(&mut self, key: ProjectionCacheKey<'tcx>) { + let fresh = self.map().insert(key, ProjectionCacheEntry::Recur); + assert!(!fresh, "never started projecting `{:?}`", key); + } + /// Indicates that trying to normalize `key` resulted in /// error. pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 7fa070caa275..fa0526445c19 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -496,12 +496,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( return Ok(None); } Err(ProjectionCacheEntry::InProgress) => { - // If while normalized A::B, we are asked to normalize - // A::B, just return A::B itself. This is a conservative - // answer, in the sense that A::B *is* clearly equivalent - // to A::B, though there may be a better value we can - // find. - // Under lazy normalization, this can arise when // bootstrapping. That is, imagine an environment with a // where-clause like `A::B == u32`. Now, if we are asked @@ -512,6 +506,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( debug!("found cache entry: in-progress"); + // Cache that normalizing this projection resulted in a cycle. This + // should ensure that, unless this happens within a snapshot that's + // rolled back, fulfillment or evaluation will notice the cycle. + + infcx.inner.borrow_mut().projection_cache().recur(cache_key); + return Err(InProgress); + } + Err(ProjectionCacheEntry::Recur) => { return Err(InProgress); } Err(ProjectionCacheEntry::NormalizedTy(ty)) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f1c86eab0956..a8f81445b039 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -291,6 +291,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } + pub(super) fn query_mode(&self) -> TraitQueryMode { + self.query_mode + } + /////////////////////////////////////////////////////////////////////////// // Selection // diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.rs b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs index afb2b3df716e..61ef013236e8 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-1.rs +++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs @@ -24,13 +24,13 @@ impl Tr for u32 { // ...but not in an impl that redefines one of the types. impl Tr for bool { type A = Box; - //~^ ERROR type mismatch resolving `::B == _` + //~^ ERROR overflow evaluating the requirement `::B == _` } // (the error is shown twice for some reason) impl Tr for usize { type B = &'static Self::A; - //~^ ERROR type mismatch resolving `::A == _` + //~^ ERROR overflow evaluating the requirement `::A == _` } fn main() { diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr index ae7150d47ca9..5e98520b4118 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr +++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr @@ -1,15 +1,15 @@ -error[E0271]: type mismatch resolving `::B == _` +error[E0275]: overflow evaluating the requirement `::B == _` --> $DIR/defaults-cyclic-fail-1.rs:26:5 | LL | type A = Box; - | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0271]: type mismatch resolving `::A == _` +error[E0275]: overflow evaluating the requirement `::A == _` --> $DIR/defaults-cyclic-fail-1.rs:32:5 | LL | type B = &'static Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.rs b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs index ba4bb0d5a296..e91c9f2d29a8 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-2.rs +++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs @@ -25,13 +25,13 @@ impl Tr for u32 { impl Tr for bool { type A = Box; - //~^ ERROR type mismatch resolving `::B == _` + //~^ ERROR overflow evaluating the requirement `::B == _` } // (the error is shown twice for some reason) impl Tr for usize { type B = &'static Self::A; - //~^ ERROR type mismatch resolving `::A == _` + //~^ ERROR overflow evaluating the requirement `::A == _` } fn main() { diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr index 0dfbac2dec5d..c538805f8582 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr +++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr @@ -1,15 +1,15 @@ -error[E0271]: type mismatch resolving `::B == _` +error[E0275]: overflow evaluating the requirement `::B == _` --> $DIR/defaults-cyclic-fail-2.rs:27:5 | LL | type A = Box; - | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0271]: type mismatch resolving `::A == _` +error[E0275]: overflow evaluating the requirement `::A == _` --> $DIR/defaults-cyclic-fail-2.rs:33:5 | LL | type B = &'static Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/impl-wf-cycle-1.rs b/src/test/ui/associated-types/impl-wf-cycle-1.rs new file mode 100644 index 000000000000..ba074210a2b5 --- /dev/null +++ b/src/test/ui/associated-types/impl-wf-cycle-1.rs @@ -0,0 +1,29 @@ +// Regression test for #79714 + +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for (T,) +where + Self::A: Baz, + Self::B: Fiz, +{ + type A = (); + //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` + type B = bool; + //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +} +//~^^^^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` + +fn main() { + let x: <(_,) as Grault>::A = (); +} diff --git a/src/test/ui/associated-types/impl-wf-cycle-1.stderr b/src/test/ui/associated-types/impl-wf-cycle-1.stderr new file mode 100644 index 000000000000..82328048c99a --- /dev/null +++ b/src/test/ui/associated-types/impl-wf-cycle-1.stderr @@ -0,0 +1,39 @@ +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-1.rs:15:1 + | +LL | / impl Grault for (T,) +LL | | where +LL | | Self::A: Baz, +LL | | Self::B: Fiz, +... | +LL | | +LL | | } + | |_^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-1.rs:20:5 + | +LL | type A = (); + | ^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-1.rs:22:5 + | +LL | type B = bool; + | ^^^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/impl-wf-cycle-2.rs b/src/test/ui/associated-types/impl-wf-cycle-2.rs new file mode 100644 index 000000000000..6fccc54f229a --- /dev/null +++ b/src/test/ui/associated-types/impl-wf-cycle-2.rs @@ -0,0 +1,16 @@ +// Regression test for #79714 + +trait Grault { + type A; +} + +impl Grault for (T,) +where + Self::A: Copy, +{ + type A = (); + //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +} +//~^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` + +fn main() {} diff --git a/src/test/ui/associated-types/impl-wf-cycle-2.stderr b/src/test/ui/associated-types/impl-wf-cycle-2.stderr new file mode 100644 index 000000000000..5cd18a33adf3 --- /dev/null +++ b/src/test/ui/associated-types/impl-wf-cycle-2.stderr @@ -0,0 +1,25 @@ +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-2.rs:7:1 + | +LL | / impl Grault for (T,) +LL | | where +LL | | Self::A: Copy, +LL | | { +LL | | type A = (); +LL | | +LL | | } + | |_^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-2.rs:11:5 + | +LL | type A = (); + | ^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0275`. From f499601dd879159dbb593d2451756364f013285d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 20 Dec 2020 22:49:53 +0100 Subject: [PATCH 465/719] Create closure outside of the loop --- compiler/rustc_resolve/src/late.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a45c5ccea9c6..eee115fc0f6b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -953,8 +953,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); }; - for item in trait_items { - this.with_trait_items(trait_items, |this| { + this.with_trait_items(trait_items, |this| { + for item in trait_items { match &item.kind { AssocItemKind::Const(_, ty, default) => { this.visit_ty(ty); @@ -983,8 +983,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { panic!("unexpanded macro in resolve!") } }; - }); - } + } + }); }); }); } From dc58fc4de0a877df53222b890bceea3b8129ec22 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 20 Dec 2020 14:08:55 -0800 Subject: [PATCH 466/719] Remove `I-prioritize` from Zulip topic It doesn't add anything since every topic in `t-compiler/wg-prioritization/alerts` is about prioritization. And it makes it harder to see the issue title, which is what the topic is actually about. --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index fc733b9e45f1..c0cf50e51670 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -90,7 +90,7 @@ exclude_labels = [ [notify-zulip."I-prioritize"] zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts -topic = "I-prioritize #{number} {title}" +topic = "#{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* issue #{number} has been requested for prioritization. From 8cfaf94a61bead79e3675b981a8563c2f36f04e9 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Sun, 20 Dec 2020 16:10:28 -0600 Subject: [PATCH 467/719] update rustfmt to v1.4.30 --- Cargo.lock | 4 ++-- src/tools/rustfmt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcfd23f2dae5..596a9413e1d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4396,7 +4396,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.29" +version = "1.4.30" dependencies = [ "annotate-snippets 0.6.1", "anyhow", @@ -5342,7 +5342,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.11.0", + "parking_lot 0.9.0", "regex", "serde", "serde_json", diff --git a/src/tools/rustfmt b/src/tools/rustfmt index 70ce18255f42..acd94866fd0f 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit 70ce18255f429caf0d75ecfed8c1464535ee779b +Subproject commit acd94866fd0ff5eacb7e184ae21c19e5440fc5fb From 66c28729016301da78f294aaff15d29567d9d02c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 20 Dec 2020 23:17:56 +0100 Subject: [PATCH 468/719] Inline a single-use closure --- compiler/rustc_resolve/src/late.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index eee115fc0f6b..2775ed51c51a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1771,7 +1771,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { path ); let ns = source.namespace(); - let is_expected = &|res| source.is_expected(res); let report_errors = |this: &mut Self, res: Option| { if this.should_report_errs() { @@ -1874,7 +1873,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { crate_lint, ) { Ok(Some(partial_res)) if partial_res.unresolved_segments() == 0 => { - if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err { + if source.is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err + { partial_res } else { report_errors(self, Some(partial_res.base_res())) From 6d71cc675091e2ca1080dc46ddaf3d202dd2c949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 20 Dec 2020 23:55:03 +0100 Subject: [PATCH 469/719] Move std_path construction into condition --- compiler/rustc_resolve/src/late.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2775ed51c51a..b13462587bc6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1891,12 +1891,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.r.trait_map.insert(id, traits); } - let mut std_path = Vec::with_capacity(1 + path.len()); - - std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std))); - std_path.extend(path); - if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { + let mut std_path = Vec::with_capacity(1 + path.len()); + + std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std))); + std_path.extend(path); if let PathResult::Module(_) | PathResult::NonModule(_) = self.resolve_path(&std_path, Some(ns), false, span, CrateLint::No) { From bb9b322b8ad666237995c02d074bf0eb95fefeef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 21 Dec 2020 00:00:00 +0000 Subject: [PATCH 470/719] Update stdarch submodule --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index f1ed22803f09..9c732a56f67f 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit f1ed22803f09e3b2c2b86d773db07ce70804987a +Subproject commit 9c732a56f67f54d12a0b4fd99993154906c95ea6 From 087101e285895b8bce94a16a90f7e7a3d938c3da Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 21 Dec 2020 12:05:10 +0100 Subject: [PATCH 471/719] make path normalization compatible with mac python2 --- src/test/run-make-fulldeps/coverage-reports/normalize_paths.py | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 src/test/run-make-fulldeps/coverage-reports/normalize_paths.py diff --git a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py old mode 100644 new mode 100755 index 05fb412cdb63..e5777ad2512f --- a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py +++ b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py @@ -1,5 +1,7 @@ #!/usr/bin/env python +from __future__ import print_function + import sys # Normalize file paths in output From a272d621bc7a2ca61d704fbe531dc532d49ab402 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Fri, 18 Dec 2020 17:32:26 +0100 Subject: [PATCH 472/719] Implemented a compiler diagnostic for move async mistake Ran the tidy check Following the diagnostic guide better Diagnostic generation is now relegated to its own function in the diagnostics module. Added tests Fixed the ui test --- compiler/rustc_parse/src/parser/diagnostics.rs | 18 ++++++++++++++++++ compiler/rustc_parse/src/parser/expr.rs | 18 ++++++++++++++---- ...ncorrect-move-async-order-issue-79694.fixed | 8 ++++++++ .../incorrect-move-async-order-issue-79694.rs | 8 ++++++++ ...correct-move-async-order-issue-79694.stderr | 13 +++++++++++++ 5 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.rs create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 350a372a684c..98c7b9a63a55 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1912,4 +1912,22 @@ impl<'a> Parser<'a> { *self = snapshot; Err(err) } + + /// Get the diagnostics for the cases where `move async` is found. + /// + /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword + pub(super) fn incorrect_move_async_order_found( + &self, + move_async_span: Span, + ) -> DiagnosticBuilder<'a> { + let mut err = + self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect"); + err.span_suggestion_verbose( + move_async_span, + "try switching the order", + "async move".to_owned(), + Applicability::MaybeIncorrect, + ); + err + } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93be478fc8c2..7d0d4f30137a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1603,7 +1603,7 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::async_closure, span); } - let capture_clause = self.parse_capture_clause(); + let capture_clause = self.parse_capture_clause()?; let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; let body = match decl.output { @@ -1626,8 +1626,18 @@ impl<'a> Parser<'a> { } /// Parses an optional `move` prefix to a closure-like construct. - fn parse_capture_clause(&mut self) -> CaptureBy { - if self.eat_keyword(kw::Move) { CaptureBy::Value } else { CaptureBy::Ref } + fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { + if self.eat_keyword(kw::Move) { + // Check for `move async` and recover + if self.check_keyword(kw::Async) { + let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + Err(self.incorrect_move_async_order_found(move_async_span)) + } else { + Ok(CaptureBy::Value) + } + } else { + Ok(CaptureBy::Ref) + } } /// Parses the `|arg, arg|` header of a closure. @@ -2018,7 +2028,7 @@ impl<'a> Parser<'a> { fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.expect_keyword(kw::Async)?; - let capture_clause = self.parse_capture_clause(); + let capture_clause = self.parse_capture_clause()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body); diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed new file mode 100644 index 000000000000..055800d23b6c --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs new file mode 100644 index 000000000000..e8be16516d6d --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr new file mode 100644 index 000000000000..2add9fb33c70 --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr @@ -0,0 +1,13 @@ +error: the order of `move` and `async` is incorrect + --> $DIR/incorrect-move-async-order-issue-79694.rs:7:13 + | +LL | let _ = move async { }; + | ^^^^^^^^^^ + | +help: try switching the order + | +LL | let _ = async move { }; + | ^^^^^^^^^^ + +error: aborting due to previous error + From 29bed26036f5b74d4779423ec2313ba8280ec4a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 13:35:45 +0100 Subject: [PATCH 473/719] slightly more typed interface to panic implementation --- library/panic_abort/src/lib.rs | 4 +++- library/panic_unwind/src/lib.rs | 3 +-- library/std/src/panicking.rs | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index a8ebb4b3219f..eb2277d8baac 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -14,11 +14,13 @@ #![feature(core_intrinsics)] #![feature(nll)] #![feature(panic_runtime)] +#![feature(std_internals)] #![feature(staged_api)] #![feature(rustc_attrs)] #![feature(asm)] use core::any::Any; +use core::panic::BoxMeUp; #[rustc_std_internal_symbol] #[allow(improper_ctypes_definitions)] @@ -28,7 +30,7 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen // "Leak" the payload and shim to the relevant abort on the platform in question. #[rustc_std_internal_symbol] -pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 { +pub unsafe extern "C" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 { abort(); cfg_if::cfg_if! { diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 0b74a844fec6..1ac050be3e43 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -104,8 +104,7 @@ pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any // implementation. #[rustc_std_internal_symbol] #[unwind(allowed)] -pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 { - let payload = payload as *mut &mut dyn BoxMeUp; +pub unsafe extern "C" fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 { let payload = (*payload).take_box(); imp::panic(Box::from_raw(payload)) diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 8ba3feccb6bc..31c215a52a2e 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -48,7 +48,7 @@ extern "C" { /// It cannot be `Box` because the other end of this call does not depend /// on liballoc, and thus cannot use `Box`. #[unwind(allowed)] - fn __rust_start_panic(payload: usize) -> u32; + fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32; } /// This function is called by the panic runtime if FFI code catches a Rust @@ -637,7 +637,7 @@ pub fn rust_panic_without_hook(payload: Box) -> ! { fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! { let code = unsafe { let obj = &mut msg as *mut &mut dyn BoxMeUp; - __rust_start_panic(obj as usize) + __rust_start_panic(obj) }; rtabort!("failed to initiate panic, error {}", code) } From dffa1e241289f1c98f8a6e4757c00305592e7794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 21 Dec 2020 17:40:39 +0100 Subject: [PATCH 474/719] Remove redundant test --- src/test/rustdoc-ui/reference-link-has-one-warning.rs | 6 ------ .../rustdoc-ui/reference-link-has-one-warning.stderr | 10 ---------- 2 files changed, 16 deletions(-) delete mode 100644 src/test/rustdoc-ui/reference-link-has-one-warning.rs delete mode 100644 src/test/rustdoc-ui/reference-link-has-one-warning.stderr diff --git a/src/test/rustdoc-ui/reference-link-has-one-warning.rs b/src/test/rustdoc-ui/reference-link-has-one-warning.rs deleted file mode 100644 index 21cb7eb9040b..000000000000 --- a/src/test/rustdoc-ui/reference-link-has-one-warning.rs +++ /dev/null @@ -1,6 +0,0 @@ -// ignore-test -// check-pass - -/// docs [label][with#anchor#error] -//~^ WARNING has an issue with the link anchor -pub struct S; diff --git a/src/test/rustdoc-ui/reference-link-has-one-warning.stderr b/src/test/rustdoc-ui/reference-link-has-one-warning.stderr deleted file mode 100644 index a1eeb60f1785..000000000000 --- a/src/test/rustdoc-ui/reference-link-has-one-warning.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: `[with#anchor#error]` has an issue with the link anchor. - --> $DIR/reference-link-has-one-warning.rs:3:18 - | -LL | /// docs [label][with#anchor#error] - | ^^^^^^^^^^^^^^^^^ only one `#` is allowed in a link - | - = note: `#[warn(broken_intra_doc_links)]` on by default - -warning: 1 warning emitted - From 00ff7fe6bd068b457fcd70de943d4ed81d58e1a5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 21 Dec 2020 21:59:57 +0300 Subject: [PATCH 475/719] rustc_span: Provide a reserved identifier check for a specific edition Edition evaluation is kept lazy because it may be expensive. --- compiler/rustc_span/src/symbol.rs | 43 +++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4d14763825ca..46b08174f740 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -13,7 +13,7 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::str; -use crate::{Span, DUMMY_SP, SESSION_GLOBALS}; +use crate::{Edition, Span, DUMMY_SP, SESSION_GLOBALS}; #[cfg(test)] mod tests; @@ -1609,12 +1609,32 @@ pub mod sym { } impl Symbol { - fn is_used_keyword_2018(self) -> bool { - self >= kw::Async && self <= kw::Dyn + fn is_special(self) -> bool { + self <= kw::Underscore } - fn is_unused_keyword_2018(self) -> bool { - self == kw::Try + fn is_used_keyword_always(self) -> bool { + self >= kw::As && self <= kw::While + } + + fn is_used_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { + (self >= kw::Async && self <= kw::Dyn) && edition() >= Edition::Edition2018 + } + + fn is_unused_keyword_always(self) -> bool { + self >= kw::Abstract && self <= kw::Yield + } + + fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { + self == kw::Try && edition() >= Edition::Edition2018 + } + + pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool { + self.is_special() + || self.is_used_keyword_always() + || self.is_unused_keyword_always() + || self.is_used_keyword_conditional(edition) + || self.is_unused_keyword_conditional(edition) } /// A keyword or reserved identifier that can be used as a path segment. @@ -1642,26 +1662,27 @@ impl Ident { // Returns `true` for reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. pub fn is_special(self) -> bool { - self.name <= kw::Underscore + self.name.is_special() } /// Returns `true` if the token is a keyword used in the language. pub fn is_used_keyword(self) -> bool { // Note: `span.edition()` is relatively expensive, don't call it unless necessary. - self.name >= kw::As && self.name <= kw::While - || self.name.is_used_keyword_2018() && self.span.rust_2018() + self.name.is_used_keyword_always() + || self.name.is_used_keyword_conditional(|| self.span.edition()) } /// Returns `true` if the token is a keyword reserved for possible future use. pub fn is_unused_keyword(self) -> bool { // Note: `span.edition()` is relatively expensive, don't call it unless necessary. - self.name >= kw::Abstract && self.name <= kw::Yield - || self.name.is_unused_keyword_2018() && self.span.rust_2018() + self.name.is_unused_keyword_always() + || self.name.is_unused_keyword_conditional(|| self.span.edition()) } /// Returns `true` if the token is either a special identifier or a keyword. pub fn is_reserved(self) -> bool { - self.is_special() || self.is_used_keyword() || self.is_unused_keyword() + // Note: `span.edition()` is relatively expensive, don't call it unless necessary. + self.name.is_reserved(|| self.span.edition()) } /// A keyword or reserved identifier that can be used as a path segment. From aec3575aa7d6903fbff2140b37b65961836d47dc Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 14:17:53 -0800 Subject: [PATCH 476/719] Rename rustc_middle::lint::LintSource Rename rustc_middle::lint::LintSource to rustc_middle::lint::LintLevelSource. --- compiler/rustc_lint/src/levels.rs | 20 ++++++------ compiler/rustc_middle/src/lint.rs | 32 +++++++++---------- compiler/rustc_middle/src/ty/context.rs | 4 +-- .../passes/calculate_doc_coverage.rs | 4 +-- src/librustdoc/passes/doc_test_lints.rs | 4 +-- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 3e22eba15aae..410bd06850e7 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -12,7 +12,7 @@ use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::map::Map; use rustc_middle::lint::LevelSource; use rustc_middle::lint::LintDiagnosticBuilder; -use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; +use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintLevelSource}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{builtin, Level, Lint, LintId}; @@ -91,7 +91,7 @@ impl<'s> LintLevelsBuilder<'s> { }; for id in ids { self.check_gated_lint(id, DUMMY_SP); - let src = LintSource::CommandLine(lint_flag_val, orig_level); + let src = LintLevelSource::CommandLine(lint_flag_val, orig_level); specs.insert(id, (level, src)); } } @@ -128,19 +128,19 @@ impl<'s> LintLevelsBuilder<'s> { ); diag_builder.span_label(src.span(), "overruled by previous forbid"); match old_src { - LintSource::Default => { + LintLevelSource::Default => { diag_builder.note(&format!( "`forbid` lint level is the default for {}", id.to_string() )); } - LintSource::Node(_, forbid_source_span, reason) => { + LintLevelSource::Node(_, forbid_source_span, reason) => { diag_builder.span_label(forbid_source_span, "`forbid` level set here"); if let Some(rationale) = reason { diag_builder.note(&rationale.as_str()); } } - LintSource::CommandLine(_, _) => { + LintLevelSource::CommandLine(_, _) => { diag_builder.note("`forbid` lint level was set on command line"); } } @@ -276,7 +276,7 @@ impl<'s> LintLevelsBuilder<'s> { let name = meta_item.path.segments.last().expect("empty lint name").ident.name; match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { - let src = LintSource::Node(name, li.span(), reason); + let src = LintLevelSource::Node(name, li.span(), reason); for &id in ids { self.check_gated_lint(id, attr.span); self.insert_spec(&mut specs, id, (level, src)); @@ -287,7 +287,7 @@ impl<'s> LintLevelsBuilder<'s> { match result { Ok(ids) => { let complete_name = &format!("{}::{}", tool_name.unwrap(), name); - let src = LintSource::Node( + let src = LintLevelSource::Node( Symbol::intern(complete_name), li.span(), reason, @@ -324,7 +324,7 @@ impl<'s> LintLevelsBuilder<'s> { }, ); - let src = LintSource::Node( + let src = LintLevelSource::Node( Symbol::intern(&new_lint_name), li.span(), reason, @@ -403,7 +403,7 @@ impl<'s> LintLevelsBuilder<'s> { } let (lint_attr_name, lint_attr_span) = match *src { - LintSource::Node(name, span, _) => (name, span), + LintLevelSource::Node(name, span, _) => (name, span), _ => continue, }; @@ -460,7 +460,7 @@ impl<'s> LintLevelsBuilder<'s> { } /// Find the lint level for a lint. - pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintSource) { + pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) { self.sets.get_lint_level(lint, self.cur, None, self.sess) } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index a61d37cc90eb..2dbb84970d10 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -13,7 +13,7 @@ use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; /// How a lint level was set. #[derive(Clone, Copy, PartialEq, Eq, HashStable)] -pub enum LintSource { +pub enum LintLevelSource { /// Lint is at the default level as declared /// in rustc or a plugin. Default, @@ -27,25 +27,25 @@ pub enum LintSource { CommandLine(Symbol, Level), } -impl LintSource { +impl LintLevelSource { pub fn name(&self) -> Symbol { match *self { - LintSource::Default => symbol::kw::Default, - LintSource::Node(name, _, _) => name, - LintSource::CommandLine(name, _) => name, + LintLevelSource::Default => symbol::kw::Default, + LintLevelSource::Node(name, _, _) => name, + LintLevelSource::CommandLine(name, _) => name, } } pub fn span(&self) -> Span { match *self { - LintSource::Default => DUMMY_SP, - LintSource::Node(_, span, _) => span, - LintSource::CommandLine(_, _) => DUMMY_SP, + LintLevelSource::Default => DUMMY_SP, + LintLevelSource::Node(_, span, _) => span, + LintLevelSource::CommandLine(_, _) => DUMMY_SP, } } } -pub type LevelSource = (Level, LintSource); +pub type LevelSource = (Level, LintLevelSource); pub struct LintLevelSets { pub list: Vec, @@ -113,7 +113,7 @@ impl LintLevelSets { id: LintId, mut idx: u32, aux: Option<&FxHashMap>, - ) -> (Option, LintSource) { + ) -> (Option, LintLevelSource) { if let Some(specs) = aux { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); @@ -125,7 +125,7 @@ impl LintLevelSets { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); } - return (None, LintSource::Default); + return (None, LintLevelSource::Default); } LintSet::Node { ref specs, parent } => { if let Some(&(level, src)) = specs.get(&id) { @@ -213,7 +213,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option, decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd, ) { @@ -223,7 +223,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option, decorate: Box FnOnce(LintDiagnosticBuilder<'b>) + 'd>, ) { @@ -274,14 +274,14 @@ pub fn struct_lint_level<'s, 'd>( let name = lint.name_lower(); match src { - LintSource::Default => { + LintLevelSource::Default => { sess.diag_note_once( &mut err, DiagnosticMessageId::from(lint), &format!("`#[{}({})]` on by default", level.as_str(), name), ); } - LintSource::CommandLine(lint_flag_val, orig_level) => { + LintLevelSource::CommandLine(lint_flag_val, orig_level) => { let flag = match orig_level { Level::Warn => "-W", Level::Deny => "-D", @@ -310,7 +310,7 @@ pub fn struct_lint_level<'s, 'd>( ); } } - LintSource::Node(lint_attr_name, src, reason) => { + LintLevelSource::Node(lint_attr_name, src, reason) => { if let Some(rationale) = reason { err.note(&rationale.as_str()); } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4205e2ca5aa6..9b944f202a93 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -5,7 +5,7 @@ use crate::dep_graph::{self, DepGraph, DepKind, DepNode, DepNodeExt}; use crate::hir::exports::ExportMap; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintSource}; +use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::middle; use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata}; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; @@ -2559,7 +2559,7 @@ impl<'tcx> TyCtxt<'tcx> { self, lint: &'static Lint, mut id: hir::HirId, - ) -> (Level, LintSource) { + ) -> (Level, LintLevelSource) { let sets = self.lint_levels(LOCAL_CRATE); loop { if let Some(pair) = sets.level_and_source(lint, id, self.sess) { diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 52f6a97089bd..af5121d6b1be 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -5,7 +5,7 @@ use crate::html::markdown::{find_testable_code, ErrorCodes}; use crate::passes::doc_test_lints::{should_have_doc_example, Tests}; use crate::passes::Pass; use rustc_lint::builtin::MISSING_DOCS; -use rustc_middle::lint::LintSource; +use rustc_middle::lint::LintLevelSource; use rustc_session::lint; use rustc_span::symbol::sym; use rustc_span::FileName; @@ -254,7 +254,7 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { // `missing_docs` is allow-by-default, so don't treat this as ignoring the item // unless the user had an explicit `allow` let should_have_docs = - level != lint::Level::Allow || matches!(source, LintSource::Default); + level != lint::Level::Allow || matches!(source, LintLevelSource::Default); debug!("counting {:?} {:?} in {}", i.type_(), i.name, filename); self.items.entry(filename).or_default().count_item( has_docs, diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 1c1141e7c812..17d2847913d4 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -9,7 +9,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; -use rustc_middle::lint::LintSource; +use rustc_middle::lint::LintLevelSource; use rustc_session::lint; crate const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { @@ -77,7 +77,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local()); let (level, source) = cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id); - level != lint::Level::Allow || matches!(source, LintSource::Default) + level != lint::Level::Allow || matches!(source, LintLevelSource::Default) } crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { From d3900d3775c665237b83ea87e01838da9cf0da87 Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 14:40:50 -0800 Subject: [PATCH 477/719] Document rustc_middle::lint::LevelSource This is to clarify the difference between `LevelSource` and `LintLevelSource`. Appease x.py fmt. --- compiler/rustc_lint/src/levels.rs | 4 +++- compiler/rustc_middle/src/lint.rs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 410bd06850e7..5cece569903c 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -12,7 +12,9 @@ use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::map::Map; use rustc_middle::lint::LevelSource; use rustc_middle::lint::LintDiagnosticBuilder; -use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintLevelSource}; +use rustc_middle::lint::{ + struct_lint_level, LintLevelMap, LintLevelSets, LintLevelSource, LintSet, +}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{builtin, Level, Lint, LintId}; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 2dbb84970d10..d1a7e89734d2 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -45,6 +45,7 @@ impl LintLevelSource { } } +/// A tuple of a lint level and its source. pub type LevelSource = (Level, LintLevelSource); pub struct LintLevelSets { From c2281cc1899c79823aab72e5a987764c5ae4dd49 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Thu, 19 Nov 2020 21:39:23 +0100 Subject: [PATCH 478/719] Stabilize `core::slice::fill` --- library/core/src/slice/mod.rs | 4 +--- library/std/src/lib.rs | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 44fe2ca88596..f5af48e0dd27 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2581,14 +2581,12 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_fill)] - /// /// let mut buf = vec![0; 10]; /// buf.fill(1); /// assert_eq!(buf, vec![1; 10]); /// ``` #[doc(alias = "memset")] - #[unstable(feature = "slice_fill", issue = "70758")] + #[stable(feature = "slice_fill", since = "1.50.0")] pub fn fill(&mut self, value: T) where T: Clone, diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 39b0ca63301e..5bc5ddaa5fe3 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -304,7 +304,6 @@ #![feature(rustc_private)] #![feature(shrink_to)] #![feature(slice_concat_ext)] -#![feature(slice_fill)] #![feature(slice_internals)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] From 163f5da322f7e62216532735c67813060eacc8de Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 17:18:48 -0800 Subject: [PATCH 479/719] Add installation commands to `x` tool README --- src/tools/x/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tools/x/README.md b/src/tools/x/README.md index 3b3cf2847c20..80bf02e8a0ef 100644 --- a/src/tools/x/README.md +++ b/src/tools/x/README.md @@ -1,3 +1,10 @@ # x `x` invokes `x.py` from any subdirectory. + +To install, run the following commands: + +``` +$ cd rust/src/tools/x/ +$ cargo install --path . +``` From 1339c813906a33530b1ef2770141fecc03ec9452 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 21 Dec 2020 19:00:49 -0800 Subject: [PATCH 480/719] Update books --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/book b/src/doc/book index a190438d77d2..5bb44f8b5b0a 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit a190438d77d28041f24da4f6592e287fab073a61 +Subproject commit 5bb44f8b5b0aa105c8b22602e9b18800484afa21 diff --git a/src/doc/nomicon b/src/doc/nomicon index d8383b65f794..a5a48441d411 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit d8383b65f7948c2ca19191b3b4bd709b403aaf45 +Subproject commit a5a48441d411f61556b57d762b03d6874afe575d diff --git a/src/doc/reference b/src/doc/reference index a8afdca5d071..b278478b7661 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit a8afdca5d0715b2257b6f8b9a032fd4dd7dae855 +Subproject commit b278478b766178491a8b6f67afa4bcd6b64d977a diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 236c734a2cb3..1cce0737d6a7 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 236c734a2cb323541b3394f98682cb981b9ec086 +Subproject commit 1cce0737d6a7d3ceafb139b4a206861fb1dcb2ab From 80aa551d668233280e78b689b56ccb6cbffca368 Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 20:00:18 -0800 Subject: [PATCH 481/719] docs: Edit rustc_middle::middle::privacy Add descriptions of `AccessLevel` and `AccessLevels`. Add missing punctuation. --- compiler/rustc_middle/src/middle/privacy.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 254b57a005e8..54188985d7c5 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -8,7 +8,9 @@ use rustc_macros::HashStable; use std::fmt; use std::hash::Hash; -// Accessibility levels, sorted in ascending order +/// Represents the levels of accessibility an item can have. +/// +/// The variants are sorted in ascending order of accessibility. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)] pub enum AccessLevel { /// Superset of `AccessLevel::Reachable` used to mark impl Trait items. @@ -18,13 +20,13 @@ pub enum AccessLevel { /// public, then type `T` is reachable. Its values can be obtained by other crates /// even if the type itself is not nameable. Reachable, - /// Public items + items accessible to other crates with help of `pub use` re-exports + /// Public items + items accessible to other crates with the help of `pub use` re-exports. Exported, - /// Items accessible to other crates directly, without help of re-exports + /// Items accessible to other crates directly, without the help of re-exports. Public, } -// Accessibility levels for reachable HIR nodes +/// Holds a map of accessibility levels for reachable HIR nodes. #[derive(Clone)] pub struct AccessLevels { pub map: FxHashMap, From 3abba5e21f362e325d52d922676ef26513a668e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 20 Nov 2020 21:45:51 +0100 Subject: [PATCH 482/719] Deprecate compare_and_swap on all atomic types --- library/core/src/sync/atomic.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index a96da9aa6dc7..8de7d53f3025 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -479,6 +479,10 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated( + since = "1.50.0", + reason = "Use `compare_exchange` or `compare_exchange_weak` instead" + )] #[cfg(target_has_atomic = "8")] pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { @@ -1080,6 +1084,10 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated( + since = "1.50.0", + reason = "Use `compare_exchange` or `compare_exchange_weak` instead" + )] #[cfg(target_has_atomic = "ptr")] pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { @@ -1619,6 +1627,10 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[inline] #[$stable] + #[rustc_deprecated( + since = "1.50.0", + reason = "Use `compare_exchange` or `compare_exchange_weak` instead") + ] #[$cfg_cas] pub fn compare_and_swap(&self, current: $int_type, From 4252e482569f00612e768811cbe0295562095343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 20 Nov 2020 22:16:15 +0100 Subject: [PATCH 483/719] Add documentation on migrating away from compare_and_swap --- library/core/src/sync/atomic.rs | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 8de7d53f3025..4fc455d06ede 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -464,6 +464,23 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// + /// # Migrating to `compare_exchange` and `compare_exchange_weak` + /// + /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for + /// memory orderings: + /// + /// Original | Success | Failure + /// -------- | ------- | ------- + /// Relaxed | Relaxed | Relaxed + /// Acquire | Acquire | Acquire + /// Release | Release | Relaxed + /// AcqRel | AcqRel | Acquire + /// SeqCst | SeqCst | SeqCst + /// + /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, + /// which allows the compiler to generate better assembly code when the compare and swap + /// is used in a loop. + /// /// # Examples /// /// ``` @@ -1070,6 +1087,23 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// + /// # Migrating to `compare_exchange` and `compare_exchange_weak` + /// + /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for + /// memory orderings: + /// + /// Original | Success | Failure + /// -------- | ------- | ------- + /// Relaxed | Relaxed | Relaxed + /// Acquire | Acquire | Acquire + /// Release | Release | Relaxed + /// AcqRel | AcqRel | Acquire + /// SeqCst | SeqCst | SeqCst + /// + /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, + /// which allows the compiler to generate better assembly code when the compare and swap + /// is used in a loop. + /// /// # Examples /// /// ``` @@ -1612,6 +1646,23 @@ happens, and using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). +# Migrating to `compare_exchange` and `compare_exchange_weak` + +`compare_and_swap` is equivalent to `compare_exchange` with the following mapping for +memory orderings: + +Original | Success | Failure +-------- | ------- | ------- +Relaxed | Relaxed | Relaxed +Acquire | Acquire | Acquire +Release | Release | Relaxed +AcqRel | AcqRel | Acquire +SeqCst | SeqCst | SeqCst + +`compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, +which allows the compiler to generate better assembly code when the compare and swap +is used in a loop. + # Examples ``` From 828d4ace4dee856b376fa44cc095d490ee799c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 20 Nov 2020 22:27:50 +0100 Subject: [PATCH 484/719] Migrate standard library away from compare_and_swap --- library/core/tests/atomic.rs | 6 +++--- library/std/src/sync/mpsc/blocking.rs | 6 +++++- library/std/src/sync/mpsc/oneshot.rs | 14 +++++++++++--- library/std/src/sync/mpsc/shared.rs | 11 +++++++++-- library/std/src/sync/mpsc/stream.rs | 9 ++++++--- library/std/src/sync/once.rs | 16 +++++++++++----- library/std/src/sys/sgx/abi/mod.rs | 8 ++++---- library/std/src/sys/sgx/waitqueue/spin_mutex.rs | 2 +- library/std/src/sys/windows/mutex.rs | 6 +++--- library/std/src/sys_common/condvar/check.rs | 6 +++--- library/std/src/sys_common/thread_local_key.rs | 8 ++++---- .../std/src/sys_common/thread_parker/futex.rs | 2 +- .../ui/array-slice-vec/box-of-array-of-drop-1.rs | 7 ++++++- .../ui/array-slice-vec/box-of-array-of-drop-2.rs | 7 ++++++- src/test/ui/array-slice-vec/nested-vec-3.rs | 7 ++++++- 15 files changed, 79 insertions(+), 36 deletions(-) diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index 75528ebb54ea..2d1e4496aeef 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -4,11 +4,11 @@ use core::sync::atomic::*; #[test] fn bool_() { let a = AtomicBool::new(false); - assert_eq!(a.compare_and_swap(false, true, SeqCst), false); - assert_eq!(a.compare_and_swap(false, true, SeqCst), true); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false)); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Err(true)); a.store(false, SeqCst); - assert_eq!(a.compare_and_swap(false, true, SeqCst), false); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false)); } #[test] diff --git a/library/std/src/sync/mpsc/blocking.rs b/library/std/src/sync/mpsc/blocking.rs index d34de6a4fac3..4c852b8ee812 100644 --- a/library/std/src/sync/mpsc/blocking.rs +++ b/library/std/src/sync/mpsc/blocking.rs @@ -36,7 +36,11 @@ pub fn tokens() -> (WaitToken, SignalToken) { impl SignalToken { pub fn signal(&self) -> bool { - let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst); + let wake = self + .inner + .woken + .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) + .is_ok(); if wake { self.inner.thread.unpark(); } diff --git a/library/std/src/sync/mpsc/oneshot.rs b/library/std/src/sync/mpsc/oneshot.rs index 75f5621fa127..3dcf03f579a0 100644 --- a/library/std/src/sync/mpsc/oneshot.rs +++ b/library/std/src/sync/mpsc/oneshot.rs @@ -129,7 +129,7 @@ impl Packet { let ptr = unsafe { signal_token.cast_to_usize() }; // race with senders to enter the blocking state - if self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) == EMPTY { + if self.state.compare_exchange(EMPTY, ptr, Ordering::SeqCst, Ordering::SeqCst).is_ok() { if let Some(deadline) = deadline { let timed_out = !wait_token.wait_max_until(deadline); // Try to reset the state @@ -161,7 +161,12 @@ impl Packet { // the state changes under our feet we'd rather just see that state // change. DATA => { - self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst); + let _ = self.state.compare_exchange( + DATA, + EMPTY, + Ordering::SeqCst, + Ordering::SeqCst, + ); match (&mut *self.data.get()).take() { Some(data) => Ok(data), None => unreachable!(), @@ -264,7 +269,10 @@ impl Packet { // If we've got a blocked thread, then use an atomic to gain ownership // of it (may fail) - ptr => self.state.compare_and_swap(ptr, EMPTY, Ordering::SeqCst), + ptr => self + .state + .compare_exchange(ptr, EMPTY, Ordering::SeqCst, Ordering::SeqCst) + .unwrap_or_else(|x| x), }; // Now that we've got ownership of our state, figure out what to do diff --git a/library/std/src/sync/mpsc/shared.rs b/library/std/src/sync/mpsc/shared.rs index 898654f21f2e..0c32e636a563 100644 --- a/library/std/src/sync/mpsc/shared.rs +++ b/library/std/src/sync/mpsc/shared.rs @@ -385,8 +385,15 @@ impl Packet { self.port_dropped.store(true, Ordering::SeqCst); let mut steals = unsafe { *self.steals.get() }; while { - let cnt = self.cnt.compare_and_swap(steals, DISCONNECTED, Ordering::SeqCst); - cnt != DISCONNECTED && cnt != steals + match self.cnt.compare_exchange( + steals, + DISCONNECTED, + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(_) => false, + Err(old) => old != DISCONNECTED, + } } { // See the discussion in 'try_recv' for why we yield // control of this thread. diff --git a/library/std/src/sync/mpsc/stream.rs b/library/std/src/sync/mpsc/stream.rs index 9f7c1af89519..a652f24c58a1 100644 --- a/library/std/src/sync/mpsc/stream.rs +++ b/library/std/src/sync/mpsc/stream.rs @@ -322,12 +322,15 @@ impl Packet { // (because there is a bounded number of senders). let mut steals = unsafe { *self.queue.consumer_addition().steals.get() }; while { - let cnt = self.queue.producer_addition().cnt.compare_and_swap( + match self.queue.producer_addition().cnt.compare_exchange( steals, DISCONNECTED, Ordering::SeqCst, - ); - cnt != DISCONNECTED && cnt != steals + Ordering::SeqCst, + ) { + Ok(_) => false, + Err(old) => old != DISCONNECTED, + } } { while self.queue.pop().is_some() { steals += 1; diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index de5ddf1daf27..9a17d121db19 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -65,7 +65,7 @@ // must do so with Release ordering to make the result available. // - `wait` inserts `Waiter` nodes as a pointer in `state_and_queue`, and // needs to make the nodes available with Release ordering. The load in -// its `compare_and_swap` can be Relaxed because it only has to compare +// its `compare_exchange` can be Relaxed because it only has to compare // the atomic, not to read other data. // - `WaiterQueue::Drop` must see the `Waiter` nodes, so it must load // `state_and_queue` with Acquire ordering. @@ -395,12 +395,13 @@ impl Once { } POISONED | INCOMPLETE => { // Try to register this thread as the one RUNNING. - let old = self.state_and_queue.compare_and_swap( + let exchange_result = self.state_and_queue.compare_exchange( state_and_queue, RUNNING, Ordering::Acquire, + Ordering::Acquire, ); - if old != state_and_queue { + if let Err(old) = exchange_result { state_and_queue = old; continue; } @@ -452,8 +453,13 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { // Try to slide in the node at the head of the linked list, making sure // that another thread didn't just replace the head of the linked list. - let old = state_and_queue.compare_and_swap(current_state, me | RUNNING, Ordering::Release); - if old != current_state { + let exchange_result = state_and_queue.compare_exchange( + current_state, + me | RUNNING, + Ordering::Release, + Ordering::Relaxed, + ); + if let Err(old) = exchange_result { current_state = old; continue; } diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs index a0eb12c3d154..a5e453034762 100644 --- a/library/std/src/sys/sgx/abi/mod.rs +++ b/library/std/src/sys/sgx/abi/mod.rs @@ -36,20 +36,20 @@ unsafe extern "C" fn tcs_init(secondary: bool) { } // Try to atomically swap UNINIT with BUSY. The returned state can be: - match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) { + match RELOC_STATE.compare_exchange(UNINIT, BUSY, Ordering::Acquire, Ordering::Acquire) { // This thread just obtained the lock and other threads will observe BUSY - UNINIT => { + Ok(_) => { reloc::relocate_elf_rela(); RELOC_STATE.store(DONE, Ordering::Release); } // We need to wait until the initialization is done. - BUSY => { + Err(BUSY) => { while RELOC_STATE.load(Ordering::Acquire) == BUSY { core::hint::spin_loop(); } } // Initialization is done. - DONE => {} + Err(DONE) => {} _ => unreachable!(), } } diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs index d99ce895da59..9140041c5841 100644 --- a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs +++ b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs @@ -42,7 +42,7 @@ impl SpinMutex { #[inline(always)] pub fn try_lock(&self) -> Option> { - if !self.lock.compare_and_swap(false, true, Ordering::Acquire) { + if self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_ok() { Some(SpinMutexGuard { mutex: self }) } else { None diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index fa51b006c346..d4cc56d4cb3e 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -123,9 +123,9 @@ impl Mutex { let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) }; inner.remutex.init(); let inner = Box::into_raw(inner); - match self.lock.compare_and_swap(0, inner as usize, Ordering::SeqCst) { - 0 => inner, - n => { + match self.lock.compare_exchange(0, inner as usize, Ordering::SeqCst, Ordering::SeqCst) { + Ok(_) => inner, + Err(n) => { Box::from_raw(inner).remutex.destroy(); n as *const _ } diff --git a/library/std/src/sys_common/condvar/check.rs b/library/std/src/sys_common/condvar/check.rs index fecb732b910c..1578a2de60ce 100644 --- a/library/std/src/sys_common/condvar/check.rs +++ b/library/std/src/sys_common/condvar/check.rs @@ -23,9 +23,9 @@ impl SameMutexCheck { } pub fn verify(&self, mutex: &MovableMutex) { let addr = mutex.raw() as *const mutex_imp::Mutex as usize; - match self.addr.compare_and_swap(0, addr, Ordering::SeqCst) { - 0 => {} // Stored the address - n if n == addr => {} // Lost a race to store the same address + match self.addr.compare_exchange(0, addr, Ordering::SeqCst, Ordering::SeqCst) { + Ok(_) => {} // Stored the address + Err(n) if n == addr => {} // Lost a race to store the same address _ => panic!("attempted to use a condition variable with two mutexes"), } } diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index dbcb7b36265f..32cd56416655 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -168,7 +168,7 @@ impl StaticKey { return key; } - // POSIX allows the key created here to be 0, but the compare_and_swap + // POSIX allows the key created here to be 0, but the compare_exchange // below relies on using 0 as a sentinel value to check who won the // race to set the shared TLS key. As far as I know, there is no // guaranteed value that cannot be returned as a posix_key_create key, @@ -186,11 +186,11 @@ impl StaticKey { key2 }; rtassert!(key != 0); - match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) { + match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) { // The CAS succeeded, so we've created the actual key - 0 => key as usize, + Ok(_) => key as usize, // If someone beat us to the punch, use their key instead - n => { + Err(n) => { imp::destroy(key); n } diff --git a/library/std/src/sys_common/thread_parker/futex.rs b/library/std/src/sys_common/thread_parker/futex.rs index a5d4927dcc5c..0132743b2440 100644 --- a/library/std/src/sys_common/thread_parker/futex.rs +++ b/library/std/src/sys_common/thread_parker/futex.rs @@ -49,7 +49,7 @@ impl Parker { // Wait for something to happen, assuming it's still set to PARKED. futex_wait(&self.state, PARKED, None); // Change NOTIFIED=>EMPTY and return in that case. - if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED { + if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() { return; } else { // Spurious wake up. We loop to try again. diff --git a/src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs b/src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs index d48589328156..c8559d247282 100644 --- a/src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs +++ b/src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs @@ -17,7 +17,12 @@ impl Drop for D { fn drop(&mut self) { println!("Dropping {}", self.0); let old = LOG.load(Ordering::SeqCst); - LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst); + let _ = LOG.compare_exchange( + old, + old << 4 | self.0 as usize, + Ordering::SeqCst, + Ordering::SeqCst + ); } } diff --git a/src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs b/src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs index e8a5b00a55b9..e75051caabcc 100644 --- a/src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs +++ b/src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs @@ -17,7 +17,12 @@ impl Drop for D { fn drop(&mut self) { println!("Dropping {}", self.0); let old = LOG.load(Ordering::SeqCst); - LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst); + let _ = LOG.compare_exchange( + old, + old << 4 | self.0 as usize, + Ordering::SeqCst, + Ordering::SeqCst + ); } } diff --git a/src/test/ui/array-slice-vec/nested-vec-3.rs b/src/test/ui/array-slice-vec/nested-vec-3.rs index 52b892dbcdfa..96497a53d308 100644 --- a/src/test/ui/array-slice-vec/nested-vec-3.rs +++ b/src/test/ui/array-slice-vec/nested-vec-3.rs @@ -18,7 +18,12 @@ impl Drop for D { fn drop(&mut self) { println!("Dropping {}", self.0); let old = LOG.load(Ordering::SeqCst); - LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst); + let _ = LOG.compare_exchange( + old, + old << 4 | self.0 as usize, + Ordering::SeqCst, + Ordering::SeqCst, + ); } } From 7f35e2d5737a73e86c08316aca9c9cd90ddde3cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sun, 22 Nov 2020 18:56:47 +0100 Subject: [PATCH 485/719] Add doc aliases to compare_exchange[_weak] --- library/core/src/sync/atomic.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 4fc455d06ede..668b0dc08860 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -546,6 +546,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] + #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] pub fn compare_exchange( &self, @@ -599,6 +600,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] + #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] pub fn compare_exchange_weak( &self, From 427996a2868ec958dc1a5bee564fb8f377241255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sun, 22 Nov 2020 20:26:36 +0100 Subject: [PATCH 486/719] Fix documentation typo --- library/std/src/sync/once.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 9a17d121db19..6a330834489d 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -110,7 +110,7 @@ use crate::thread::{self, Thread}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Once { - // `state_and_queue` is actually an a pointer to a `Waiter` with extra state + // `state_and_queue` is actually a pointer to a `Waiter` with extra state // bits, so we add the `PhantomData` appropriately. state_and_queue: AtomicUsize, _marker: marker::PhantomData<*const Waiter>, From 3eef20ffa0887a88a15c29eb17de5e20a5c99363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sun, 22 Nov 2020 20:36:29 +0100 Subject: [PATCH 487/719] Improve documentation on `success` and `failure` arguments --- library/core/src/sync/atomic.rs | 42 +++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 668b0dc08860..36857979af8c 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -514,9 +514,10 @@ impl AtomicBool { /// the previous value. On success this value is guaranteed to be equal to `current`. /// /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. Using [`Acquire`] as success ordering makes the store part + /// ordering of this operation. `success` describes the required ordering for the + /// read-modify-write operation that takes place if the comparison with `current` succeeds. + /// `failure` describes the required ordering for the load operation that takes place when + /// the comparison fails. Using [`Acquire`] as success ordering makes the store part /// of this operation [`Relaxed`], and using [`Release`] makes the successful load /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] /// and must be equivalent to or weaker than the success ordering. @@ -572,9 +573,10 @@ impl AtomicBool { /// previous value. /// /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. Using [`Acquire`] as success ordering makes the store part + /// ordering of this operation. `success` describes the required ordering for the + /// read-modify-write operation that takes place if the comparison with `current` succeeds. + /// `failure` describes the required ordering for the load operation that takes place when + /// the comparison fails. Using [`Acquire`] as success ordering makes the store part /// of this operation [`Relaxed`], and using [`Release`] makes the successful load /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] /// and must be equivalent to or weaker than the success ordering. @@ -1138,9 +1140,10 @@ impl AtomicPtr { /// the previous value. On success this value is guaranteed to be equal to `current`. /// /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. Using [`Acquire`] as success ordering makes the store part + /// ordering of this operation. `success` describes the required ordering for the + /// read-modify-write operation that takes place if the comparison with `current` succeeds. + /// `failure` describes the required ordering for the load operation that takes place when + /// the comparison fails. Using [`Acquire`] as success ordering makes the store part /// of this operation [`Relaxed`], and using [`Release`] makes the successful load /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] /// and must be equivalent to or weaker than the success ordering. @@ -1201,9 +1204,10 @@ impl AtomicPtr { /// previous value. /// /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. Using [`Acquire`] as success ordering makes the store part + /// ordering of this operation. `success` describes the required ordering for the + /// read-modify-write operation that takes place if the comparison with `current` succeeds. + /// `failure` describes the required ordering for the load operation that takes place when + /// the comparison fails. Using [`Acquire`] as success ordering makes the store part /// of this operation [`Relaxed`], and using [`Release`] makes the successful load /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] /// and must be equivalent to or weaker than the success ordering. @@ -1708,9 +1712,10 @@ containing the previous value. On success this value is guaranteed to be equal t `current`. `compare_exchange` takes two [`Ordering`] arguments to describe the memory -ordering of this operation. The first describes the required ordering if the -operation succeeds while the second describes the required ordering when the -operation fails. Using [`Acquire`] as success ordering makes the store part +ordering of this operation. `success` describes the required ordering for the +read-modify-write operation that takes place if the comparison with `current` succeeds. +`failure` describes the required ordering for the load operation that takes place when +the comparison fails. Using [`Acquire`] as success ordering makes the store part of this operation [`Relaxed`], and using [`Release`] makes the successful load [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the success ordering. @@ -1760,9 +1765,10 @@ platforms. The return value is a result indicating whether the new value was written and containing the previous value. `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory -ordering of this operation. The first describes the required ordering if the -operation succeeds while the second describes the required ordering when the -operation fails. Using [`Acquire`] as success ordering makes the store part +ordering of this operation. `success` describes the required ordering for the +read-modify-write operation that takes place if the comparison with `current` succeeds. +`failure` describes the required ordering for the load operation that takes place when +the comparison fails. Using [`Acquire`] as success ordering makes the store part of this operation [`Relaxed`], and using [`Release`] makes the successful load [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the success ordering. From 865e4797df83a702982186bbbd6bc70268cd2664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Tue, 22 Dec 2020 12:24:17 +0100 Subject: [PATCH 488/719] Fix compare_and_swap in Windows thread_parker --- library/std/src/sys/windows/thread_parker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index 701c6e2e9bec..e3585d4cb37a 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -113,7 +113,7 @@ impl Parker { // Wait for something to happen, assuming it's still set to PARKED. c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE); // Change NOTIFIED=>EMPTY but leave PARKED alone. - if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED { + if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire) == NOTIFIED { // Actually woken up by unpark(). return; } else { From 454f3ed9029dc407b59b714cb60c00036a253a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Tue, 22 Dec 2020 12:33:11 +0100 Subject: [PATCH 489/719] Update library/std/src/sys/windows/thread_parker.rs Co-authored-by: Mara Bos --- library/std/src/sys/windows/thread_parker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index e3585d4cb37a..9e4c9aa0a512 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -113,7 +113,7 @@ impl Parker { // Wait for something to happen, assuming it's still set to PARKED. c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE); // Change NOTIFIED=>EMPTY but leave PARKED alone. - if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire) == NOTIFIED { + if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() { // Actually woken up by unpark(). return; } else { From 7524eb2704b025a6b36bcc280ce2a81bdb782699 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Dec 2020 12:49:59 +0100 Subject: [PATCH 490/719] update a seemingly outdated comment --- library/std/src/panicking.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 31c215a52a2e..7f4b739cbf87 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -44,9 +44,8 @@ use realstd::io::set_output_capture; extern "C" { fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); - /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings. - /// It cannot be `Box` because the other end of this call does not depend - /// on liballoc, and thus cannot use `Box`. + /// `payload` is actually a `Box`, but we pass this by-reference because the other + /// end of this call does not depend on liballoc, and thus cannot use `Box`. #[unwind(allowed)] fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32; } From 9414f0b833734c344e795d590e9a845ce437c908 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 19 Dec 2020 16:29:38 -0500 Subject: [PATCH 491/719] Revert "Remove missing_fragment_specifier lint" This reverts commit 5ba961018c482e050af908de60e4f8bd1a00f0ae. --- compiler/rustc_lint_defs/src/builtin.rs | 17 +++++++++++++++++ .../rustc/src/lints/listing/deny-by-default.md | 3 --- 2 files changed, 17 insertions(+), 3 deletions(-) delete mode 100644 src/doc/rustc/src/lints/listing/deny-by-default.md diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 6a48b8f4dfbb..de5253a84cc0 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1227,6 +1227,22 @@ declare_lint! { }; } +declare_lint! { + /// The missing_fragment_specifier warning is issued when an unused pattern in a + /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not + /// followed by a fragment specifier (e.g. `:expr`). + /// + /// This warning can always be fixed by removing the unused pattern in the + /// `macro_rules!` macro definition. + pub MISSING_FRAGMENT_SPECIFIER, + Deny, + "detects missing fragment specifiers in unused `macro_rules!` patterns", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #40107 ", + edition: None, + }; +} + declare_lint! { /// The `late_bound_lifetime_arguments` lint detects generic lifetime /// arguments in path segments with late bound lifetime parameters. @@ -2827,6 +2843,7 @@ declare_lint_pass! { CONST_ITEM_MUTATION, SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, + MISSING_FRAGMENT_SPECIFIER, LATE_BOUND_LIFETIME_ARGUMENTS, ORDER_DEPENDENT_TRAIT_OBJECTS, COHERENCE_LEAK_CHECK, diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md deleted file mode 100644 index 3c1452d64676..000000000000 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ /dev/null @@ -1,3 +0,0 @@ -# Deny-by-default lints - -This file is auto-generated by the lint-docs script. From f1eb88b28a84b0533ddd036a60bb5b8acbffabb2 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 19 Dec 2020 16:30:56 -0500 Subject: [PATCH 492/719] Revert "Promote missing_fragment_specifier to hard error" This reverts commit 02eae432e7476a0686633a8c2b7cb1d5aab1bd2c. --- compiler/rustc_expand/src/mbe.rs | 2 +- compiler/rustc_expand/src/mbe/macro_parser.rs | 20 ++++++++++++++--- compiler/rustc_expand/src/mbe/macro_rules.rs | 15 +++++++------ compiler/rustc_expand/src/mbe/quoted.rs | 11 ++++++---- compiler/rustc_interface/src/passes.rs | 19 +++++++++++++++- compiler/rustc_session/src/parse.rs | 2 ++ src/test/ui/lint/expansion-time.rs | 4 ++++ src/test/ui/lint/expansion-time.stderr | 22 +++++++++++++++---- src/test/ui/macros/issue-39404.rs | 1 + src/test/ui/macros/issue-39404.stderr | 4 ++++ src/test/ui/macros/macro-match-nonterminal.rs | 1 + .../ui/macros/macro-match-nonterminal.stderr | 4 ++++ src/test/ui/parser/macro/issue-33569.rs | 1 - src/test/ui/parser/macro/issue-33569.stderr | 16 +++++--------- 14 files changed, 90 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs index eb4aab116f00..cbc4d14a65a1 100644 --- a/compiler/rustc_expand/src/mbe.rs +++ b/compiler/rustc_expand/src/mbe.rs @@ -84,7 +84,7 @@ enum TokenTree { /// e.g., `$var` MetaVar(Span, Ident), /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros. - MetaVarDecl(Span, Ident /* name to bind */, NonterminalKind), + MetaVarDecl(Span, Ident /* name to bind */, Option), } impl TokenTree { diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 3cf2d8f8ac1e..0c44f5fe9e10 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -378,6 +378,11 @@ fn nameize>( n_rec(sess, next_m, res.by_ref(), ret_val)?; } } + TokenTree::MetaVarDecl(span, _, None) => { + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { + return Err((span, "missing fragment specifier".to_string())); + } + } TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val .entry(MacroRulesNormalizedIdent::new(bind_name)) { @@ -446,6 +451,7 @@ fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode { /// /// A `ParseResult`. Note that matches are kept track of through the items generated. fn inner_parse_loop<'root, 'tt>( + sess: &ParseSess, cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, next_items: &mut Vec>, eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, @@ -563,9 +569,16 @@ fn inner_parse_loop<'root, 'tt>( }))); } + // We need to match a metavar (but the identifier is invalid)... this is an error + TokenTree::MetaVarDecl(span, _, None) => { + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { + return Error(span, "missing fragment specifier".to_string()); + } + } + // We need to match a metavar with a valid ident... call out to the black-box // parser by adding an item to `bb_items`. - TokenTree::MetaVarDecl(span, _, kind) => { + TokenTree::MetaVarDecl(span, _, Some(kind)) => { // Built-in nonterminals never start with these tokens, so we can eliminate // them from consideration. // @@ -640,6 +653,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na // parsing from the black-box parser done. The result is that `next_items` will contain a // bunch of possible next matcher positions in `next_items`. match inner_parse_loop( + parser.sess, &mut cur_items, &mut next_items, &mut eof_items, @@ -701,7 +715,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na let nts = bb_items .iter() .map(|item| match item.top_elts.get_tt(item.idx) { - TokenTree::MetaVarDecl(_, bind, kind) => format!("{} ('{}')", kind, bind), + TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind), _ => panic!(), }) .collect::>() @@ -731,7 +745,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na assert_eq!(bb_items.len(), 1); let mut item = bb_items.pop().unwrap(); - if let TokenTree::MetaVarDecl(span, _, kind) = item.top_elts.get_tt(item.idx) { + if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) { let match_cur = item.match_cur; // We use the span of the metavariable declaration to determine any // edition-specific matching behavior for non-terminals. diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 66463eeb9071..89d375b257da 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -401,7 +401,7 @@ pub fn compile_declarative_macro( let diag = &sess.parse_sess.span_diagnostic; let lhs_nm = Ident::new(sym::lhs, def.span); let rhs_nm = Ident::new(sym::rhs, def.span); - let tt_spec = NonterminalKind::TT; + let tt_spec = Some(NonterminalKind::TT); // Parse the macro_rules! invocation let (macro_rules, body) = match &def.kind { @@ -578,7 +578,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { TokenTree::Sequence(span, ref seq) => { if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| match *seq_tt { - TokenTree::MetaVarDecl(_, _, NonterminalKind::Vis) => true, + TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true, TokenTree::Sequence(_, ref sub_seq) => { sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne @@ -961,7 +961,7 @@ fn check_matcher_core( // Now `last` holds the complete set of NT tokens that could // end the sequence before SUFFIX. Check that every one works with `suffix`. for token in &last.tokens { - if let TokenTree::MetaVarDecl(_, name, kind) = *token { + if let TokenTree::MetaVarDecl(_, name, Some(kind)) = *token { for next_token in &suffix_first.tokens { match is_in_follow(next_token, kind) { IsInFollow::Yes => {} @@ -1019,7 +1019,7 @@ fn check_matcher_core( } fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool { - if let mbe::TokenTree::MetaVarDecl(_, _, kind) = *tok { + if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok { frag_can_be_followed_by_any(kind) } else { // (Non NT's can always be followed by anything in matchers.) @@ -1123,7 +1123,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } _ => IsInFollow::No(TOKENS), }, - TokenTree::MetaVarDecl(_, _, NonterminalKind::Block) => IsInFollow::Yes, + TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } } @@ -1158,7 +1158,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { TokenTree::MetaVarDecl( _, _, - NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path, + Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path), ) => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } @@ -1171,7 +1171,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { match *tt { mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token), mbe::TokenTree::MetaVar(_, name) => format!("${}", name), - mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind), + mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind), + mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name), _ => panic!( "{}", "unexpected mbe::TokenTree::{Sequence or Delimited} \ diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 48db532c78f3..01b11bb979d6 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -3,7 +3,7 @@ use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream; -use rustc_ast::NodeId; +use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, Ident}; @@ -73,7 +73,7 @@ pub(super) fn parse( .emit(); token::NonterminalKind::Ident }); - result.push(TokenTree::MetaVarDecl(span, ident, kind)); + result.push(TokenTree::MetaVarDecl(span, ident, Some(kind))); continue; } _ => token.span, @@ -83,8 +83,11 @@ pub(super) fn parse( } tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), }; - sess.span_diagnostic.struct_span_err(span, "missing fragment specifier").emit(); - continue; + if node_id != DUMMY_NODE_ID { + // Macros loaded from other crates have dummy node ids. + sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id); + } + result.push(TokenTree::MetaVarDecl(span, ident, None)); } // Not a metavar or no matchers allowed, so just return the tree diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c13d26c79d73..a8c8690b9e7f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -29,6 +29,7 @@ use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}; +use rustc_session::lint; use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; use rustc_session::Session; @@ -306,11 +307,27 @@ fn configure_and_expand_inner<'a>( ecx.check_unused_macros(); }); + let mut missing_fragment_specifiers: Vec<_> = ecx + .sess + .parse_sess + .missing_fragment_specifiers + .borrow() + .iter() + .map(|(span, node_id)| (*span, *node_id)) + .collect(); + missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span); + + let recursion_limit_hit = ecx.reduced_recursion_limit.is_some(); + + for (span, node_id) in missing_fragment_specifiers { + let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; + let msg = "missing fragment specifier"; + resolver.lint_buffer().buffer_lint(lint, node_id, span, msg); + } if cfg!(windows) { env::set_var("PATH", &old_path); } - let recursion_limit_hit = ecx.reduced_recursion_limit.is_some(); if recursion_limit_hit { // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed // with a large AST diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 66c3738fb5b5..b1a483424173 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -119,6 +119,7 @@ pub struct ParseSess { pub unstable_features: UnstableFeatures, pub config: CrateConfig, pub edition: Edition, + pub missing_fragment_specifiers: Lock>, /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. pub raw_identifier_spans: Lock>, /// Used to determine and report recursive module inclusions. @@ -152,6 +153,7 @@ impl ParseSess { unstable_features: UnstableFeatures::from_environment(None), config: FxHashSet::default(), edition: ExpnId::root().expn_data().edition, + missing_fragment_specifiers: Default::default(), raw_identifier_spans: Lock::new(Vec::new()), included_mod_stack: Lock::new(vec![]), source_map, diff --git a/src/test/ui/lint/expansion-time.rs b/src/test/ui/lint/expansion-time.rs index a9c7ac363b0b..f23c7cb0dca1 100644 --- a/src/test/ui/lint/expansion-time.rs +++ b/src/test/ui/lint/expansion-time.rs @@ -5,6 +5,10 @@ macro_rules! foo { ( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator } +#[warn(missing_fragment_specifier)] +macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier + //~| WARN this was previously accepted + #[warn(soft_unstable)] mod benches { #[bench] //~ WARN use of unstable library feature 'test' diff --git a/src/test/ui/lint/expansion-time.stderr b/src/test/ui/lint/expansion-time.stderr index 24e2733064e4..b0fc1f8e5eec 100644 --- a/src/test/ui/lint/expansion-time.stderr +++ b/src/test/ui/lint/expansion-time.stderr @@ -12,14 +12,28 @@ note: the lint level is defined here LL | #[warn(meta_variable_misuse)] | ^^^^^^^^^^^^^^^^^^^^ +warning: missing fragment specifier + --> $DIR/expansion-time.rs:9:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | +note: the lint level is defined here + --> $DIR/expansion-time.rs:8:8 + | +LL | #[warn(missing_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 + warning: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable - --> $DIR/expansion-time.rs:10:7 + --> $DIR/expansion-time.rs:14:7 | LL | #[bench] | ^^^^^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:8:8 + --> $DIR/expansion-time.rs:12:8 | LL | #[warn(soft_unstable)] | ^^^^^^^^^^^^^ @@ -33,10 +47,10 @@ LL | 2 | ^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:25:8 + --> $DIR/expansion-time.rs:29:8 | LL | #[warn(incomplete_include)] | ^^^^^^^^^^^^^^^^^^ -warning: 3 warnings emitted +warning: 4 warnings emitted diff --git a/src/test/ui/macros/issue-39404.rs b/src/test/ui/macros/issue-39404.rs index 054958ba00b8..2229f2c3900c 100644 --- a/src/test/ui/macros/issue-39404.rs +++ b/src/test/ui/macros/issue-39404.rs @@ -2,5 +2,6 @@ macro_rules! m { ($i) => {} } //~^ ERROR missing fragment specifier +//~| WARN previously accepted fn main() {} diff --git a/src/test/ui/macros/issue-39404.stderr b/src/test/ui/macros/issue-39404.stderr index 645f06e59d81..d2f2a823c2a6 100644 --- a/src/test/ui/macros/issue-39404.stderr +++ b/src/test/ui/macros/issue-39404.stderr @@ -3,6 +3,10 @@ error: missing fragment specifier | LL | macro_rules! m { ($i) => {} } | ^^ + | + = note: `#[deny(missing_fragment_specifier)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 error: aborting due to previous error diff --git a/src/test/ui/macros/macro-match-nonterminal.rs b/src/test/ui/macros/macro-match-nonterminal.rs index 6b023e413727..b23e5c71c03f 100644 --- a/src/test/ui/macros/macro-match-nonterminal.rs +++ b/src/test/ui/macros/macro-match-nonterminal.rs @@ -2,6 +2,7 @@ macro_rules! test { ($a, $b) => { //~^ ERROR missing fragment //~| ERROR missing fragment + //~| WARN this was previously accepted () }; } diff --git a/src/test/ui/macros/macro-match-nonterminal.stderr b/src/test/ui/macros/macro-match-nonterminal.stderr index 334d62812cda..674ce3434aac 100644 --- a/src/test/ui/macros/macro-match-nonterminal.stderr +++ b/src/test/ui/macros/macro-match-nonterminal.stderr @@ -9,6 +9,10 @@ error: missing fragment specifier | LL | ($a, $b) => { | ^^ + | + = note: `#[deny(missing_fragment_specifier)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/macro/issue-33569.rs b/src/test/ui/parser/macro/issue-33569.rs index cf81f0480a2a..80e2d7c6545b 100644 --- a/src/test/ui/parser/macro/issue-33569.rs +++ b/src/test/ui/parser/macro/issue-33569.rs @@ -2,7 +2,6 @@ macro_rules! foo { { $+ } => { //~ ERROR expected identifier, found `+` //~^ ERROR missing fragment specifier $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?` - //~^ ERROR attempted to repeat an expression containing no syntax variables } } diff --git a/src/test/ui/parser/macro/issue-33569.stderr b/src/test/ui/parser/macro/issue-33569.stderr index f54efaa6996f..b4d38d3ce480 100644 --- a/src/test/ui/parser/macro/issue-33569.stderr +++ b/src/test/ui/parser/macro/issue-33569.stderr @@ -4,23 +4,17 @@ error: expected identifier, found `+` LL | { $+ } => { | ^ -error: missing fragment specifier - --> $DIR/issue-33569.rs:2:8 - | -LL | { $+ } => { - | ^ - error: expected one of: `*`, `+`, or `?` --> $DIR/issue-33569.rs:4:13 | LL | $(x)(y) | ^^^ -error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth - --> $DIR/issue-33569.rs:4:10 +error: missing fragment specifier + --> $DIR/issue-33569.rs:2:8 | -LL | $(x)(y) - | ^^^ +LL | { $+ } => { + | ^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 56154a11473da93da0f5d57f4692991ae4972695 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 20 Dec 2020 21:44:27 -0500 Subject: [PATCH 493/719] Add example to lint docs --- compiler/rustc_lint_defs/src/builtin.rs | 30 ++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index de5253a84cc0..1c692d4f2076 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1228,12 +1228,40 @@ declare_lint! { } declare_lint! { - /// The missing_fragment_specifier warning is issued when an unused pattern in a + /// The `missing_fragment_specifier` lint is issued when an unused pattern in a /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not /// followed by a fragment specifier (e.g. `:expr`). /// /// This warning can always be fixed by removing the unused pattern in the /// `macro_rules!` macro definition. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// macro_rules! foo { + /// () => {}; + /// ($name) => { }; + /// } + /// + /// fn main() { + /// foo!(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To fix this, remove the unused pattern from the `macro_rules!` macro definition: + /// + /// ```rust + /// macro_rules! foo { + /// () => {}; + /// } + /// fn main() { + /// foo!(); + /// } + /// ``` pub MISSING_FRAGMENT_SPECIFIER, Deny, "detects missing fragment specifiers in unused `macro_rules!` patterns", From 9cd992f394de0ba9d7990c0159bea8855329e6b0 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 22 Dec 2020 09:54:23 -0500 Subject: [PATCH 494/719] Add some intra-doc links to compiler docs --- compiler/rustc_builtin_macros/src/deriving/generic/mod.rs | 5 ++++- compiler/rustc_interface/src/interface.rs | 3 ++- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_interface/src/queries.rs | 6 +++++- compiler/rustc_span/src/symbol.rs | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 68c11868af88..6531e68be9cd 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -257,7 +257,10 @@ pub struct Substructure<'a> { pub type_ident: Ident, /// ident of the method pub method_ident: Ident, - /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments + /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)][ptr]` arguments + /// + /// [`Self_`]: ty::Ty::Self_ + /// [ptr]: ty::Ty::Ptr pub self_args: &'a [P], /// verbatim access to any other arguments pub nonself_args: &'a [P], diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index acd49d86c2c8..28eb1fed6a0a 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -25,8 +25,9 @@ use std::sync::{Arc, Mutex}; pub type Result = result::Result; /// Represents a compiler session. +/// /// Can be used to run `rustc_interface` queries. -/// Created by passing `Config` to `run_compiler`. +/// Created by passing [`Config`] to [`run_compiler`]. pub struct Compiler { pub(crate) sess: Lrc, codegen_backend: Lrc>, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c13d26c79d73..3398da024c98 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -95,7 +95,7 @@ declare_box_region_type!( /// harness if one is to be provided, injection of a dependency on the /// standard library and prelude, and name resolution. /// -/// Returns `None` if we're aborting after handling -W help. +/// Returns [`None`] if we're aborting after handling -W help. pub fn configure_and_expand( sess: Lrc, lint_store: Lrc, diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 4c340b3fc1f5..6ea0828cea0d 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -23,7 +23,11 @@ use std::cell::{Ref, RefCell, RefMut}; use std::rc::Rc; /// Represent the result of a query. -/// This result can be stolen with the `take` method and generated with the `compute` method. +/// +/// This result can be stolen with the [`take`] method and generated with the [`compute`] method. +/// +/// [`take`]: Self::take +/// [`compute`]: Self::compute pub struct Query { result: RefCell>>, } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4d14763825ca..1af7fa81cbb4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1681,7 +1681,7 @@ fn with_interner T>(f: F) -> T { SESSION_GLOBALS.with(|session_globals| f(&mut *session_globals.symbol_interner.lock())) } -/// An alternative to `Symbol`, useful when the chars within the symbol need to +/// An alternative to [`Symbol`], useful when the chars within the symbol need to /// be accessed. It deliberately has limited functionality and should only be /// used for temporary values. /// From 64afdedfb87d471dcf1b757cea5f4b0b570176c1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 20 Dec 2020 23:37:24 +0100 Subject: [PATCH 495/719] Rework beautify_doc_string so that it returns a Symbol instead of a String --- compiler/rustc_ast/src/util/comments.rs | 58 ++++++++++--------- compiler/rustc_ast/src/util/comments/tests.rs | 14 ++--- compiler/rustc_save_analysis/src/lib.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index e97c8cc4562f..5d994c903795 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -25,9 +25,8 @@ pub struct Comment { /// Makes a doc string more presentable to users. /// Used by rustdoc and perhaps other tools, but not by rustc. -pub fn beautify_doc_string(data: Symbol) -> String { - /// remove whitespace-only lines from the start/end of lines - fn vertical_trim(lines: Vec) -> Vec { +pub fn beautify_doc_string(data: Symbol) -> Symbol { + fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> { let mut i = 0; let mut j = lines.len(); // first line of all-stars should be omitted @@ -47,55 +46,58 @@ pub fn beautify_doc_string(data: Symbol) -> String { j -= 1; } - lines[i..j].to_vec() + if i != 0 || j != lines.len() { Some((i, j)) } else { None } } - /// remove a "[ \t]*\*" block from each line, if possible - fn horizontal_trim(lines: Vec) -> Vec { + fn get_horizontal_trim(lines: &[&str]) -> Option { let mut i = usize::MAX; - let mut can_trim = true; let mut first = true; - for line in &lines { + for line in lines { for (j, c) in line.chars().enumerate() { if j > i || !"* \t".contains(c) { - can_trim = false; - break; + return None; } if c == '*' { if first { i = j; first = false; } else if i != j { - can_trim = false; + return None; } break; } } if i >= line.len() { - can_trim = false; - } - if !can_trim { - break; + return None; } } + Some(i) + } - if can_trim { - lines.iter().map(|line| (&line[i + 1..line.len()]).to_string()).collect() + let data_s = data.as_str(); + if data_s.contains('\n') { + let mut lines = data_s.lines().collect::>(); + let mut changes = false; + let lines = if let Some((i, j)) = get_vertical_trim(&lines) { + changes = true; + // remove whitespace-only lines from the start/end of lines + &mut lines[i..j] } else { - lines + &mut lines + }; + if let Some(horizontal) = get_horizontal_trim(&lines) { + changes = true; + // remove a "[ \t]*\*" block from each line, if possible + for line in lines.iter_mut() { + *line = &line[horizontal + 1..]; + } + } + if changes { + return Symbol::intern(&lines.join("\n")); } } - - let data = data.as_str(); - if data.contains('\n') { - let lines = data.lines().map(|s| s.to_string()).collect::>(); - let lines = vertical_trim(lines); - let lines = horizontal_trim(lines); - lines.join("\n") - } else { - data.to_string() - } + data } /// Returns `None` if the first `col` chars of `s` contain a non-whitespace char. diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs index e19198f863ba..98ab653e45f7 100644 --- a/compiler/rustc_ast/src/util/comments/tests.rs +++ b/compiler/rustc_ast/src/util/comments/tests.rs @@ -6,7 +6,7 @@ fn test_block_doc_comment_1() { with_default_session_globals(|| { let comment = "\n * Test \n ** Test\n * Test\n"; let stripped = beautify_doc_string(Symbol::intern(comment)); - assert_eq!(stripped, " Test \n* Test\n Test"); + assert_eq!(stripped.as_str(), " Test \n* Test\n Test"); }) } @@ -15,7 +15,7 @@ fn test_block_doc_comment_2() { with_default_session_globals(|| { let comment = "\n * Test\n * Test\n"; let stripped = beautify_doc_string(Symbol::intern(comment)); - assert_eq!(stripped, " Test\n Test"); + assert_eq!(stripped.as_str(), " Test\n Test"); }) } @@ -24,7 +24,7 @@ fn test_block_doc_comment_3() { with_default_session_globals(|| { let comment = "\n let a: *i32;\n *a = 5;\n"; let stripped = beautify_doc_string(Symbol::intern(comment)); - assert_eq!(stripped, " let a: *i32;\n *a = 5;"); + assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;"); }) } @@ -32,12 +32,12 @@ fn test_block_doc_comment_3() { fn test_line_doc_comment() { with_default_session_globals(|| { let stripped = beautify_doc_string(Symbol::intern(" test")); - assert_eq!(stripped, " test"); + assert_eq!(stripped.as_str(), " test"); let stripped = beautify_doc_string(Symbol::intern("! test")); - assert_eq!(stripped, "! test"); + assert_eq!(stripped.as_str(), "! test"); let stripped = beautify_doc_string(Symbol::intern("test")); - assert_eq!(stripped, "test"); + assert_eq!(stripped.as_str(), "test"); let stripped = beautify_doc_string(Symbol::intern("!test")); - assert_eq!(stripped, "!test"); + assert_eq!(stripped.as_str(), "!test"); }) } diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index eed9f2eb74d4..056c0b3d9d51 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -825,7 +825,7 @@ impl<'tcx> SaveContext<'tcx> { for attr in attrs { if let Some(val) = attr.doc_str() { // FIXME: Should save-analysis beautify doc strings itself or leave it to users? - result.push_str(&beautify_doc_string(val)); + result.push_str(&beautify_doc_string(val).as_str()); result.push('\n'); } else if self.tcx.sess.check_name(attr, sym::doc) { if let Some(meta_list) = attr.meta_item_list() { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index cd6eccea5321..632aad75c26c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -617,7 +617,7 @@ impl Attributes { let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| { if let Some(value) = attr.doc_str() { trace!("got doc_str={:?}", value); - let value = beautify_doc_string(value); + let value = beautify_doc_string(value).to_string(); let kind = if attr.is_doc_comment() { DocFragmentKind::SugaredDoc } else { From ef75761fb1aa5ce04954349a85e89b8cffbf5c42 Mon Sep 17 00:00:00 2001 From: LingMan Date: Tue, 22 Dec 2020 16:18:34 +0100 Subject: [PATCH 496/719] Turn helper method into a closure `replace_prefix` is currently implemented as a method but has no real relation to the struct it is implemented on. Turn it into a closure and move it into the only method from which it is called. --- compiler/rustc_typeck/src/check/demand.rs | 40 +++++++++++++---------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index aa4d57f7e1d9..2728e03171a7 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -360,10 +360,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn replace_prefix(&self, s: &str, old: &str, new: &str) -> Option { - s.strip_prefix(old).map(|stripped| new.to_string() + stripped) - } - /// This function is used to determine potential "simple" improvements or users' errors and /// provide them useful help. For example: /// @@ -394,6 +390,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } + let replace_prefix = |s: &str, old: &str, new: &str| { + s.strip_prefix(old).map(|stripped| new.to_string() + stripped) + }; + let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp); @@ -409,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(&src, "b\"", "\"") { + if let Some(src) = replace_prefix(&src, "b\"", "\"") { return Some(( sp, "consider removing the leading `b`", @@ -423,7 +423,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(&src, "\"", "b\"") { + if let Some(src) = replace_prefix(&src, "\"", "b\"") { return Some(( sp, "consider adding a leading `b`", @@ -583,23 +583,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Mutability::Mut => { let new_prefix = "&mut ".to_owned() + derefs; match mutbl_a { - hir::Mutability::Mut => self - .replace_prefix(&src, "&mut ", &new_prefix) - .map(|s| (s, Applicability::MachineApplicable)), - hir::Mutability::Not => self - .replace_prefix(&src, "&", &new_prefix) - .map(|s| (s, Applicability::Unspecified)), + hir::Mutability::Mut => { + replace_prefix(&src, "&mut ", &new_prefix) + .map(|s| (s, Applicability::MachineApplicable)) + } + hir::Mutability::Not => { + replace_prefix(&src, "&", &new_prefix) + .map(|s| (s, Applicability::Unspecified)) + } } } hir::Mutability::Not => { let new_prefix = "&".to_owned() + derefs; match mutbl_a { - hir::Mutability::Mut => self - .replace_prefix(&src, "&mut ", &new_prefix) - .map(|s| (s, Applicability::MachineApplicable)), - hir::Mutability::Not => self - .replace_prefix(&src, "&", &new_prefix) - .map(|s| (s, Applicability::MachineApplicable)), + hir::Mutability::Mut => { + replace_prefix(&src, "&mut ", &new_prefix) + .map(|s| (s, Applicability::MachineApplicable)) + } + hir::Mutability::Not => { + replace_prefix(&src, "&", &new_prefix) + .map(|s| (s, Applicability::MachineApplicable)) + } } } } { From 42b77c709e98f8f75498e1b57eac20756f6c6ead Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 14 Nov 2020 21:50:53 +0000 Subject: [PATCH 497/719] Add some tests --- .../ui/pattern/usefulness/consts-opaque.rs | 39 ++++++++++-- .../pattern/usefulness/consts-opaque.stderr | 60 +++++++++++-------- 2 files changed, 71 insertions(+), 28 deletions(-) diff --git a/src/test/ui/pattern/usefulness/consts-opaque.rs b/src/test/ui/pattern/usefulness/consts-opaque.rs index f87f96e34fcc..ca4fcd85bb6d 100644 --- a/src/test/ui/pattern/usefulness/consts-opaque.rs +++ b/src/test/ui/pattern/usefulness/consts-opaque.rs @@ -25,10 +25,6 @@ enum Baz { impl Eq for Baz {} const BAZ: Baz = Baz::Baz1; -type Quux = fn(usize, usize) -> usize; -fn quux(a: usize, b: usize) -> usize { a + b } -const QUUX: Quux = quux; - fn main() { match FOO { FOO => {} @@ -106,9 +102,44 @@ fn main() { //~^ ERROR unreachable pattern } + type Quux = fn(usize, usize) -> usize; + fn quux(a: usize, b: usize) -> usize { a + b } + const QUUX: Quux = quux; + match QUUX { QUUX => {} QUUX => {} _ => {} } + + #[derive(PartialEq, Eq)] + struct Wrap(T); + const WRAPQUUX: Wrap = Wrap(quux); + + match WRAPQUUX { + WRAPQUUX => {} + WRAPQUUX => {} + Wrap(_) => {} + } + + match WRAPQUUX { + Wrap(_) => {} + WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer + //~^ ERROR unreachable pattern + } + + #[derive(PartialEq, Eq)] + enum WhoKnows { + Yay(T), + Nope, + }; + const WHOKNOWSQUUX: WhoKnows = WhoKnows::Yay(quux); + + match WHOKNOWSQUUX { + WHOKNOWSQUUX => {} + WhoKnows::Yay(_) => {} + WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer + //~^ ERROR unreachable pattern + WhoKnows::Nope => {} + } } diff --git a/src/test/ui/pattern/usefulness/consts-opaque.stderr b/src/test/ui/pattern/usefulness/consts-opaque.stderr index f10166d5a358..68451043cf54 100644 --- a/src/test/ui/pattern/usefulness/consts-opaque.stderr +++ b/src/test/ui/pattern/usefulness/consts-opaque.stderr @@ -1,11 +1,11 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:34:9 + --> $DIR/consts-opaque.rs:30:9 | LL | FOO => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:36:9 + --> $DIR/consts-opaque.rs:32:9 | LL | _ => {} // should not be emitting unreachable warning | ^ @@ -17,19 +17,19 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:41:9 + --> $DIR/consts-opaque.rs:37:9 | LL | FOO_REF => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:43:9 + --> $DIR/consts-opaque.rs:39:9 | LL | Foo(_) => {} // should not be emitting unreachable warning | ^^^^^^ warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:49:9 + --> $DIR/consts-opaque.rs:45:9 | LL | FOO_REF_REF => {} | ^^^^^^^^^^^ @@ -39,13 +39,13 @@ LL | FOO_REF_REF => {} = note: for more information, see issue #62411 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:57:9 + --> $DIR/consts-opaque.rs:53:9 | LL | BAR => {} // should not be emitting unreachable warning | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:57:9 + --> $DIR/consts-opaque.rs:53:9 | LL | Bar => {} | --- matches any value @@ -53,7 +53,7 @@ LL | BAR => {} // should not be emitting unreachable warning | ^^^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:60:9 + --> $DIR/consts-opaque.rs:56:9 | LL | Bar => {} | --- matches any value @@ -62,19 +62,19 @@ LL | _ => {} | ^ unreachable pattern error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:65:9 + --> $DIR/consts-opaque.rs:61:9 | LL | BAR => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:67:9 + --> $DIR/consts-opaque.rs:63:9 | LL | Bar => {} // should not be emitting unreachable warning | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:69:9 + --> $DIR/consts-opaque.rs:65:9 | LL | Bar => {} // should not be emitting unreachable warning | --- matches any value @@ -83,76 +83,88 @@ LL | _ => {} | ^ unreachable pattern error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:74:9 + --> $DIR/consts-opaque.rs:70:9 | LL | BAR => {} | ^^^ error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:76:9 + --> $DIR/consts-opaque.rs:72:9 | LL | BAR => {} // should not be emitting unreachable warning | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:76:9 + --> $DIR/consts-opaque.rs:72:9 | LL | BAR => {} // should not be emitting unreachable warning | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:79:9 + --> $DIR/consts-opaque.rs:75:9 | LL | _ => {} // should not be emitting unreachable warning | ^ error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:84:9 + --> $DIR/consts-opaque.rs:80:9 | LL | BAZ => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:86:9 + --> $DIR/consts-opaque.rs:82:9 | LL | Baz::Baz1 => {} // should not be emitting unreachable warning | ^^^^^^^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:88:9 + --> $DIR/consts-opaque.rs:84:9 | LL | _ => {} | ^ error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:94:9 + --> $DIR/consts-opaque.rs:90:9 | LL | BAZ => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:96:9 + --> $DIR/consts-opaque.rs:92:9 | LL | _ => {} | ^ error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:101:9 + --> $DIR/consts-opaque.rs:97:9 | LL | BAZ => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:103:9 + --> $DIR/consts-opaque.rs:99:9 | LL | Baz::Baz2 => {} // should not be emitting unreachable warning | ^^^^^^^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:105:9 + --> $DIR/consts-opaque.rs:101:9 | LL | _ => {} // should not be emitting unreachable warning | ^ -error: aborting due to 22 previous errors; 1 warning emitted +error: unreachable pattern + --> $DIR/consts-opaque.rs:127:9 + | +LL | WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:141:9 + | +LL | WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer + | ^^^^^^^^^^^^ + +error: aborting due to 24 previous errors; 1 warning emitted From 5a24b2c2c7b483ef6eae7e46d69cc200cb02575d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 10 Dec 2020 13:52:51 +0000 Subject: [PATCH 498/719] Factor out `SplitIntRange` used for integer range splitting --- .../src/thir/pattern/deconstruct_pat.rs | 199 ++++++++++-------- 1 file changed, 110 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index dd0c61a2882f..a6cf0ebeb82e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -24,7 +24,7 @@ use rustc_target::abi::{Integer, Size, VariantIdx}; use smallvec::{smallvec, SmallVec}; use std::cmp::{self, max, min, Ordering}; -use std::iter::IntoIterator; +use std::iter::{once, IntoIterator}; use std::ops::RangeInclusive; /// An inclusive interval, used for precise integer exhaustiveness checking. @@ -183,77 +183,24 @@ impl IntRange { Pat { ty, span: DUMMY_SP, kind: Box::new(kind) } } - /// For exhaustive integer matching, some constructors are grouped within other constructors - /// (namely integer typed values are grouped within ranges). However, when specialising these - /// constructors, we want to be specialising for the underlying constructors (the integers), not - /// the groups (the ranges). Thus we need to split the groups up. Splitting them up naïvely would - /// mean creating a separate constructor for every single value in the range, which is clearly - /// impractical. However, observe that for some ranges of integers, the specialisation will be - /// identical across all values in that range (i.e., there are equivalence classes of ranges of - /// constructors based on their `U(S(c, P), S(c, p))` outcome). These classes are grouped by - /// the patterns that apply to them (in the matrix `P`). We can split the range whenever the - /// patterns that apply to that range (specifically: the patterns that *intersect* with that range) - /// change. - /// Our solution, therefore, is to split the range constructor into subranges at every single point - /// the group of intersecting patterns changes (using the method described below). - /// And voilà! We're testing precisely those ranges that we need to, without any exhaustive matching - /// on actual integers. The nice thing about this is that the number of subranges is linear in the - /// number of rows in the matrix (i.e., the number of cases in the `match` statement), so we don't - /// need to be worried about matching over gargantuan ranges. - /// - /// Essentially, given the first column of a matrix representing ranges, looking like the following: - /// - /// |------| |----------| |-------| || - /// |-------| |-------| |----| || - /// |---------| - /// - /// We split the ranges up into equivalence classes so the ranges are no longer overlapping: - /// - /// |--|--|||-||||--||---|||-------| |-|||| || - /// - /// The logic for determining how to split the ranges is fairly straightforward: we calculate - /// boundaries for each interval range, sort them, then create constructors for each new interval - /// between every pair of boundary points. (This essentially sums up to performing the intuitive - /// merging operation depicted above.) + /// Split this range, as described at the top of the file. fn split<'p, 'tcx>( &self, pcx: PatCtxt<'_, 'p, 'tcx>, hir_id: Option, ) -> SmallVec<[Constructor<'tcx>; 1]> { - /// Represents a border between 2 integers. Because the intervals spanning borders - /// must be able to cover every integer, we need to be able to represent - /// 2^128 + 1 such borders. - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] - enum Border { - JustBefore(u128), - AfterMax, - } - - // A function for extracting the borders of an integer interval. - fn range_borders(r: IntRange) -> impl Iterator { - let (lo, hi) = r.range.into_inner(); - let from = Border::JustBefore(lo); - let to = match hi.checked_add(1) { - Some(m) => Border::JustBefore(m), - None => Border::AfterMax, - }; - vec![from, to].into_iter() - } - - // Collect the span and range of all the intersecting ranges to lint on likely - // incorrect range patterns. (#63987) + // We collect the span and range of all the intersecting ranges to lint on likely incorrect + // range patterns. (#63987) let mut overlaps = vec![]; + let mut split_range = SplitIntRange::new(self.clone()); let row_len = pcx.matrix.column_count().unwrap_or(0); - // `borders` is the set of borders between equivalence classes: each equivalence - // class lies between 2 borders. - let row_borders = pcx + let intranges = pcx .matrix .head_ctors_and_spans(pcx.cx) - .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))) - .filter_map(|(range, span)| { - let intersection = self.intersection(&range); - let should_lint = self.suspicious_intersection(&range); - if let (Some(range), 1, true) = (&intersection, row_len, should_lint) { + .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))); + let intranges = intranges.inspect(|(range, span)| { + if let Some(intersection) = self.intersection(&range) { + if row_len == 1 && self.suspicious_intersection(&range) { // FIXME: for now, only check for overlapping ranges on simple range // patterns. Otherwise with the current logic the following is detected // as overlapping: @@ -264,36 +211,15 @@ impl IntRange { // _ => {} // } // ``` - overlaps.push((range.clone(), span)); + overlaps.push((intersection.clone(), *span)); } - intersection - }) - .flat_map(range_borders); - let self_borders = range_borders(self.clone()); - let mut borders: Vec<_> = row_borders.chain(self_borders).collect(); - borders.sort_unstable(); + } + }); + split_range.split(intranges.map(|(range, _)| range).cloned()); self.lint_overlapping_range_endpoints(pcx, hir_id, overlaps); - // We're going to iterate through every adjacent pair of borders, making sure that - // each represents an interval of nonnegative length, and convert each such - // interval into a constructor. - borders - .array_windows() - .filter_map(|&pair| match pair { - [Border::JustBefore(n), Border::JustBefore(m)] => { - if n < m { - Some(n..=(m - 1)) - } else { - None - } - } - [Border::JustBefore(n), Border::AfterMax] => Some(n..=u128::MAX), - [Border::AfterMax, _] => None, - }) - .map(|range| IntRange { range }) - .map(IntRange) - .collect() + split_range.iter().map(IntRange).collect() } fn lint_overlapping_range_endpoints( @@ -339,6 +265,101 @@ impl IntRange { } } +/// Represents a border between 2 integers. Because the intervals spanning borders must be able to +/// cover every integer, we need to be able to represent 2^128 + 1 such borders. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +enum IntBorder { + JustBefore(u128), + AfterMax, +} + +/// A range of integers that is partitioned into disjoint subranges. +/// +/// This is fed an input of multiple ranges, and returns an output that covers the union of the +/// inputs but is split so that an output range only intersects an input range by being a subrange +/// of it. No output range straddles the boundary of one of the inputs. This does constructor +/// splitting for integer ranges as explained at the top of the file. +/// +/// The following input: +/// ``` +/// |-------------------------| // `self` +/// |------| |----------| |----| +/// |-------| |-------| +/// ``` +/// would be iterated over as follows: +/// ``` +/// ||---|--||-|---|---|---|--| +/// ``` +#[derive(Debug, Clone)] +struct SplitIntRange { + /// The range we are splitting + range: IntRange, + /// The borders of ranges we have seen. They are all contained within `range`. This is kept + /// sorted. + borders: Vec, +} + +impl SplitIntRange { + fn new(r: IntRange) -> Self { + SplitIntRange { range: r.clone(), borders: Vec::new() } + } + + /// Internal use + fn to_borders(r: IntRange) -> [IntBorder; 2] { + use IntBorder::*; + let (lo, hi) = r.boundaries(); + let lo = JustBefore(lo); + let hi = match hi.checked_add(1) { + Some(m) => JustBefore(m), + None => AfterMax, + }; + [lo, hi] + } + + /// Add ranges relative to which we split. + fn split(&mut self, ranges: impl Iterator) { + let this_range = &self.range; + let included_ranges = ranges.filter_map(|r| this_range.intersection(&r)); + let included_borders = included_ranges.flat_map(|r| { + let borders = Self::to_borders(r); + once(borders[0]).chain(once(borders[1])) + }); + self.borders.extend(included_borders); + self.borders.sort_unstable(); + } + + /// Iterate over the contained ranges. + fn iter<'a>(&'a self) -> impl Iterator + Captures<'a> { + use IntBorder::*; + + let self_range = Self::to_borders(self.range.clone()); + // Start with the start of the range. + let mut prev_border = self_range[0]; + self.borders + .iter() + .copied() + // End with the end of the range. + .chain(once(self_range[1])) + // List pairs of adjacent borders. + .map(move |border| { + let ret = (prev_border, border); + prev_border = border; + ret + }) + // Skip duplicates. + .filter(|(prev_border, border)| prev_border != border) + // Finally, convert to ranges. + .map(|(prev_border, border)| { + let range = match (prev_border, border) { + (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), + (JustBefore(n), AfterMax) => n..=u128::MAX, + _ => unreachable!(), // Ruled out by the sorting and filtering we did + }; + IntRange { range } + }) + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum SliceKind { /// Patterns of length `n` (`[x, y]`). From 7948f919108b43d69debcf7ed57d8944407463dd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 19 Dec 2020 00:37:36 +0000 Subject: [PATCH 499/719] Run the annoying lint separately --- .../src/thir/pattern/deconstruct_pat.rs | 88 ++++++++----------- .../src/thir/pattern/usefulness.rs | 9 +- 2 files changed, 43 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index a6cf0ebeb82e..f4dd7d2dcd64 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::lint; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; use rustc_target::abi::{Integer, Size, VariantIdx}; use smallvec::{smallvec, SmallVec}; @@ -184,51 +184,42 @@ impl IntRange { } /// Split this range, as described at the top of the file. - fn split<'p, 'tcx>( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - hir_id: Option, - ) -> SmallVec<[Constructor<'tcx>; 1]> { - // We collect the span and range of all the intersecting ranges to lint on likely incorrect - // range patterns. (#63987) - let mut overlaps = vec![]; + fn split<'p, 'tcx>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { let mut split_range = SplitIntRange::new(self.clone()); - let row_len = pcx.matrix.column_count().unwrap_or(0); - let intranges = pcx - .matrix - .head_ctors_and_spans(pcx.cx) - .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))); - let intranges = intranges.inspect(|(range, span)| { - if let Some(intersection) = self.intersection(&range) { - if row_len == 1 && self.suspicious_intersection(&range) { - // FIXME: for now, only check for overlapping ranges on simple range - // patterns. Otherwise with the current logic the following is detected - // as overlapping: - // ``` - // match (0u8, true) { - // (0 ..= 125, false) => {} - // (125 ..= 255, true) => {} - // _ => {} - // } - // ``` - overlaps.push((intersection.clone(), *span)); - } - } - }); - split_range.split(intranges.map(|(range, _)| range).cloned()); - - self.lint_overlapping_range_endpoints(pcx, hir_id, overlaps); - + let intranges = pcx.matrix.head_ctors(pcx.cx).filter_map(|ctor| ctor.as_int_range()); + split_range.split(intranges.cloned()); split_range.iter().map(IntRange).collect() } - fn lint_overlapping_range_endpoints( - &self, - pcx: PatCtxt<'_, '_, '_>, - hir_id: Option, - overlaps: Vec<(IntRange, Span)>, - ) { - if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) { + /// Lint on likely incorrect range patterns (#63987) + pub(super) fn lint_overlapping_range_endpoints(&self, pcx: PatCtxt<'_, '_, '_>, hir_id: HirId) { + if self.is_singleton() { + return; + } + + if pcx.matrix.column_count().unwrap_or(0) != 1 { + // FIXME: for now, only check for overlapping ranges on simple range + // patterns. Otherwise with the current logic the following is detected + // as overlapping: + // ``` + // match (0u8, true) { + // (0 ..= 125, false) => {} + // (125 ..= 255, true) => {} + // _ => {} + // } + // ``` + return; + } + + let overlaps: Vec<_> = pcx + .matrix + .head_ctors_and_spans(pcx.cx) + .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))) + .filter(|(range, _)| self.suspicious_intersection(range)) + .map(|(range, span)| (self.intersection(&range).unwrap(), span)) + .collect(); + + if !overlaps.is_empty() { pcx.cx.tcx.struct_span_lint_hir( lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, hir_id, @@ -673,21 +664,14 @@ impl<'tcx> Constructor<'tcx> { /// This function may discard some irrelevant constructors if this preserves behavior and /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the /// matrix, unless all of them are. - /// - /// `hir_id` is `None` when we're evaluating the wildcard pattern. In that case we do not want - /// to lint for overlapping ranges. - pub(super) fn split<'p>( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - hir_id: Option, - ) -> SmallVec<[Self; 1]> { + pub(super) fn split<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> { debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix); match self { Wildcard => Constructor::split_wildcard(pcx), // Fast-track if the range is trivial. In particular, we don't do the overlapping // ranges check. - IntRange(ctor_range) if !ctor_range.is_singleton() => ctor_range.split(pcx, hir_id), + IntRange(ctor_range) if !ctor_range.is_singleton() => ctor_range.split(pcx), Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx), // Any other constructor can be used unchanged. _ => smallvec![self.clone()], @@ -937,7 +921,7 @@ impl<'tcx> MissingConstructors<'tcx> { pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect(); // Since `all_ctors` never contains wildcards, this won't recurse further. let all_ctors = - all_constructors(pcx).into_iter().flat_map(|ctor| ctor.split(pcx, None)).collect(); + all_constructors(pcx).into_iter().flat_map(|ctor| ctor.split(pcx)).collect(); MissingConstructors { all_ctors, used_ctors } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 0ecc034ac0ba..877d48a85b76 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -991,11 +991,16 @@ fn is_useful<'p, 'tcx>( }); Usefulness::merge(usefulnesses) } else { + let v_ctor = v.head_ctor(cx); + if let Constructor::IntRange(ctor_range) = &v_ctor { + // Lint on likely incorrect range patterns (#63987) + ctor_range.lint_overlapping_range_endpoints(pcx, hir_id) + } // We split the head constructor of `v`. - let ctors = v.head_ctor(cx).split(pcx, Some(hir_id)); + let split_ctors = v_ctor.split(pcx); // For each constructor, we compute whether there's a value that starts with it that would // witness the usefulness of `v`. - let usefulnesses = ctors.into_iter().map(|ctor| { + let usefulnesses = split_ctors.into_iter().map(|ctor| { // We cache the result of `Fields::wildcards` because it is used a lot. let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); From 9d0c2ed913efa358c2ce9f17e4753f72c5169dd5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Dec 2020 22:20:14 +0000 Subject: [PATCH 500/719] Factor out `SplitVarLenSlice` used for slice splitting --- .../src/thir/pattern/deconstruct_pat.rs | 236 +++++++++--------- 1 file changed, 124 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index f4dd7d2dcd64..3c6cade1634f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -403,124 +403,17 @@ impl Slice { self.kind.arity() } - /// The exhaustiveness-checking paper does not include any details on - /// checking variable-length slice patterns. However, they may be - /// matched by an infinite collection of fixed-length array patterns. - /// - /// Checking the infinite set directly would take an infinite amount - /// of time. However, it turns out that for each finite set of - /// patterns `P`, all sufficiently large array lengths are equivalent: - /// - /// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies - /// to exactly the subset `Pₜ` of `P` can be transformed to a slice - /// `sₘ` for each sufficiently-large length `m` that applies to exactly - /// the same subset of `P`. - /// - /// Because of that, each witness for reachability-checking of one - /// of the sufficiently-large lengths can be transformed to an - /// equally-valid witness of any other length, so we only have - /// to check slices of the "minimal sufficiently-large length" - /// and less. - /// - /// Note that the fact that there is a *single* `sₘ` for each `m` - /// not depending on the specific pattern in `P` is important: if - /// you look at the pair of patterns - /// `[true, ..]` - /// `[.., false]` - /// Then any slice of length ≥1 that matches one of these two - /// patterns can be trivially turned to a slice of any - /// other length ≥1 that matches them and vice-versa, - /// but the slice of length 2 `[false, true]` that matches neither - /// of these patterns can't be turned to a slice from length 1 that - /// matches neither of these patterns, so we have to consider - /// slices from length 2 there. - /// - /// Now, to see that that length exists and find it, observe that slice - /// patterns are either "fixed-length" patterns (`[_, _, _]`) or - /// "variable-length" patterns (`[_, .., _]`). - /// - /// For fixed-length patterns, all slices with lengths *longer* than - /// the pattern's length have the same outcome (of not matching), so - /// as long as `L` is greater than the pattern's length we can pick - /// any `sₘ` from that length and get the same result. - /// - /// For variable-length patterns, the situation is more complicated, - /// because as seen above the precise value of `sₘ` matters. - /// - /// However, for each variable-length pattern `p` with a prefix of length - /// `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last - /// `slₚ` elements are examined. - /// - /// Therefore, as long as `L` is positive (to avoid concerns about empty - /// types), all elements after the maximum prefix length and before - /// the maximum suffix length are not examined by any variable-length - /// pattern, and therefore can be added/removed without affecting - /// them - creating equivalent patterns from any sufficiently-large - /// length. - /// - /// Of course, if fixed-length patterns exist, we must be sure - /// that our length is large enough to miss them all, so - /// we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))` - /// - /// for example, with the above pair of patterns, all elements - /// but the first and last can be added/removed, so any - /// witness of length ≥2 (say, `[false, false, true]`) can be - /// turned to a witness from any other length ≥2. + /// Split this slice, as described at the top of the file. fn split<'p, 'tcx>(self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { let (self_prefix, self_suffix) = match self.kind { VarLen(self_prefix, self_suffix) => (self_prefix, self_suffix), _ => return smallvec![Slice(self)], }; - let head_ctors = pcx.matrix.head_ctors(pcx.cx).filter(|c| !c.is_wildcard()); - - let mut max_prefix_len = self_prefix; - let mut max_suffix_len = self_suffix; - let mut max_fixed_len = 0; - - for ctor in head_ctors { - if let Slice(slice) = ctor { - match slice.kind { - FixedLen(len) => { - max_fixed_len = cmp::max(max_fixed_len, len); - } - VarLen(prefix, suffix) => { - max_prefix_len = cmp::max(max_prefix_len, prefix); - max_suffix_len = cmp::max(max_suffix_len, suffix); - } - } - } else { - bug!("unexpected ctor for slice type: {:?}", ctor); - } - } - - // For diagnostics, we keep the prefix and suffix lengths separate, so in the case - // where `max_fixed_len + 1` is the largest, we adapt `max_prefix_len` accordingly, - // so that `L = max_prefix_len + max_suffix_len`. - if max_fixed_len + 1 >= max_prefix_len + max_suffix_len { - // The subtraction can't overflow thanks to the above check. - // The new `max_prefix_len` is also guaranteed to be larger than its previous - // value. - max_prefix_len = max_fixed_len + 1 - max_suffix_len; - } - - let final_slice = VarLen(max_prefix_len, max_suffix_len); - let final_slice = Slice::new(self.array_len, final_slice); - match self.array_len { - Some(_) => smallvec![Slice(final_slice)], - None => { - // `self` originally covered the range `(self.arity()..infinity)`. We split that - // range into two: lengths smaller than `final_slice.arity()` are treated - // independently as fixed-lengths slices, and lengths above are captured by - // `final_slice`. - let smaller_lengths = (self.arity()..final_slice.arity()).map(FixedLen); - smaller_lengths - .map(|kind| Slice::new(self.array_len, kind)) - .chain(Some(final_slice)) - .map(Slice) - .collect() - } - } + let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, self.array_len); + let slices = pcx.matrix.head_ctors(pcx.cx).filter_map(|c| c.as_slice()).map(|s| s.kind); + split_self.split(slices); + split_self.iter().map(Slice).collect() } /// See `Constructor::is_covered_by` @@ -529,6 +422,125 @@ impl Slice { } } +/// The exhaustiveness-checking paper does not include any details on checking variable-length +/// slice patterns. However, they may be matched by an infinite collection of fixed-length array +/// patterns. +/// +/// Checking the infinite set directly would take an infinite amount of time. However, it turns out +/// that for each finite set of patterns `P`, all sufficiently large array lengths are equivalent: +/// +/// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies to exactly the subset +/// `Pₜ` of `P` can be transformed to a slice `sₘ` for each sufficiently-large length `m` that +/// applies to exactly the same subset of `P`. +/// +/// Because of that, each witness for reachability-checking of one of the sufficiently-large +/// lengths can be transformed to an equally-valid witness of any other length, so we only have to +/// check slices of the "minimal sufficiently-large length" and less. +/// +/// Note that the fact that there is a *single* `sₘ` for each `m` not depending on the specific +/// pattern in `P` is important: if you look at the pair of patterns `[true, ..]` `[.., false]` +/// Then any slice of length ≥1 that matches one of these two patterns can be trivially turned to a +/// slice of any other length ≥1 that matches them and vice-versa, but the slice of length 2 +/// `[false, true]` that matches neither of these patterns can't be turned to a slice from length 1 +/// that matches neither of these patterns, so we have to consider slices from length 2 there. +/// +/// Now, to see that that length exists and find it, observe that slice patterns are either +/// "fixed-length" patterns (`[_, _, _]`) or "variable-length" patterns (`[_, .., _]`). +/// +/// For fixed-length patterns, all slices with lengths *longer* than the pattern's length have the +/// same outcome (of not matching), so as long as `L` is greater than the pattern's length we can +/// pick any `sₘ` from that length and get the same result. +/// +/// For variable-length patterns, the situation is more complicated, because as seen above the +/// precise value of `sₘ` matters. +/// +/// However, for each variable-length pattern `p` with a prefix of length `plₚ` and suffix of +/// length `slₚ`, only the first `plₚ` and the last `slₚ` elements are examined. +/// +/// Therefore, as long as `L` is positive (to avoid concerns about empty types), all elements after +/// the maximum prefix length and before the maximum suffix length are not examined by any +/// variable-length pattern, and therefore can be added/removed without affecting them - creating +/// equivalent patterns from any sufficiently-large length. +/// +/// Of course, if fixed-length patterns exist, we must be sure that our length is large enough to +/// miss them all, so we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))` +/// +/// `max_slice` below will be made to have arity `L`. +/// +/// For example, with the above pair of patterns, all elements but the first and last can be +/// added/removed, so any witness of length ≥2 (say, `[false, false, true]`) can be turned to a +/// witness from any other length ≥2. +#[derive(Debug)] +struct SplitVarLenSlice { + /// If the type is an array, this is its size. + array_len: Option, + /// The arity of the input slice. + arity: u64, + /// The smallest slice bigger than any slice seen. `max_slice.arity()` is the length `L` + /// described above. + max_slice: SliceKind, +} + +impl SplitVarLenSlice { + fn new(prefix: u64, suffix: u64, array_len: Option) -> Self { + SplitVarLenSlice { array_len, arity: prefix + suffix, max_slice: VarLen(prefix, suffix) } + } + + /// Pass a set of slices relative to which to split this one. + fn split(&mut self, slices: impl Iterator) { + let (max_prefix_len, max_suffix_len) = match &mut self.max_slice { + VarLen(prefix, suffix) => (prefix, suffix), + FixedLen(_) => return, // No need to split + }; + // We grow `self.max_slice` to be larger than all slices encountered, as described above. + // For diagnostics, we keep the prefix and suffix lengths separate, but grow them so that + // `L = max_prefix_len + max_suffix_len`. + let mut max_fixed_len = 0; + for slice in slices { + match slice { + FixedLen(len) => { + max_fixed_len = cmp::max(max_fixed_len, len); + } + VarLen(prefix, suffix) => { + *max_prefix_len = cmp::max(*max_prefix_len, prefix); + *max_suffix_len = cmp::max(*max_suffix_len, suffix); + } + } + } + // We want `L = max(L, max_fixed_len + 1)`, modulo the fact that we keep prefix and + // suffix separate. + if max_fixed_len + 1 >= *max_prefix_len + *max_suffix_len { + // The subtraction can't overflow thanks to the above check. + // The new `max_prefix_len` is larger than its previous value. + *max_prefix_len = max_fixed_len + 1 - *max_suffix_len; + } + + // We cap the arity of `max_slice` at the array size. + match self.array_len { + Some(len) if self.max_slice.arity() >= len => self.max_slice = FixedLen(len), + _ => {} + } + } + + /// Iterate over the partition of this slice. + fn iter<'a>(&'a self) -> impl Iterator + Captures<'a> { + let smaller_lengths = match self.array_len { + // The only admissible fixed-length slice is one of the array size. Whether `max_slice` + // is fixed-length or variable-length, it will be the only relevant slice to output + // here. + Some(_) => (0..0), // empty range + // We cover all arities in the range `(self.arity..infinity)`. We split that range into + // two: lengths smaller than `max_slice.arity()` are treated independently as + // fixed-lengths slices, and lengths above are captured by `max_slice`. + None => self.arity..self.max_slice.arity(), + }; + smaller_lengths + .map(FixedLen) + .chain(once(self.max_slice)) + .map(move |kind| Slice::new(self.array_len, kind)) + } +} + /// A value can be decomposed into a constructor applied to some fields. This struct represents /// the constructor. See also `Fields`. /// From bbb4ac06511fd0a45632327b7888a31e4f7854e5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 13 Dec 2020 23:56:13 +0000 Subject: [PATCH 501/719] Rebrand `MissingConstructors` as `SplitWildcard` --- .../src/thir/pattern/deconstruct_pat.rs | 109 ++++++++++-------- .../src/thir/pattern/usefulness.rs | 7 +- 2 files changed, 67 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 3c6cade1634f..9b065810ad47 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -695,20 +695,9 @@ impl<'tcx> Constructor<'tcx> { /// Two constructors that are not in the matrix will either both be caught (by a wildcard), or /// both not be caught. Therefore we can keep the missing constructors grouped together. fn split_wildcard<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> { - // Missing constructors are those that are not matched by any non-wildcard patterns in the - // current column. We only fully construct them on-demand, because they're rarely used and - // can be big. - let missing_ctors = MissingConstructors::new(pcx); - if missing_ctors.is_empty(pcx) { - // All the constructors are present in the matrix, so we just go through them all. - // We must also split them first. - missing_ctors.all_ctors - } else { - // Some constructors are missing, thus we can specialize with the wildcard constructor, - // which will stand for those constructors that are missing, and behaves like any of - // them. - smallvec![Wildcard] - } + let mut split_wildcard = SplitWildcard::new(pcx); + split_wildcard.split(pcx); + split_wildcard.into_ctors(pcx) } /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`. @@ -811,7 +800,7 @@ impl<'tcx> Constructor<'tcx> { /// `Option`, we do not include `Some(_)` in the returned list of constructors. /// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by /// `cx.is_uninhabited()`). -fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec> { +fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { debug!("all_constructors({:?})", pcx.ty); let cx = pcx.cx; let make_range = |start, end| { @@ -821,19 +810,19 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec vec![make_range(0, 1)], + ty::Bool => smallvec![make_range(0, 1)], ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { let len = len.eval_usize(cx.tcx, cx.param_env); if len != 0 && cx.is_uninhabited(sub_ty) { - vec![] + smallvec![] } else { - vec![Slice(Slice::new(Some(len), VarLen(0, 0)))] + smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))] } } // Treat arrays of a constant but unknown length like slices. ty::Array(sub_ty, _) | ty::Slice(sub_ty) => { let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) }; - vec![Slice(Slice::new(None, kind))] + smallvec![Slice(Slice::new(None, kind))] } ty::Adt(def, substs) if def.is_enum() => { // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an @@ -863,7 +852,7 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec { - vec![ + smallvec![ // The valid Unicode Scalar Value ranges. make_range('\u{0000}' as u128, '\u{D7FF}' as u128), make_range('\u{E000}' as u128, '\u{10FFFF}' as u128), @@ -893,66 +882,94 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec { let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128; let min = 1u128 << (bits - 1); let max = min - 1; - vec![make_range(min, max)] + smallvec![make_range(min, max)] } &ty::Uint(uty) => { let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); let max = size.truncate(u128::MAX); - vec![make_range(0, max)] + smallvec![make_range(0, max)] } // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot // expose its emptiness. The exception is if the pattern is at the top level, because we // want empty matches to be considered exhaustive. ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => { - vec![NonExhaustive] + smallvec![NonExhaustive] } - ty::Never => vec![], - _ if cx.is_uninhabited(pcx.ty) => vec![], - ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => vec![Single], + ty::Never => smallvec![], + _ if cx.is_uninhabited(pcx.ty) => smallvec![], + ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => smallvec![Single], // This type is one for which we cannot list constructors, like `str` or `f64`. - _ => vec![NonExhaustive], + _ => smallvec![NonExhaustive], } } -// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`. +/// A wildcard constructor that we split relative to the constructors in the matrix, as explained +/// at the top of the file. +/// For splitting wildcards, there are two groups of constructors: there are the constructors +/// actually present in the matrix (`matrix_ctors`), and the constructors not present. Two +/// constructors that are not in the matrix will either both be covered (by a wildcard), or both +/// not be covered by any given row. Therefore we can keep the missing constructors grouped +/// together. #[derive(Debug)] -pub(super) struct MissingConstructors<'tcx> { +pub(super) struct SplitWildcard<'tcx> { + /// Constructors seen in the matrix. + matrix_ctors: Vec>, + /// All the constructors for this type all_ctors: SmallVec<[Constructor<'tcx>; 1]>, - used_ctors: Vec>, } -impl<'tcx> MissingConstructors<'tcx> { +impl<'tcx> SplitWildcard<'tcx> { pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self { - let used_ctors: Vec> = + let matrix_ctors = Vec::new(); + let all_ctors = all_constructors(pcx); + SplitWildcard { matrix_ctors, all_ctors } + } + + /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't + /// do what you want. + pub(super) fn split(&mut self, pcx: PatCtxt<'_, '_, 'tcx>) { + self.matrix_ctors = pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect(); // Since `all_ctors` never contains wildcards, this won't recurse further. - let all_ctors = - all_constructors(pcx).into_iter().flat_map(|ctor| ctor.split(pcx)).collect(); - - MissingConstructors { all_ctors, used_ctors } + self.all_ctors = self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx)).collect(); } - fn is_empty<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> bool { - self.iter(pcx).next().is_none() + /// Whether there are any value constructors for this type that are not present in the matrix. + fn any_missing(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool { + self.iter_missing(pcx).next().is_some() } - /// Iterate over all_ctors \ used_ctors - fn iter<'a, 'p>( + /// Iterate over the constructors for this type that are not present in the matrix. + fn iter_missing<'a, 'p>( &'a self, pcx: PatCtxt<'a, 'p, 'tcx>, ) -> impl Iterator> + Captures<'p> { - self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.used_ctors)) + self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors)) + } + + /// Return the set of constructors resulting from splitting the wildcard. As explained at the + /// top of the file, if any constructors are missing we can ignore the present ones. + fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { + if self.any_missing(pcx) { + // Some constructors are missing, thus we can specialize with the wildcard constructor, + // which will stand for those constructors that are missing, and matches the same rows + // as any of them (namely the wildcard rows). + return smallvec![Wildcard]; + } + + // All the constructors are present in the matrix, so we just go through them all. + self.all_ctors } /// List the patterns corresponding to the missing constructors. In some cases, instead of /// listing all constructors of a given type, we prefer to simply report a wildcard. - pub(super) fn report_patterns<'p>( + pub(super) fn report_missing_patterns<'p>( &self, pcx: PatCtxt<'_, 'p, 'tcx>, ) -> SmallVec<[Pat<'tcx>; 1]> { @@ -984,7 +1001,7 @@ impl<'tcx> MissingConstructors<'tcx> { // The exception is: if we are at the top-level, for example in an empty match, we // sometimes prefer reporting the list of constructors instead of just `_`. let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); - if self.used_ctors.is_empty() && !report_when_all_missing { + if self.matrix_ctors.is_empty() && !report_when_all_missing { // All constructors are unused. Report only a wildcard // rather than each individual constructor. smallvec![Pat::wildcard_from_ty(pcx.ty)] @@ -993,7 +1010,7 @@ impl<'tcx> MissingConstructors<'tcx> { // constructor, that matches everything that can be built with // it. For example, if `ctor` is a `Constructor::Variant` for // `Option::Some`, we get the pattern `Some(_)`. - self.iter(pcx) + self.iter_missing(pcx) .map(|missing_ctor| Fields::wildcards(pcx, &missing_ctor).apply(pcx, missing_ctor)) .collect() } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 877d48a85b76..5da42e705df8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -306,7 +306,7 @@ use self::Usefulness::*; use self::WitnessPreference::*; -use super::deconstruct_pat::{Constructor, Fields, MissingConstructors}; +use super::deconstruct_pat::{Constructor, Fields, SplitWildcard}; use super::{Pat, PatKind}; use super::{PatternFoldable, PatternFolder}; @@ -810,8 +810,9 @@ impl<'tcx> Usefulness<'tcx> { match self { UsefulWithWitness(witnesses) => { let new_witnesses = if ctor.is_wildcard() { - let missing_ctors = MissingConstructors::new(pcx); - let new_patterns = missing_ctors.report_patterns(pcx); + let mut split_wildcard = SplitWildcard::new(pcx); + split_wildcard.split(pcx); + let new_patterns = split_wildcard.report_missing_patterns(pcx); witnesses .into_iter() .flat_map(|witness| { From 3141f2d78c446b35930d4a73273578e6c6b488f5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 14 Dec 2020 01:09:06 +0000 Subject: [PATCH 502/719] Inline `all_constructors` --- .../src/thir/pattern/deconstruct_pat.rs | 236 +++++++++--------- 1 file changed, 115 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 9b065810ad47..9e02cb2e3694 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -791,124 +791,6 @@ impl<'tcx> Constructor<'tcx> { } } -/// This determines the set of all possible constructors of a pattern matching -/// values of type `left_ty`. For vectors, this would normally be an infinite set -/// but is instead bounded by the maximum fixed length of slice patterns in -/// the column of patterns being analyzed. -/// -/// We make sure to omit constructors that are statically impossible. E.g., for -/// `Option`, we do not include `Some(_)` in the returned list of constructors. -/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by -/// `cx.is_uninhabited()`). -fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { - debug!("all_constructors({:?})", pcx.ty); - let cx = pcx.cx; - let make_range = |start, end| { - IntRange( - // `unwrap()` is ok because we know the type is an integer. - IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included).unwrap(), - ) - }; - match pcx.ty.kind() { - ty::Bool => smallvec![make_range(0, 1)], - ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { - let len = len.eval_usize(cx.tcx, cx.param_env); - if len != 0 && cx.is_uninhabited(sub_ty) { - smallvec![] - } else { - smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))] - } - } - // Treat arrays of a constant but unknown length like slices. - ty::Array(sub_ty, _) | ty::Slice(sub_ty) => { - let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) }; - smallvec![Slice(Slice::new(None, kind))] - } - ty::Adt(def, substs) if def.is_enum() => { - // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an - // additional "unknown" constructor. - // There is no point in enumerating all possible variants, because the user can't - // actually match against them all themselves. So we always return only the fictitious - // constructor. - // E.g., in an example like: - // - // ``` - // let err: io::ErrorKind = ...; - // match err { - // io::ErrorKind::NotFound => {}, - // } - // ``` - // - // we don't want to show every possible IO error, but instead have only `_` as the - // witness. - let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); - - // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it - // as though it had an "unknown" constructor to avoid exposing its emptiness. The - // exception is if the pattern is at the top level, because we want empty matches to be - // considered exhaustive. - let is_secretly_empty = def.variants.is_empty() - && !cx.tcx.features().exhaustive_patterns - && !pcx.is_top_level; - - if is_secretly_empty || is_declared_nonexhaustive { - smallvec![NonExhaustive] - } else if cx.tcx.features().exhaustive_patterns { - // If `exhaustive_patterns` is enabled, we exclude variants known to be - // uninhabited. - def.variants - .iter() - .filter(|v| { - !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env) - .contains(cx.tcx, cx.module) - }) - .map(|v| Variant(v.def_id)) - .collect() - } else { - def.variants.iter().map(|v| Variant(v.def_id)).collect() - } - } - ty::Char => { - smallvec![ - // The valid Unicode Scalar Value ranges. - make_range('\u{0000}' as u128, '\u{D7FF}' as u128), - make_range('\u{E000}' as u128, '\u{10FFFF}' as u128), - ] - } - ty::Int(_) | ty::Uint(_) - if pcx.ty.is_ptr_sized_integral() - && !cx.tcx.features().precise_pointer_size_matching => - { - // `usize`/`isize` are not allowed to be matched exhaustively unless the - // `precise_pointer_size_matching` feature is enabled. So we treat those types like - // `#[non_exhaustive]` enums by returning a special unmatcheable constructor. - smallvec![NonExhaustive] - } - &ty::Int(ity) => { - let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128; - let min = 1u128 << (bits - 1); - let max = min - 1; - smallvec![make_range(min, max)] - } - &ty::Uint(uty) => { - let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); - let max = size.truncate(u128::MAX); - smallvec![make_range(0, max)] - } - // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot - // expose its emptiness. The exception is if the pattern is at the top level, because we - // want empty matches to be considered exhaustive. - ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => { - smallvec![NonExhaustive] - } - ty::Never => smallvec![], - _ if cx.is_uninhabited(pcx.ty) => smallvec![], - ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => smallvec![Single], - // This type is one for which we cannot list constructors, like `str` or `f64`. - _ => smallvec![NonExhaustive], - } -} - /// A wildcard constructor that we split relative to the constructors in the matrix, as explained /// at the top of the file. /// For splitting wildcards, there are two groups of constructors: there are the constructors @@ -926,9 +808,121 @@ pub(super) struct SplitWildcard<'tcx> { impl<'tcx> SplitWildcard<'tcx> { pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self { - let matrix_ctors = Vec::new(); - let all_ctors = all_constructors(pcx); - SplitWildcard { matrix_ctors, all_ctors } + debug!("SplitWildcard::new({:?})", pcx.ty); + let cx = pcx.cx; + let make_range = |start, end| { + IntRange( + // `unwrap()` is ok because we know the type is an integer. + IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included).unwrap(), + ) + }; + // This determines the set of all possible constructors for the type `pcx.ty`. For numbers, + // arrays and slices we use ranges and variable-length slices when appropriate. + // + // If the `exhaustive_patterns` feature is enabled, we make sure to omit constructors that + // are statically impossible. E.g., for `Option`, we do not include `Some(_)` in the + // returned list of constructors. + // Invariant: this is empty if and only if the type is uninhabited (as determined by + // `cx.is_uninhabited()`). + let all_ctors = match pcx.ty.kind() { + ty::Bool => smallvec![make_range(0, 1)], + ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { + let len = len.eval_usize(cx.tcx, cx.param_env); + if len != 0 && cx.is_uninhabited(sub_ty) { + smallvec![] + } else { + smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))] + } + } + // Treat arrays of a constant but unknown length like slices. + ty::Array(sub_ty, _) | ty::Slice(sub_ty) => { + let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) }; + smallvec![Slice(Slice::new(None, kind))] + } + ty::Adt(def, substs) if def.is_enum() => { + // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an + // additional "unknown" constructor. + // There is no point in enumerating all possible variants, because the user can't + // actually match against them all themselves. So we always return only the fictitious + // constructor. + // E.g., in an example like: + // + // ``` + // let err: io::ErrorKind = ...; + // match err { + // io::ErrorKind::NotFound => {}, + // } + // ``` + // + // we don't want to show every possible IO error, but instead have only `_` as the + // witness. + let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); + + // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it + // as though it had an "unknown" constructor to avoid exposing its emptiness. The + // exception is if the pattern is at the top level, because we want empty matches to be + // considered exhaustive. + let is_secretly_empty = def.variants.is_empty() + && !cx.tcx.features().exhaustive_patterns + && !pcx.is_top_level; + + if is_secretly_empty || is_declared_nonexhaustive { + smallvec![NonExhaustive] + } else if cx.tcx.features().exhaustive_patterns { + // If `exhaustive_patterns` is enabled, we exclude variants known to be + // uninhabited. + def.variants + .iter() + .filter(|v| { + !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env) + .contains(cx.tcx, cx.module) + }) + .map(|v| Variant(v.def_id)) + .collect() + } else { + def.variants.iter().map(|v| Variant(v.def_id)).collect() + } + } + ty::Char => { + smallvec![ + // The valid Unicode Scalar Value ranges. + make_range('\u{0000}' as u128, '\u{D7FF}' as u128), + make_range('\u{E000}' as u128, '\u{10FFFF}' as u128), + ] + } + ty::Int(_) | ty::Uint(_) + if pcx.ty.is_ptr_sized_integral() + && !cx.tcx.features().precise_pointer_size_matching => + { + // `usize`/`isize` are not allowed to be matched exhaustively unless the + // `precise_pointer_size_matching` feature is enabled. So we treat those types like + // `#[non_exhaustive]` enums by returning a special unmatcheable constructor. + smallvec![NonExhaustive] + } + &ty::Int(ity) => { + let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128; + let min = 1u128 << (bits - 1); + let max = min - 1; + smallvec![make_range(min, max)] + } + &ty::Uint(uty) => { + let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); + let max = size.truncate(u128::MAX); + smallvec![make_range(0, max)] + } + // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot + // expose its emptiness. The exception is if the pattern is at the top level, because we + // want empty matches to be considered exhaustive. + ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => { + smallvec![NonExhaustive] + } + ty::Never => smallvec![], + _ if cx.is_uninhabited(pcx.ty) => smallvec![], + ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => smallvec![Single], + // This type is one for which we cannot list constructors, like `str` or `f64`. + _ => smallvec![NonExhaustive], + }; + SplitWildcard { matrix_ctors: Vec::new(), all_ctors } } /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't From 8b38b6859a5395520e4f466133db4ec4bfd0317d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 20 Dec 2020 14:22:53 +0000 Subject: [PATCH 503/719] Inline the constructor-specific `split` functions --- .../src/thir/pattern/deconstruct_pat.rs | 53 +++++++------------ 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 9e02cb2e3694..060e4fdf6f81 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -183,14 +183,6 @@ impl IntRange { Pat { ty, span: DUMMY_SP, kind: Box::new(kind) } } - /// Split this range, as described at the top of the file. - fn split<'p, 'tcx>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { - let mut split_range = SplitIntRange::new(self.clone()); - let intranges = pcx.matrix.head_ctors(pcx.cx).filter_map(|ctor| ctor.as_int_range()); - split_range.split(intranges.cloned()); - split_range.iter().map(IntRange).collect() - } - /// Lint on likely incorrect range patterns (#63987) pub(super) fn lint_overlapping_range_endpoints(&self, pcx: PatCtxt<'_, '_, '_>, hir_id: HirId) { if self.is_singleton() { @@ -403,19 +395,6 @@ impl Slice { self.kind.arity() } - /// Split this slice, as described at the top of the file. - fn split<'p, 'tcx>(self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { - let (self_prefix, self_suffix) = match self.kind { - VarLen(self_prefix, self_suffix) => (self_prefix, self_suffix), - _ => return smallvec![Slice(self)], - }; - - let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, self.array_len); - let slices = pcx.matrix.head_ctors(pcx.cx).filter_map(|c| c.as_slice()).map(|s| s.kind); - split_self.split(slices); - split_self.iter().map(Slice).collect() - } - /// See `Constructor::is_covered_by` fn is_covered_by(self, other: Self) -> bool { other.kind.covers_length(self.arity()) @@ -680,26 +659,32 @@ impl<'tcx> Constructor<'tcx> { debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix); match self { - Wildcard => Constructor::split_wildcard(pcx), + Wildcard => { + let mut split_wildcard = SplitWildcard::new(pcx); + split_wildcard.split(pcx); + split_wildcard.into_ctors(pcx) + } // Fast-track if the range is trivial. In particular, we don't do the overlapping // ranges check. - IntRange(ctor_range) if !ctor_range.is_singleton() => ctor_range.split(pcx), - Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx), + IntRange(ctor_range) if !ctor_range.is_singleton() => { + let mut split_range = SplitIntRange::new(ctor_range.clone()); + let intranges = + pcx.matrix.head_ctors(pcx.cx).filter_map(|ctor| ctor.as_int_range()); + split_range.split(intranges.cloned()); + split_range.iter().map(IntRange).collect() + } + &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => { + let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len); + let slices = + pcx.matrix.head_ctors(pcx.cx).filter_map(|c| c.as_slice()).map(|s| s.kind); + split_self.split(slices); + split_self.iter().map(Slice).collect() + } // Any other constructor can be used unchanged. _ => smallvec![self.clone()], } } - /// For wildcards, there are two groups of constructors: there are the constructors actually - /// present in the matrix (`head_ctors`), and the constructors not present (`missing_ctors`). - /// Two constructors that are not in the matrix will either both be caught (by a wildcard), or - /// both not be caught. Therefore we can keep the missing constructors grouped together. - fn split_wildcard<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx); - split_wildcard.into_ctors(pcx) - } - /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`. /// For the simple cases, this is simply checking for equality. For the "grouped" constructors, /// this checks for inclusion. From 43d445c8d1ae9c6ecb8203dd97d96f0e245b042d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 20 Dec 2020 14:29:42 +0000 Subject: [PATCH 504/719] Pass `Matrix` explicitly instead of via `PatCtxt` --- .../src/thir/pattern/deconstruct_pat.rs | 49 ++++++++++++------- .../src/thir/pattern/usefulness.rs | 26 ++++++---- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 060e4fdf6f81..4860bb0fe876 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::lint; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; use smallvec::{smallvec, SmallVec}; @@ -184,12 +184,18 @@ impl IntRange { } /// Lint on likely incorrect range patterns (#63987) - pub(super) fn lint_overlapping_range_endpoints(&self, pcx: PatCtxt<'_, '_, '_>, hir_id: HirId) { + pub(super) fn lint_overlapping_range_endpoints<'a, 'tcx: 'a>( + &self, + pcx: PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator, Span)>, + column_count: usize, + hir_id: HirId, + ) { if self.is_singleton() { return; } - if pcx.matrix.column_count().unwrap_or(0) != 1 { + if column_count != 1 { // FIXME: for now, only check for overlapping ranges on simple range // patterns. Otherwise with the current logic the following is detected // as overlapping: @@ -203,9 +209,7 @@ impl IntRange { return; } - let overlaps: Vec<_> = pcx - .matrix - .head_ctors_and_spans(pcx.cx) + let overlaps: Vec<_> = ctors .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))) .filter(|(range, _)| self.suspicious_intersection(range)) .map(|(range, span)| (self.intersection(&range).unwrap(), span)) @@ -655,28 +659,33 @@ impl<'tcx> Constructor<'tcx> { /// This function may discard some irrelevant constructors if this preserves behavior and /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the /// matrix, unless all of them are. - pub(super) fn split<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> { - debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix); + pub(super) fn split<'a>( + &self, + pcx: PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator> + Clone, + ) -> SmallVec<[Self; 1]> + where + 'tcx: 'a, + { + debug!("Constructor::split({:#?})", self); match self { Wildcard => { let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx); + split_wildcard.split(pcx, ctors); split_wildcard.into_ctors(pcx) } // Fast-track if the range is trivial. In particular, we don't do the overlapping // ranges check. IntRange(ctor_range) if !ctor_range.is_singleton() => { let mut split_range = SplitIntRange::new(ctor_range.clone()); - let intranges = - pcx.matrix.head_ctors(pcx.cx).filter_map(|ctor| ctor.as_int_range()); + let intranges = ctors.filter_map(|ctor| ctor.as_int_range()); split_range.split(intranges.cloned()); split_range.iter().map(IntRange).collect() } &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => { let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len); - let slices = - pcx.matrix.head_ctors(pcx.cx).filter_map(|c| c.as_slice()).map(|s| s.kind); + let slices = ctors.filter_map(|c| c.as_slice()).map(|s| s.kind); split_self.split(slices); split_self.iter().map(Slice).collect() } @@ -912,11 +921,17 @@ impl<'tcx> SplitWildcard<'tcx> { /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't /// do what you want. - pub(super) fn split(&mut self, pcx: PatCtxt<'_, '_, 'tcx>) { - self.matrix_ctors = - pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect(); + pub(super) fn split<'a>( + &mut self, + pcx: PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator> + Clone, + ) where + 'tcx: 'a, + { // Since `all_ctors` never contains wildcards, this won't recurse further. - self.all_ctors = self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx)).collect(); + self.all_ctors = + self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect(); + self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect(); } /// Whether there are any value constructors for this type that are not present in the matrix. diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 5da42e705df8..ad672b59ba4f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -358,8 +358,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { #[derive(Copy, Clone)] pub(super) struct PatCtxt<'a, 'p, 'tcx> { pub(super) cx: &'a MatchCheckCtxt<'p, 'tcx>, - /// Current state of the matrix. - pub(super) matrix: &'a Matrix<'p, 'tcx>, /// Type of the current column under investigation. pub(super) ty: Ty<'tcx>, /// Span of the current pattern under investigation. @@ -538,7 +536,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { pub(super) fn head_ctors<'a>( &'a self, cx: &'a MatchCheckCtxt<'p, 'tcx>, - ) -> impl Iterator> + Captures<'p> { + ) -> impl Iterator> + Captures<'p> + Clone { self.patterns.iter().map(move |r| r.head_ctor(cx)) } @@ -804,6 +802,7 @@ impl<'tcx> Usefulness<'tcx> { fn apply_constructor<'p>( self, pcx: PatCtxt<'_, 'p, 'tcx>, + matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors ctor: &Constructor<'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>, ) -> Self { @@ -811,7 +810,7 @@ impl<'tcx> Usefulness<'tcx> { UsefulWithWitness(witnesses) => { let new_witnesses = if ctor.is_wildcard() { let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx); + split_wildcard.split(pcx, matrix.head_ctors(pcx.cx)); let new_patterns = split_wildcard.report_missing_patterns(pcx); witnesses .into_iter() @@ -968,7 +967,7 @@ fn is_useful<'p, 'tcx>( // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); - let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level }; + let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level }; debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head()); @@ -995,20 +994,27 @@ fn is_useful<'p, 'tcx>( let v_ctor = v.head_ctor(cx); if let Constructor::IntRange(ctor_range) = &v_ctor { // Lint on likely incorrect range patterns (#63987) - ctor_range.lint_overlapping_range_endpoints(pcx, hir_id) + ctor_range.lint_overlapping_range_endpoints( + pcx, + matrix.head_ctors_and_spans(cx), + matrix.column_count().unwrap_or(0), + hir_id, + ) } // We split the head constructor of `v`. - let split_ctors = v_ctor.split(pcx); + let split_ctors = v_ctor.split(pcx, matrix.head_ctors(cx)); // For each constructor, we compute whether there's a value that starts with it that would // witness the usefulness of `v`. + let start_matrix = &matrix; let usefulnesses = split_ctors.into_iter().map(|ctor| { // We cache the result of `Fields::wildcards` because it is used a lot. let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); - let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); + let spec_matrix = + start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); let v = v.pop_head_constructor(&ctor_wild_subpatterns); let usefulness = - is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); - usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) + is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false); + usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns) }); Usefulness::merge(usefulnesses) }; From 2a541cea354fe5866cf2addafe730c0d7c0dd0c2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 20 Dec 2020 13:29:39 +0000 Subject: [PATCH 505/719] Completely rework the explanation of the algorithm --- .../src/thir/pattern/deconstruct_pat.rs | 164 ++++-- .../src/thir/pattern/usefulness.rs | 499 +++++++++--------- 2 files changed, 351 insertions(+), 312 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 4860bb0fe876..f71a4829e8a2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1,6 +1,47 @@ -//! This module provides functions to deconstruct and reconstruct patterns into a constructor -//! applied to some fields. This is used by the `_match` module to compute pattern -//! usefulness/exhaustiveness. +//! [`super::usefulness`] explains most of what is happening in this file. As explained there, +//! values and patterns are made from constructors applied to fields. This file defines a +//! `Constructor` enum, a `Fields` struct, and various operations to manipulate them and convert +//! them from/to patterns. +//! +//! There's one idea that is not detailed in [`super::usefulness`] because the details are not +//! needed there: _constructor splitting_. +//! +//! # Constructor splitting +//! +//! The idea is as follows: given a constructor `c` and a matrix, we want to specialize in turn +//! with all the value constructors that are covered by `c`, and compute usefulness for each. +//! Instead of listing all those constructors (which is intractable), we group those value +//! constructors together as much as possible. Example: +//! +//! ``` +//! match (0, false) { +//! (0 ..=100, true) => {} // `p_1` +//! (50..=150, false) => {} // `p_2` +//! (0 ..=200, _) => {} // `q` +//! } +//! ``` +//! +//! The naive approach would try all numbers in the range `0..=200`. But we can be a lot more +//! clever: `0` and `1` for example will match the exact same rows, and return equivalent +//! witnesses. In fact all of `0..50` would. We can thus restrict our exploration to 4 +//! constructors: `0..50`, `50..=100`, `101..=150` and `151..=200`. That is enough and infinitely +//! more tractable. +//! +//! We capture this idea in a function `split(p_1 ... p_n, c)` which returns a list of constructors +//! `c'` covered by `c`. Given such a `c'`, we require that all value ctors `c''` covered by `c'` +//! return an equivalent set of witnesses after specializing and computing usefulness. +//! In the example above, witnesses for specializing by `c''` covered by `0..50` will only differ +//! in their first element. +//! +//! We usually also ask that the `c'` together cover all of the original `c`. However we allow +//! skipping some constructors as long as it doesn't change whether the resulting list of witnesses +//! is empty of not. We use this in the wildcard `_` case. +//! +//! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for +//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting +//! wildcards, see [`SplitWildcard`]; for integer ranges, see [`SplitIntRange`]; for slices, see +//! [`SplitVarLenSlice`]. + use self::Constructor::*; use self::SliceKind::*; @@ -260,13 +301,13 @@ enum IntBorder { AfterMax, } -/// A range of integers that is partitioned into disjoint subranges. -/// -/// This is fed an input of multiple ranges, and returns an output that covers the union of the -/// inputs but is split so that an output range only intersects an input range by being a subrange -/// of it. No output range straddles the boundary of one of the inputs. This does constructor +/// A range of integers that is partitioned into disjoint subranges. This does constructor /// splitting for integer ranges as explained at the top of the file. /// +/// This is fed multiple ranges, and returns an output that covers the input, but is split so that +/// the only intersections between an output range and a seen range are inclusions. No output range +/// straddles the boundary of one of the inputs. +/// /// The following input: /// ``` /// |-------------------------| // `self` @@ -405,54 +446,67 @@ impl Slice { } } -/// The exhaustiveness-checking paper does not include any details on checking variable-length -/// slice patterns. However, they may be matched by an infinite collection of fixed-length array -/// patterns. +/// This computes constructor splitting for variable-length slices, as explained at the top of the +/// file. /// -/// Checking the infinite set directly would take an infinite amount of time. However, it turns out -/// that for each finite set of patterns `P`, all sufficiently large array lengths are equivalent: +/// A slice pattern `[x, .., y]` behaves like the infinite or-pattern `[x, y] | [x, _, y] | [x, _, +/// _, y] | ...`. The corresponding value constructors are fixed-length array constructors above a +/// given minimum length. We obviously can't list all of this infinity of constructors. Thankfully, +/// it turns out that for each finite set of slice patterns, all sufficiently large array lengths +/// are equivalent. /// -/// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies to exactly the subset -/// `Pₜ` of `P` can be transformed to a slice `sₘ` for each sufficiently-large length `m` that -/// applies to exactly the same subset of `P`. +/// Let's look at an example, where we are trying to split the last pattern: +/// ``` +/// match x { +/// [true, true, ..] => {} +/// [.., false, false] => {} +/// [..] => {} +/// } +/// ``` +/// Here are the results of specialization for the first few lengths: +/// ``` +/// // length 0 +/// [] => {} +/// // length 1 +/// [_] => {} +/// // length 2 +/// [true, true] => {} +/// [false, false] => {} +/// [_, _] => {} +/// // length 3 +/// [true, true, _ ] => {} +/// [_, false, false] => {} +/// [_, _, _ ] => {} +/// // length 4 +/// [true, true, _, _ ] => {} +/// [_, _, false, false] => {} +/// [_, _, _, _ ] => {} +/// // length 5 +/// [true, true, _, _, _ ] => {} +/// [_, _, _, false, false] => {} +/// [_, _, _, _, _ ] => {} +/// ``` /// -/// Because of that, each witness for reachability-checking of one of the sufficiently-large -/// lengths can be transformed to an equally-valid witness of any other length, so we only have to -/// check slices of the "minimal sufficiently-large length" and less. +/// If we went above length 5, we would simply be inserting more columns full of wildcards in the +/// middle. This means that the set of witnesses for length `l >= 5` if equivalent to the set for +/// any other `l' >= 5`: simply add or remove wildcards in the middle to convert between them. /// -/// Note that the fact that there is a *single* `sₘ` for each `m` not depending on the specific -/// pattern in `P` is important: if you look at the pair of patterns `[true, ..]` `[.., false]` -/// Then any slice of length ≥1 that matches one of these two patterns can be trivially turned to a -/// slice of any other length ≥1 that matches them and vice-versa, but the slice of length 2 -/// `[false, true]` that matches neither of these patterns can't be turned to a slice from length 1 -/// that matches neither of these patterns, so we have to consider slices from length 2 there. +/// This applies to any set of slice patterns: there will be a length `L` above which all length +/// behave the same. This is exactly what we need for constructor splitting. Therefore a +/// variable-length slice can be split into a variable-length slice of minimal length `L`, and many +/// fixed-length slices of lengths `< L`. /// -/// Now, to see that that length exists and find it, observe that slice patterns are either -/// "fixed-length" patterns (`[_, _, _]`) or "variable-length" patterns (`[_, .., _]`). -/// -/// For fixed-length patterns, all slices with lengths *longer* than the pattern's length have the -/// same outcome (of not matching), so as long as `L` is greater than the pattern's length we can -/// pick any `sₘ` from that length and get the same result. -/// -/// For variable-length patterns, the situation is more complicated, because as seen above the -/// precise value of `sₘ` matters. -/// -/// However, for each variable-length pattern `p` with a prefix of length `plₚ` and suffix of -/// length `slₚ`, only the first `plₚ` and the last `slₚ` elements are examined. -/// -/// Therefore, as long as `L` is positive (to avoid concerns about empty types), all elements after -/// the maximum prefix length and before the maximum suffix length are not examined by any -/// variable-length pattern, and therefore can be added/removed without affecting them - creating -/// equivalent patterns from any sufficiently-large length. +/// For each variable-length pattern `p` with a prefix of length `plₚ` and suffix of length `slₚ`, +/// only the first `plₚ` and the last `slₚ` elements are examined. Therefore, as long as `L` is +/// positive (to avoid concerns about empty types), all elements after the maximum prefix length +/// and before the maximum suffix length are not examined by any variable-length pattern, and +/// therefore can be added/removed without affecting them - creating equivalent patterns from any +/// sufficiently-large length. /// /// Of course, if fixed-length patterns exist, we must be sure that our length is large enough to /// miss them all, so we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))` /// /// `max_slice` below will be made to have arity `L`. -/// -/// For example, with the above pair of patterns, all elements but the first and last can be -/// added/removed, so any witness of length ≥2 (say, `[false, false, true]`) can be turned to a -/// witness from any other length ≥2. #[derive(Debug)] struct SplitVarLenSlice { /// If the type is an array, this is its size. @@ -787,11 +841,19 @@ impl<'tcx> Constructor<'tcx> { /// A wildcard constructor that we split relative to the constructors in the matrix, as explained /// at the top of the file. -/// For splitting wildcards, there are two groups of constructors: there are the constructors -/// actually present in the matrix (`matrix_ctors`), and the constructors not present. Two -/// constructors that are not in the matrix will either both be covered (by a wildcard), or both -/// not be covered by any given row. Therefore we can keep the missing constructors grouped -/// together. +/// +/// A constructor that is not present in the matrix rows will only be covered by the rows that have +/// wildcards. Thus we can group all of those constructors together; we call them "missing +/// constructors". Splitting a wildcard would therefore list all present constructors individually +/// (or grouped if they are integers or slices), and then all missing constructors together as a +/// group. +/// +/// However we can go further: since any constructor will match the wildcard rows, and having more +/// rows can only reduce the amount of usefulness witnesses, we can skip the present constructors +/// and only try the missing ones. +/// This will not preserve the whole list of witnesses, but will preserve whether the list is empty +/// or not. In fact this is quite natural from the point of view of diagnostics too. This is done +/// in `to_ctors`: in some cases we only return `Missing`. #[derive(Debug)] pub(super) struct SplitWildcard<'tcx> { /// Constructors seen in the matrix. diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index ad672b59ba4f..424310842307 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -12,296 +12,272 @@ //! //! ----- //! -//! This file includes the logic for exhaustiveness and usefulness checking for -//! pattern-matching. Specifically, given a list of patterns for a type, we can -//! tell whether: -//! (a) the patterns cover every possible constructor for the type (exhaustiveness) -//! (b) each pattern is necessary (usefulness) +//! This file includes the logic for exhaustiveness and reachability checking for pattern-matching. +//! Specifically, given a list of patterns for a type, we can tell whether: +//! (a) each pattern is reachable (reachability) +//! (b) the patterns cover every possible value for the type (exhaustiveness) //! -//! The algorithm implemented here is a modified version of the one described in -//! [this paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). -//! However, to save future implementors from reading the original paper, we -//! summarise the algorithm here to hopefully save time and be a little clearer -//! (without being so rigorous). -//! -//! # Premise -//! -//! The core of the algorithm revolves about a "usefulness" check. In particular, we -//! are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as -//! a matrix). `U(P, p)` represents whether, given an existing list of patterns -//! `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously- -//! uncovered values of the type). -//! -//! If we have this predicate, then we can easily compute both exhaustiveness of an -//! entire set of patterns and the individual usefulness of each one. -//! (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard -//! match doesn't increase the number of values we're matching) -//! (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a -//! pattern to those that have come before it doesn't increase the number of values -//! we're matching). -//! -//! # Core concept -//! -//! The idea that powers everything that is done in this file is the following: a value is made -//! from a constructor applied to some fields. Examples of constructors are `Some`, `None`, `(,)` -//! (the 2-tuple constructor), `Foo {..}` (the constructor for a struct `Foo`), and `2` (the -//! constructor for the number `2`). Fields are just a (possibly empty) list of values. -//! -//! Some of the constructors listed above might feel weird: `None` and `2` don't take any -//! arguments. This is part of what makes constructors so general: we will consider plain values -//! like numbers and string literals to be constructors that take no arguments, also called "0-ary -//! constructors"; they are the simplest case of constructors. This allows us to see any value as -//! made up from a tree of constructors, each having a given number of children. For example: -//! `(None, Ok(0))` is made from 4 different constructors. -//! -//! This idea can be extended to patterns: a pattern captures a set of possible values, and we can -//! describe this set using constructors. For example, `Err(_)` captures all values of the type -//! `Result` that start with the `Err` constructor (for some choice of `T` and `E`). The -//! wildcard `_` captures all values of the given type starting with any of the constructors for -//! that type. -//! -//! We use this to compute whether different patterns might capture a same value. Do the patterns -//! `Ok("foo")` and `Err(_)` capture a common value? The answer is no, because the first pattern -//! captures only values starting with the `Ok` constructor and the second only values starting -//! with the `Err` constructor. Do the patterns `Some(42)` and `Some(1..10)` intersect? They might, -//! since they both capture values starting with `Some`. To be certain, we need to dig under the -//! `Some` constructor and continue asking the question. This is the main idea behind the -//! exhaustiveness algorithm: by looking at patterns constructor-by-constructor, we can efficiently -//! figure out if some new pattern might capture a value that hadn't been captured by previous -//! patterns. -//! -//! Constructors are represented by the `Constructor` enum, and its fields by the `Fields` enum. -//! Most of the complexity of this file resides in transforming between patterns and -//! (`Constructor`, `Fields`) pairs, handling all the special cases correctly. -//! -//! Caveat: this constructors/fields distinction doesn't quite cover every Rust value. For example -//! a value of type `Rc` doesn't fit this idea very well, nor do various other things. -//! However, this idea covers most of the cases that are relevant to exhaustiveness checking. +//! The algorithm implemented here is a modified version of the one described in [this +//! paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). We have however generalized +//! it to accomodate the variety of patterns that rust supports. We thus explain our version here, +//! without being as rigorous. //! //! -//! # Algorithm +//! # Summary //! -//! Recall that `U(P, p)` represents whether, given an existing list of patterns (aka matrix) `P`, -//! adding a new pattern `p` will cover previously-uncovered values of the type. -//! During the course of the algorithm, the rows of the matrix won't just be individual patterns, -//! but rather partially-deconstructed patterns in the form of a list of fields. The paper -//! calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the -//! new pattern `p`. +//! The core of the algorithm is the notion of "usefulness". A pattern `q` is said to be *useful* +//! relative to another pattern `p` of the same type if there is a value that is matched by `q` and +//! not matched by `p`. This generalizes to many `p`s: `q` is useful wrt a list of patterns `p_1 .. +//! p_n` if there is a value that is matched by `q` and by none of the `p_i`. We write +//! `usefulness(p_1 .. p_n, q)` for a function that returns a list of such values. The aim of this +//! file is to compute it efficiently. //! -//! For example, say we have the following: -//! -//! ``` -//! // x: (Option, Result<()>) +//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it +//! is useful wrt the patterns above it: +//! ```rust //! match x { -//! (Some(true), _) => {} -//! (None, Err(())) => {} -//! (None, Err(_)) => {} +//! Some(_) => ..., +//! None => ..., // reachable: `None` is matched by this but not the branch above +//! Some(0) => ..., // unreachable: all the values this matches are already matched by +//! // `Some(_)` above //! } //! ``` //! -//! Here, the matrix `P` starts as: -//! -//! ``` -//! [ -//! [(Some(true), _)], -//! [(None, Err(()))], -//! [(None, Err(_))], -//! ] +//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_` +//! pattern is _not_ useful wrt the patterns in the match. The values returned by `usefulness` are +//! used to tell the user which values are missing. +//! ```rust +//! match x { +//! Some(0) => ..., +//! None => ..., +//! // not exhaustive: `_` is useful because it matches `Some(1)` +//! } //! ``` //! -//! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering -//! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because -//! all the values it covers are already covered by row 2. -//! -//! A list of patterns can be thought of as a stack, because we are mainly interested in the top of -//! the stack at any given point, and we can pop or apply constructors to get new pattern-stacks. -//! To match the paper, the top of the stack is at the beginning / on the left. -//! -//! There are two important operations on pattern-stacks necessary to understand the algorithm: -//! -//! 1. We can pop a given constructor off the top of a stack. This operation is called -//! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or -//! `None`) and `p` a pattern-stack. -//! If the pattern on top of the stack can cover `c`, this removes the constructor and -//! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. -//! Otherwise the pattern-stack is discarded. -//! This essentially filters those pattern-stacks whose top covers the constructor `c` and -//! discards the others. -//! -//! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we -//! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the -//! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get -//! nothing back. -//! -//! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` -//! on top of the stack, and we have four cases: -//! -//! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We -//! push onto the stack the arguments of this constructor, and return the result: -//! `r_1, .., r_a, p_2, .., p_n` -//! -//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and -//! return nothing. -//! -//! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has -//! arguments (its arity), and return the resulting stack: -//! `_, .., _, p_2, .., p_n` -//! -//! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting -//! stack: -//! - `S(c, (r_1, p_2, .., p_n))` -//! - `S(c, (r_2, p_2, .., p_n))` -//! -//! 2. We can pop a wildcard off the top of the stack. This is called `S(_, p)`, where `p` is -//! a pattern-stack. Note: the paper calls this `D(p)`. -//! This is used when we know there are missing constructor cases, but there might be -//! existing wildcard patterns, so to check the usefulness of the matrix, we have to check -//! all its *other* components. -//! -//! It is computed as follows. We look at the pattern `p_1` on top of the stack, -//! and we have three cases: -//! 2.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. -//! 2.2. `p_1 = _`. We return the rest of the stack: -//! p_2, .., p_n -//! 2.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting -//! stack. -//! - `S(_, (r_1, p_2, .., p_n))` -//! - `S(_, (r_2, p_2, .., p_n))` -//! -//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the -//! exhaustive integer matching rules, so they're written here for posterity. -//! -//! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by -//! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with -//! the given constructor, and popping a wildcard keeps those rows that start with a wildcard. +//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes +//! reachability for each match branch and exhaustiveness for the whole match. //! //! -//! The algorithm for computing `U` -//! ------------------------------- -//! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns). -//! That means we're going to check the components from left-to-right, so the algorithm -//! operates principally on the first component of the matrix and new pattern-stack `p`. -//! This algorithm is realised in the `is_useful` function. +//! # Constructors and fields //! -//! Base case. (`n = 0`, i.e., an empty tuple pattern) -//! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), -//! then `U(P, p)` is false. -//! - Otherwise, `P` must be empty, so `U(P, p)` is true. +//! Note: we will often abbreviate "constructor" as "ctor". //! -//! Inductive step. (`n > 0`, i.e., whether there's at least one column -//! [which may then be expanded into further columns later]) -//! We're going to match on the top of the new pattern-stack, `p_1`. -//! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. -//! Then, the usefulness of `p_1` can be reduced to whether it is useful when -//! we ignore all the patterns in the first column of `P` that involve other constructors. -//! This is where `S(c, P)` comes in: -//! `U(P, p) := U(S(c, P), S(c, p))` +//! The idea that powers everything that is done in this file is the following: a (matcheable) +//! value is made from a constructor applied to a number of subvalues. Examples of constructors are +//! `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor for a struct +//! `Foo`), and `2` (the constructor for the number `2`). This is natural when we think of +//! pattern-matching, and this is the basis for what follows. //! -//! For example, if `P` is: +//! Some of the ctors listed above might feel weird: `None` and `2` don't take any arguments. +//! That's ok: those are ctors that take a list of 0 arguments; they are the simplest case of +//! ctors. We treat `2` as a ctor because `u64` and other number types behave exactly like a huge +//! `enum`, with one variant for each number. This allows us to see any matcheable value as made up +//! from a tree of ctors, each having a set number of children. For example: `Foo { bar: None, +//! baz: Ok(0) }` is made from 4 different ctors, namely `Foo{..}`, `None`, `Ok` and `0`. //! +//! This idea can be extended to patterns: they are also made from constructors applied to fields. +//! A pattern for a given type is allowed to use all the ctors for values of that type (which we +//! call "value constructors"), but there are also pattern-only ctors. The most important one is +//! the wildcard (`_`), and the others are integer ranges (`0..=10`), variable-length slices (`[x, +//! ..]`), and or-patterns (`Ok(0) | Err(_)`). Examples of valid patterns are `42`, `Some(_)`, `Foo +//! { bar: Some(0) | None, baz: _ }`. Note that a binder in a pattern (e.g. `Some(x)`) matches the +//! same values as a wildcard (e.g. `Some(_)`), so we treat both as wildcards. +//! +//! From this deconstruction we can compute whether a given value matches a given pattern; we +//! simply look at ctors one at a time. Given a pattern `p` and a value `v`, we want to compute +//! `matches!(v, p)`. It's mostly straightforward: we compare the head ctors and when they match +//! we compare their fields recursively. A few representative examples: +//! +//! - `matches!(v, _) := true` +//! - `matches!((v0, v1), (p0, p1)) := matches!(v0, p0) && matches!(v1, p1)` +//! - `matches!(Foo { bar: v0, baz: v1 }, Foo { bar: p0, baz: p1 }) := matches!(v0, p0) && matches!(v1, p1)` +//! - `matches!(Ok(v0), Ok(p0)) := matches!(v0, p0)` +//! - `matches!(Ok(v0), Err(p0)) := false` (incompatible variants) +//! - `matches!(v, 1..=100) := matches!(v, 1) || ... || matches!(v, 100)` +//! - `matches!([v0], [p0, .., p1]) := false` (incompatible lengths) +//! - `matches!([v0, v1, v2], [p0, .., p1]) := matches!(v0, p0) && matches!(v2, p1)` +//! - `matches!(v, p0 | p1) := matches!(v, p0) || matches!(v, p1)` +//! +//! Constructors, fields and relevant operations are defined in the [`super::deconstruct_pat`] module. +//! +//! Note: this constructors/fields distinction may not straightforwardly apply to every Rust type. +//! For example a value of type `Rc` can't be deconstructed that way, and `&str` has an +//! infinity of constructors. There are also subtleties with visibility of fields and +//! uninhabitedness and various other things. The constructors idea can be extended to handle most +//! of these subtleties though; caveats are documented where relevant throughout the code. +//! +//! Whether constructors cover each other is computed by [`Constructor::is_covered_by`]. +//! +//! +//! # Specialization +//! +//! Recall that we wish to compute `usefulness(p_1 .. p_n, q)`: given a list of patterns `p_1 .. +//! p_n` and a pattern `q`, all of the same type, we want to find a list of values (called +//! "witnesses") that are matched by `q` and by none of the `p_i`. We obviously don't just +//! enumerate all possible values. From the discussion above we see that we can proceed +//! ctor-by-ctor: for each value ctor of the given type, we ask "is there a value that starts with +//! this constructor and matches `q` and none of the `p_i`?". As we saw above, there's a lot we can +//! say from knowing only the first constructor of our candidate value. +//! +//! Let's take the following example: //! ``` -//! [ -//! [Some(true), _], -//! [None, 0], -//! ] +//! match x { +//! Enum::Variant1(_) => {} // `p1` +//! Enum::Variant2(None, 0) => {} // `p2` +//! Enum::Variant2(Some(_), 0) => {} // `q` +//! } //! ``` //! -//! and `p` is `[Some(false), 0]`, then we don't care about row 2 since we know `p` only -//! matches values that row 2 doesn't. For row 1 however, we need to dig into the -//! arguments of `Some` to know whether some new value is covered. So we compute -//! `U([[true, _]], [false, 0])`. -//! -//! - If `p_1 == _`, then we look at the list of constructors that appear in the first -//! component of the rows of `P`: -//! + If there are some constructors that aren't present, then we might think that the -//! wildcard `_` is useful, since it covers those constructors that weren't covered -//! before. -//! That's almost correct, but only works if there were no wildcards in those first -//! components. So we need to check that `p` is useful with respect to the rows that -//! start with a wildcard, if there are any. This is where `S(_, x)` comes in: -//! `U(P, p) := U(S(_, P), S(_, p))` -//! -//! For example, if `P` is: +//! We can easily see that if our candidate value `v` starts with `Variant1` it will not match `q`. +//! If `v = Variant2(v0, v1)` however, whether or not it matches `p2` and `q` will depend on `v0` +//! and `v1`. In fact, such a `v` will be a witness of usefulness of `q` exactly when the tuple +//! `(v0, v1)` is a witness of usefulness of `q'` in the following reduced match: //! //! ``` -//! [ -//! [_, true, _], -//! [None, false, 1], -//! ] +//! match x { +//! (None, 0) => {} // `p2'` +//! (Some(_), 0) => {} // `q'` +//! } //! ``` //! -//! and `p` is `[_, false, _]`, the `Some` constructor doesn't appear in `P`. So if we -//! only had row 2, we'd know that `p` is useful. However row 1 starts with a -//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. -//! -//! + Otherwise, all possible constructors (for the relevant type) are present. In this -//! case we must check whether the wildcard pattern covers any unmatched value. For -//! that, we can think of the `_` pattern as a big OR-pattern that covers all -//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for -//! example. The wildcard pattern is useful in this case if it is useful when -//! specialized to one of the possible constructors. So we compute: -//! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` -//! -//! For example, if `P` is: +//! This motivates a new step in computing usefulness, that we call _specialization_. +//! Specialization consist of filtering a list of patterns for those that match a constructor, and +//! then looking into the constructor's fields. This enables usefulness to be computed recursively. //! +//! Instead of acting on a single pattern in each row, we will consider a list of patterns for each +//! row, and we call such a list a _pattern-stack_. The idea is that we will specialize the +//! leftmost pattern, which amounts to popping the constructor and pushing its fields, which feels +//! like a stack. We note a pattern-stack simply with `[p_1 ... p_n]`. +//! Here's a sequence of specializations of a list of pattern-stacks, to illustrate what's +//! happening: //! ``` -//! [ -//! [Some(true), _], -//! [None, false], -//! ] +//! [Enum::Variant1(_)] +//! [Enum::Variant2(None, 0)] +//! [Enum::Variant2(Some(_), 0)] +//! //==>> specialize with `Variant2` +//! [None, 0] +//! [Some(_), 0] +//! //==>> specialize with `Some` +//! [_, 0] +//! //==>> specialize with `true` (say the type was `bool`) +//! [0] +//! //==>> specialize with `0` +//! [] //! ``` //! -//! and `p` is `[_, false]`, both `None` and `Some` constructors appear in the first -//! components of `P`. We will therefore try popping both constructors in turn: we -//! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]], -//! [false])` for the `None` constructor. The first case returns true, so we know that -//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched -//! before. +//! The function `specialize(c, p)` takes a value constructor `c` and a pattern `p`, and returns 0 +//! or more pattern-stacks. If `c` does not match the head constructor of `p`, it returns nothing; +//! otherwise if returns the fields of the constructor. This only returns more than one +//! pattern-stack if `p` has a pattern-only constructor. //! -//! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: -//! `U(P, p) := U(P, (r_1, p_2, .., p_n)) -//! || U(P, (r_2, p_2, .., p_n))` +//! - Specializing for the wrong constructor returns nothing //! -//! Modifications to the algorithm -//! ------------------------------ -//! The algorithm in the paper doesn't cover some of the special cases that arise in Rust, for -//! example uninhabited types and variable-length slice patterns. These are drawn attention to -//! throughout the code below. I'll make a quick note here about how exhaustive integer matching is -//! accounted for, though. +//! `specialize(None, Some(p0)) := []` //! -//! Exhaustive integer matching -//! --------------------------- -//! An integer type can be thought of as a (huge) sum type: 1 | 2 | 3 | ... -//! So to support exhaustive integer matching, we can make use of the logic in the paper for -//! OR-patterns. However, we obviously can't just treat ranges x..=y as individual sums, because -//! they are likely gigantic. So we instead treat ranges as constructors of the integers. This means -//! that we have a constructor *of* constructors (the integers themselves). We then need to work -//! through all the inductive step rules above, deriving how the ranges would be treated as -//! OR-patterns, and making sure that they're treated in the same way even when they're ranges. -//! There are really only four special cases here: -//! - When we match on a constructor that's actually a range, we have to treat it as if we would -//! an OR-pattern. -//! + It turns out that we can simply extend the case for single-value patterns in -//! `specialize` to either be *equal* to a value constructor, or *contained within* a range -//! constructor. -//! + When the pattern itself is a range, you just want to tell whether any of the values in -//! the pattern range coincide with values in the constructor range, which is precisely -//! intersection. -//! Since when encountering a range pattern for a value constructor, we also use inclusion, it -//! means that whenever the constructor is a value/range and the pattern is also a value/range, -//! we can simply use intersection to test usefulness. -//! - When we're testing for usefulness of a pattern and the pattern's first component is a -//! wildcard. -//! + If all the constructors appear in the matrix, we have a slight complication. By default, -//! the behaviour (i.e., a disjunction over specialised matrices for each constructor) is -//! invalid, because we want a disjunction over every *integer* in each range, not just a -//! disjunction over every range. This is a bit more tricky to deal with: essentially we need -//! to form equivalence classes of subranges of the constructor range for which the behaviour -//! of the matrix `P` and new pattern `p` are the same. This is described in more -//! detail in `Constructor::split`. -//! + If some constructors are missing from the matrix, it turns out we don't need to do -//! anything special (because we know none of the integers are actually wildcards: i.e., we -//! can't span wildcards using ranges). +//! - Specializing for the correct constructor returns a single row with the fields +//! +//! `specialize(Variant1, Variant1(p0, p1, p2)) := [[p0, p1, p2]]` +//! +//! `specialize(Foo{..}, Foo { bar: p0, baz: p1 }) := [[p0, p1]]` +//! +//! - For or-patterns, we specialize each branch and concatenate the results +//! +//! `specialize(c, p0 | p1) := specialize(c, p0) ++ specialize(c, p1)` +//! +//! - We treat the other pattern constructors lik big or-patterns of all the possibilities: +//! +//! `specialize(c, _) := specialize(c, Variant1(_) | Variant2(_, _) | ...)` +//! +//! `specialize(c, 1..=100) := specialize(c, 1 | ... | 100)` +//! +//! `specialize(c, [p0, .., p1]) := specialize(c, [p0, p1] | [p0, _, p1] | [p0, _, _, p1] | ...)` +//! +//! - If `c` is a pattern-only constructor, `specialize` is defined on a case-by-case basis. See +//! the discussion abount constructor splitting in [`super::deconstruct_pat`]. +//! +//! +//! We then extend this function to work with pattern-stacks as input, by acting on the first +//! column and keeping the other columns untouched. +//! +//! Specialization for the whole matrix is done in [`Matrix::specialize_constructor`]. Note that +//! or-patterns in the first column are expanded before being stored in the matrix. Specialization +//! for a single patstack is done from a combination of [`Constructor::is_covered_by`] and +//! [`PatStack::pop_head_constructor`]. The internals of how it's done mostly live in the +//! [`Fields`] struct. +//! +//! +//! # Computing usefulness +//! +//! We now have all we need to compute usefulness. The inputs to usefulness are a list of +//! pattern-stacks `p_1 ... p_n` (one per row), and a new pattern_stack `q`. The paper and this +//! file calls the list of patstacks a _matrix_. They must all have the same number of columns and +//! the patterns in a given column must all have the same type. `usefulness` returns a (possibly +//! empty) list of witnesses of usefulness. These witnesses will also be pattern-stacks. +//! +//! - base case: `n_columns == 0`. +//! Since a pattern-stack functions like a tuple of patterns, an empty one functions like the +//! unit type. Thus `q` is useful iff there are no rows above it, i.e. if `n == 0`. +//! +//! - inductive case: `n_columns > 0`. +//! We need a way to list the constructors we want to try. We will be more clever in the next +//! section but for now assume we list all value constructors for the type of the first column. +//! +//! - for each such ctor `c`: +//! +//! - for each `q'` returned by `specialize(c, q)`: +//! +//! - we compute `usefulness(specialize(c, p_1) ... specialize(c, p_n), q')` +//! +//! - for each witness found, we revert specialization by pushing the constructor `c` on top. +//! +//! - We return the concatenation of all the witnesses found, if any. +//! +//! Example: +//! ``` +//! [Some(true)] // p_1 +//! [None] // p_2 +//! [Some(_)] // q +//! //==>> try `None`: `specialize(None, q)` returns nothing +//! //==>> try `Some`: `specialize(Some, q)` returns a single row +//! [true] // p_1' +//! [_] // q' +//! //==>> try `true`: `specialize(true, q')` returns a single row +//! [] // p_1'' +//! [] // q'' +//! //==>> base case; `n != 0` so `q''` is not useful. +//! //==>> go back up a step +//! [true] // p_1' +//! [_] // q' +//! //==>> try `false`: `specialize(false, q')` returns a single row +//! [] // q'' +//! //==>> base case; `n == 0` so `q''` is useful. We return the single witness `[]` +//! witnesses: +//! [] +//! //==>> undo the specialization with `false` +//! witnesses: +//! [false] +//! //==>> undo the specialization with `Some` +//! witnesses: +//! [Some(false)] +//! //==>> we have tried all the constructors. The output is the single witness `[Some(false)]`. +//! ``` +//! +//! This computation is done in [`is_useful`]. In practice we don't care about the list of +//! witnesses when computing reachability; we only need to know whether any exist. We do keep the +//! witnesses when computing exhaustiveness to report them to the user. +//! +//! +//! # Making usefulness tractable: constructor splitting +//! +//! We're missing one last detail: which constructors do we list? Naively listing all value +//! constructors cannot work for types like `u64` or `&str`, so we need to be more clever. The +//! first obvious insight is that we only want to list constructors that are covered by the head +//! constructor of `q`. If it's a value constructor, we only try that one. If it's a pattern-only +//! constructor, we use the final clever idea for this algorithm: _constructor splitting_, where we +//! group together constructors that behave the same. +//! +//! The details are not necessary to understand this file, so we explain them in +//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function. use self::Usefulness::*; use self::WitnessPreference::*; @@ -1025,7 +1001,7 @@ fn is_useful<'p, 'tcx>( /// The arm of a match expression. #[derive(Clone, Copy)] crate struct MatchArm<'p, 'tcx> { - /// The pattern must have been lowered through `MatchVisitor::lower_pattern`. + /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`. crate pat: &'p super::Pat<'tcx>, crate hir_id: HirId, crate has_guard: bool, @@ -1043,7 +1019,8 @@ crate struct UsefulnessReport<'p, 'tcx> { /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which /// of its arms are reachable. /// -/// Note: the input patterns must have been lowered through `MatchVisitor::lower_pattern`. +/// Note: the input patterns must have been lowered through +/// `check_match::MatchVisitor::lower_pattern`. crate fn compute_match_usefulness<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, arms: &[MatchArm<'p, 'tcx>], From 53e03fb7c10f39229241fedc001a2c28ffb569e6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 20 Dec 2020 00:39:37 +0000 Subject: [PATCH 506/719] Make the special "missing patterns" constructor real --- .../src/thir/pattern/deconstruct_pat.rs | 108 ++++++++---------- .../src/thir/pattern/usefulness.rs | 13 ++- 2 files changed, 57 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index f71a4829e8a2..da7b0e625039 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -607,6 +607,9 @@ pub(super) enum Constructor<'tcx> { /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. NonExhaustive, + /// Stands for constructors that are not seen in the matrix, as explained in the documentation + /// for [`SplitWildcard`]. + Missing, /// Wildcard pattern. Wildcard, } @@ -758,8 +761,8 @@ impl<'tcx> Constructor<'tcx> { match (self, other) { // Wildcards cover anything (_, Wildcard) => true, - // Wildcards are only covered by wildcards - (Wildcard, _) => false, + // The missing ctors are not covered by anything in the matrix except wildcards. + (Missing | Wildcard, _) => false, (Single, Single) => true, (Variant(self_id), Variant(other_id)) => self_id == other_id, @@ -832,7 +835,7 @@ impl<'tcx> Constructor<'tcx> { .any(|other| slice.is_covered_by(other)), // This constructor is never covered by anything else NonExhaustive => false, - Str(..) | FloatRange(..) | Opaque | Wildcard => { + Str(..) | FloatRange(..) | Opaque | Missing | Wildcard => { span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self) } } @@ -1002,7 +1005,7 @@ impl<'tcx> SplitWildcard<'tcx> { } /// Iterate over the constructors for this type that are not present in the matrix. - fn iter_missing<'a, 'p>( + pub(super) fn iter_missing<'a, 'p>( &'a self, pcx: PatCtxt<'a, 'p, 'tcx>, ) -> impl Iterator> + Captures<'p> { @@ -1013,64 +1016,45 @@ impl<'tcx> SplitWildcard<'tcx> { /// top of the file, if any constructors are missing we can ignore the present ones. fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { if self.any_missing(pcx) { - // Some constructors are missing, thus we can specialize with the wildcard constructor, - // which will stand for those constructors that are missing, and matches the same rows - // as any of them (namely the wildcard rows). - return smallvec![Wildcard]; + // Some constructors are missing, thus we can specialize with the special `Missing` + // constructor, which stands for those constructors that are not seen in the matrix, + // and matches the same rows as any of them (namely the wildcard rows). See the top of + // the file for details. + // However, when all constructors are missing we can also specialize with the full + // `Wildcard` constructor. The difference will depend on what we want in diagnostics. + + // If some constructors are missing, we typically want to report those constructors, + // e.g.: + // ``` + // enum Direction { N, S, E, W } + // let Direction::N = ...; + // ``` + // we can report 3 witnesses: `S`, `E`, and `W`. + // + // However, if the user didn't actually specify a constructor + // in this arm, e.g., in + // ``` + // let x: (Direction, Direction, bool) = ...; + // let (_, _, false) = x; + // ``` + // we don't want to show all 16 possible witnesses `(, , + // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we + // prefer to report just a wildcard `_`. + // + // The exception is: if we are at the top-level, for example in an empty match, we + // sometimes prefer reporting the list of constructors instead of just `_`. + let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); + let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing { + Missing + } else { + Wildcard + }; + return smallvec![ctor]; } // All the constructors are present in the matrix, so we just go through them all. self.all_ctors } - - /// List the patterns corresponding to the missing constructors. In some cases, instead of - /// listing all constructors of a given type, we prefer to simply report a wildcard. - pub(super) fn report_missing_patterns<'p>( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - ) -> SmallVec<[Pat<'tcx>; 1]> { - // There are 2 ways we can report a witness here. - // Commonly, we can report all the "free" - // constructors as witnesses, e.g., if we have: - // - // ``` - // enum Direction { N, S, E, W } - // let Direction::N = ...; - // ``` - // - // we can report 3 witnesses: `S`, `E`, and `W`. - // - // However, there is a case where we don't want - // to do this and instead report a single `_` witness: - // if the user didn't actually specify a constructor - // in this arm, e.g., in - // - // ``` - // let x: (Direction, Direction, bool) = ...; - // let (_, _, false) = x; - // ``` - // - // we don't want to show all 16 possible witnesses - // `(, , true)` - we are - // satisfied with `(_, _, true)`. In this case, - // `used_ctors` is empty. - // The exception is: if we are at the top-level, for example in an empty match, we - // sometimes prefer reporting the list of constructors instead of just `_`. - let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); - if self.matrix_ctors.is_empty() && !report_when_all_missing { - // All constructors are unused. Report only a wildcard - // rather than each individual constructor. - smallvec![Pat::wildcard_from_ty(pcx.ty)] - } else { - // Construct for each missing constructor a "wild" version of this - // constructor, that matches everything that can be built with - // it. For example, if `ctor` is a `Constructor::Variant` for - // `Option::Some`, we get the pattern `Some(_)`. - self.iter_missing(pcx) - .map(|missing_ctor| Fields::wildcards(pcx, &missing_ctor).apply(pcx, missing_ctor)) - .collect() - } - } } /// Some fields need to be explicitly hidden away in certain cases; see the comment above the @@ -1211,9 +1195,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { } _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), }, - Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Wildcard => { - Fields::empty() - } + Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Missing + | Wildcard => Fields::empty(), }; debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); ret @@ -1297,9 +1280,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty), NonExhaustive => PatKind::Wild, + Wildcard => return Pat::wildcard_from_ty(pcx.ty), Opaque => bug!("we should not try to apply an opaque constructor"), - Wildcard => bug!( - "trying to apply a wildcard constructor; this should have been done in `apply_constructors`" + Missing => bug!( + "trying to apply the `Missing` constructor; this should have been done in `apply_constructors`" ), }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 424310842307..f74cb6ade477 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -784,10 +784,19 @@ impl<'tcx> Usefulness<'tcx> { ) -> Self { match self { UsefulWithWitness(witnesses) => { - let new_witnesses = if ctor.is_wildcard() { + let new_witnesses = if matches!(ctor, Constructor::Missing) { let mut split_wildcard = SplitWildcard::new(pcx); split_wildcard.split(pcx, matrix.head_ctors(pcx.cx)); - let new_patterns = split_wildcard.report_missing_patterns(pcx); + // Construct for each missing constructor a "wild" version of this + // constructor, that matches everything that can be built with + // it. For example, if `ctor` is a `Constructor::Variant` for + // `Option::Some`, we get the pattern `Some(_)`. + let new_patterns: Vec<_> = split_wildcard + .iter_missing(pcx) + .map(|missing_ctor| { + Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor) + }) + .collect(); witnesses .into_iter() .flat_map(|witness| { From 1c176d1150db4dbbc922c56abbc2cf0e8cf9abc1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 19 Dec 2020 07:11:00 +0000 Subject: [PATCH 507/719] Simplify field filtering --- .../src/thir/pattern/deconstruct_pat.rs | 120 ++++++++---------- .../src/thir/pattern/usefulness.rs | 2 +- 2 files changed, 57 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index da7b0e625039..357735d6c16c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1058,41 +1058,30 @@ impl<'tcx> SplitWildcard<'tcx> { } /// Some fields need to be explicitly hidden away in certain cases; see the comment above the -/// `Fields` struct. This struct represents such a potentially-hidden field. When a field is hidden -/// we still keep its type around. +/// `Fields` struct. This struct represents such a potentially-hidden field. #[derive(Debug, Copy, Clone)] pub(super) enum FilteredField<'p, 'tcx> { Kept(&'p Pat<'tcx>), - Hidden(Ty<'tcx>), + Hidden, } impl<'p, 'tcx> FilteredField<'p, 'tcx> { fn kept(self) -> Option<&'p Pat<'tcx>> { match self { FilteredField::Kept(p) => Some(p), - FilteredField::Hidden(_) => None, - } - } - - fn to_pattern(self) -> Pat<'tcx> { - match self { - FilteredField::Kept(p) => p.clone(), - FilteredField::Hidden(ty) => Pat::wildcard_from_ty(ty), + FilteredField::Hidden => None, } } } /// A value can be decomposed into a constructor applied to some fields. This struct represents /// those fields, generalized to allow patterns in each field. See also `Constructor`. +/// This is constructed from a constructor using [`Fields::wildcards()`]. /// /// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is -/// uninhabited. For that, we filter these fields out of the matrix. This is subtle because we -/// still need to have those fields back when going to/from a `Pat`. Most of this is handled -/// automatically in `Fields`, but when constructing or deconstructing `Fields` you need to be -/// careful. As a rule, when going to/from the matrix, use the filtered field list; when going -/// to/from `Pat`, use the full field list. -/// This filtering is uncommon in practice, because uninhabited fields are rarely used, so we avoid -/// it when possible to preserve performance. +/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically +/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rare used, +/// so we avoid it when possible to preserve performance. #[derive(Debug, Clone)] pub(super) enum Fields<'p, 'tcx> { /// Lists of patterns that don't contain any filtered fields. @@ -1101,21 +1090,19 @@ pub(super) enum Fields<'p, 'tcx> { /// have not measured if it really made a difference. Slice(&'p [Pat<'tcx>]), Vec(SmallVec<[&'p Pat<'tcx>; 2]>), - /// Patterns where some of the fields need to be hidden. `kept_count` caches the number of - /// non-hidden fields. + /// Patterns where some of the fields need to be hidden. For all intents and purposes we only + /// care about the non-hidden fields. We need to keep the real field index for those fields; + /// we're morally storing a `Vec<(usize, &Pat)>` but what we do is more convenient. + /// `len` counts the number of non-hidden fields Filtered { fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>, - kept_count: usize, + len: usize, }, } impl<'p, 'tcx> Fields<'p, 'tcx> { - fn empty() -> Self { - Fields::Slice(&[]) - } - - /// Construct a new `Fields` from the given pattern. Must not be used if the pattern is a field - /// of a struct/tuple/variant. + /// Internal use. Use `Fields::wildcards()` instead. + /// Must not be used if the pattern is a field of a struct/tuple/variant. fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self { Fields::Slice(std::slice::from_ref(pat)) } @@ -1160,7 +1147,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { if has_no_hidden_fields { Fields::wildcards_from_tys(cx, field_tys) } else { - let mut kept_count = 0; + let mut len = 0; let fields = variant .fields .iter() @@ -1175,14 +1162,14 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { // order not to reveal the uninhabitedness of the whole // variant. if is_uninhabited && (!is_visible || is_non_exhaustive) { - FilteredField::Hidden(ty) + FilteredField::Hidden } else { - kept_count += 1; + len += 1; FilteredField::Kept(wildcard_from_ty(ty)) } }) .collect(); - Fields::Filtered { fields, kept_count } + Fields::Filtered { fields, len } } } } @@ -1196,7 +1183,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), }, Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Missing - | Wildcard => Fields::empty(), + | Wildcard => Fields::Slice(&[]), }; debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); ret @@ -1218,14 +1205,16 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { /// `self`: `[false]` /// returns `Some(false)` pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Pat<'tcx> { - let mut subpatterns = self.all_patterns(); + let subpatterns_and_indices = self.patterns_and_indices(); + let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p).cloned(); let pat = match ctor { Single | Variant(_) => match pcx.ty.kind() { ty::Adt(..) | ty::Tuple(..) => { - let subpatterns = subpatterns - .enumerate() - .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) + // We want the real indices here. + let subpatterns = subpatterns_and_indices + .iter() + .map(|&(field, p)| FieldPat { field, pattern: p.clone() }) .collect(); if let ty::Adt(adt, substs) = pcx.ty.kind() { @@ -1290,39 +1279,42 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) } } - /// Returns the number of patterns from the viewpoint of match-checking, i.e. excluding hidden - /// fields. This is what we want in most cases in this file, the only exception being - /// conversion to/from `Pat`. + /// Returns the number of patterns. This is the same as the arity of the constructor used to + /// construct `self`. pub(super) fn len(&self) -> usize { match self { Fields::Slice(pats) => pats.len(), Fields::Vec(pats) => pats.len(), - Fields::Filtered { kept_count, .. } => *kept_count, + Fields::Filtered { len, .. } => *len, } } - /// Returns the complete list of patterns, including hidden fields. - fn all_patterns(self) -> impl Iterator> { - let pats: SmallVec<[_; 2]> = match self { - Fields::Slice(pats) => pats.iter().cloned().collect(), - Fields::Vec(pats) => pats.into_iter().cloned().collect(), - Fields::Filtered { fields, .. } => { - // We don't skip any fields here. - fields.into_iter().map(|p| p.to_pattern()).collect() + /// Returns the list of patterns along with the corresponding field indices. + fn patterns_and_indices(&self) -> SmallVec<[(Field, &'p Pat<'tcx>); 2]> { + match self { + Fields::Slice(pats) => { + pats.iter().enumerate().map(|(i, p)| (Field::new(i), p)).collect() } - }; - pats.into_iter() + Fields::Vec(pats) => { + pats.iter().copied().enumerate().map(|(i, p)| (Field::new(i), p)).collect() + } + Fields::Filtered { fields, .. } => { + // Indices must be relative to the full list of patterns + fields + .iter() + .enumerate() + .filter_map(|(i, p)| Some((Field::new(i), p.kept()?))) + .collect() + } + } } - /// Returns the filtered list of patterns, not including hidden fields. - pub(super) fn filtered_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> { + /// Returns the list of patterns. + pub(super) fn into_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> { match self { Fields::Slice(pats) => pats.iter().collect(), Fields::Vec(pats) => pats, - Fields::Filtered { fields, .. } => { - // We skip hidden fields here - fields.into_iter().filter_map(|p| p.kept()).collect() - } + Fields::Filtered { fields, .. } => fields.iter().filter_map(|p| p.kept()).collect(), } } @@ -1338,10 +1330,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { } /// Overrides some of the fields with the provided patterns. This is used when a pattern - /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start with a - /// `Fields` that is just one wildcard per field of the `Foo` struct, and override the entry - /// corresponding to `field1` with the pattern `Some(_)`. This is also used for slice patterns - /// for the same reason. + /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start + /// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the + /// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice + /// patterns for the same reason. fn replace_fields_indexed( &self, new_pats: impl IntoIterator)>, @@ -1369,8 +1361,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { fields } - /// Replaces contained fields with the given filtered list of patterns, e.g. taken from the - /// matrix. There must be `len()` patterns in `pats`. + /// Replaces contained fields with the given list of patterns. There must be `len()` patterns + /// in `pats`. pub(super) fn replace_fields( &self, cx: &MatchCheckCtxt<'p, 'tcx>, @@ -1379,7 +1371,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); match self { - Fields::Filtered { fields, kept_count } => { + Fields::Filtered { fields, len } => { let mut pats = pats.iter(); let mut fields = fields.clone(); for f in &mut fields { @@ -1388,7 +1380,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { *p = pats.next().unwrap(); } } - Fields::Filtered { fields, kept_count: *kept_count } + Fields::Filtered { fields, len: *len } } _ => Fields::Slice(pats), } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index f74cb6ade477..6c40abf3f20b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -447,7 +447,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. let mut new_fields = - ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).filtered_patterns(); + ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).into_patterns(); new_fields.extend_from_slice(&self.pats[1..]); PatStack::from_vec(new_fields) } From 85fdb34d3acf631d36d493a65d45b7bd7571e55d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 22 Dec 2020 06:09:54 +0000 Subject: [PATCH 508/719] Apply suggestions from code review Co-authored-by: varkor --- .../src/thir/pattern/deconstruct_pat.rs | 10 +++++----- .../src/thir/pattern/usefulness.rs | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 357735d6c16c..d79dd97a69a7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -451,7 +451,7 @@ impl Slice { /// /// A slice pattern `[x, .., y]` behaves like the infinite or-pattern `[x, y] | [x, _, y] | [x, _, /// _, y] | ...`. The corresponding value constructors are fixed-length array constructors above a -/// given minimum length. We obviously can't list all of this infinity of constructors. Thankfully, +/// given minimum length. We obviously can't list this infinitude of constructors. Thankfully, /// it turns out that for each finite set of slice patterns, all sufficiently large array lengths /// are equivalent. /// @@ -491,7 +491,7 @@ impl Slice { /// middle. This means that the set of witnesses for length `l >= 5` if equivalent to the set for /// any other `l' >= 5`: simply add or remove wildcards in the middle to convert between them. /// -/// This applies to any set of slice patterns: there will be a length `L` above which all length +/// This applies to any set of slice patterns: there will be a length `L` above which all lengths /// behave the same. This is exactly what we need for constructor splitting. Therefore a /// variable-length slice can be split into a variable-length slice of minimal length `L`, and many /// fixed-length slices of lengths `< L`. @@ -736,8 +736,8 @@ impl<'tcx> Constructor<'tcx> { // ranges check. IntRange(ctor_range) if !ctor_range.is_singleton() => { let mut split_range = SplitIntRange::new(ctor_range.clone()); - let intranges = ctors.filter_map(|ctor| ctor.as_int_range()); - split_range.split(intranges.cloned()); + let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range()); + split_range.split(int_ranges.cloned()); split_range.iter().map(IntRange).collect() } &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => { @@ -1080,7 +1080,7 @@ impl<'p, 'tcx> FilteredField<'p, 'tcx> { /// /// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is /// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically -/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rare used, +/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rarely used, /// so we avoid it when possible to preserve performance. #[derive(Debug, Clone)] pub(super) enum Fields<'p, 'tcx> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 6c40abf3f20b..803ffc0885e6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -19,7 +19,7 @@ //! //! The algorithm implemented here is a modified version of the one described in [this //! paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). We have however generalized -//! it to accomodate the variety of patterns that rust supports. We thus explain our version here, +//! it to accommodate the variety of patterns that Rust supports. We thus explain our version here, //! without being as rigorous. //! //! @@ -27,13 +27,13 @@ //! //! The core of the algorithm is the notion of "usefulness". A pattern `q` is said to be *useful* //! relative to another pattern `p` of the same type if there is a value that is matched by `q` and -//! not matched by `p`. This generalizes to many `p`s: `q` is useful wrt a list of patterns `p_1 .. -//! p_n` if there is a value that is matched by `q` and by none of the `p_i`. We write +//! not matched by `p`. This generalizes to many `p`s: `q` is useful w.r.t. a list of patterns +//! `p_1 .. p_n` if there is a value that is matched by `q` and by none of the `p_i`. We write //! `usefulness(p_1 .. p_n, q)` for a function that returns a list of such values. The aim of this //! file is to compute it efficiently. //! //! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it -//! is useful wrt the patterns above it: +//! is useful w.r.t. the patterns above it: //! ```rust //! match x { //! Some(_) => ..., @@ -44,8 +44,8 @@ //! ``` //! //! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_` -//! pattern is _not_ useful wrt the patterns in the match. The values returned by `usefulness` are -//! used to tell the user which values are missing. +//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness` +//! are used to tell the user which values are missing. //! ```rust //! match x { //! Some(0) => ..., @@ -102,7 +102,7 @@ //! //! Note: this constructors/fields distinction may not straightforwardly apply to every Rust type. //! For example a value of type `Rc` can't be deconstructed that way, and `&str` has an -//! infinity of constructors. There are also subtleties with visibility of fields and +//! infinitude of constructors. There are also subtleties with visibility of fields and //! uninhabitedness and various other things. The constructors idea can be extended to handle most //! of these subtleties though; caveats are documented where relevant throughout the code. //! @@ -184,7 +184,8 @@ //! //! `specialize(c, p0 | p1) := specialize(c, p0) ++ specialize(c, p1)` //! -//! - We treat the other pattern constructors lik big or-patterns of all the possibilities: +//! - We treat the other pattern constructors as if they were a large or-pattern of all the +//! possibilities: //! //! `specialize(c, _) := specialize(c, Variant1(_) | Variant2(_, _) | ...)` //! @@ -193,7 +194,7 @@ //! `specialize(c, [p0, .., p1]) := specialize(c, [p0, p1] | [p0, _, p1] | [p0, _, _, p1] | ...)` //! //! - If `c` is a pattern-only constructor, `specialize` is defined on a case-by-case basis. See -//! the discussion abount constructor splitting in [`super::deconstruct_pat`]. +//! the discussion about constructor splitting in [`super::deconstruct_pat`]. //! //! //! We then extend this function to work with pattern-stacks as input, by acting on the first From be23694622609c27d52042be6b506bf69848acbe Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 22 Dec 2020 11:28:17 +0000 Subject: [PATCH 509/719] Fix a comment --- compiler/rustc_mir_build/src/thir/pattern/usefulness.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 803ffc0885e6..83fee380ccce 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -852,10 +852,10 @@ enum WitnessPreference { /// We'll perform the following steps: /// 1. Start with an empty witness /// `Witness(vec![])` -/// 2. Push a witness `Some(_)` against the `None` -/// `Witness(vec![Some(_)])` -/// 3. Push a witness `true` against the `false` -/// `Witness(vec![Some(_), true])` +/// 2. Push a witness `true` against the `false` +/// `Witness(vec![true])` +/// 3. Push a witness `Some(_)` against the `None` +/// `Witness(vec![true, Some(_)])` /// 4. Apply the `Pair` constructor to the witnesses /// `Witness(vec![Pair(Some(_), true)])` /// From 57b5f8cbb922ecb53baf5bf619a72996f8f1fb46 Mon Sep 17 00:00:00 2001 From: PankajChaudhary5 Date: Tue, 22 Dec 2020 20:52:38 +0530 Subject: [PATCH 510/719] Improve the code quality by using matches macro --- compiler/rustc_middle/src/ty/sty.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 1af56972ad08..a955cca53cc8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1628,17 +1628,11 @@ impl RegionKind { } pub fn is_late_bound(&self) -> bool { - match *self { - ty::ReLateBound(..) => true, - _ => false, - } + matches!(*self, ty::ReLateBound(..)) } pub fn is_placeholder(&self) -> bool { - match *self { - ty::RePlaceholder(..) => true, - _ => false, - } + matches!(*self, ty::RePlaceholder(..)) } pub fn bound_at_or_above_binder(&self, index: DebruijnIndex) -> bool { From 0fd4f8febf8fc0edb94481f35c44c7e9e6e1ba87 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 18 Dec 2020 23:35:44 -0500 Subject: [PATCH 511/719] Add a custom `Res` type - Don't make rustc_resolve::Res public; use a new type alias instead --- .../passes/collect_intra_doc_links.rs | 279 ++++++++++-------- 1 file changed, 162 insertions(+), 117 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ea5bf94689bc..1f1fb9754cfe 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -10,17 +10,16 @@ use rustc_hir as hir; use rustc_hir::def::{ DefKind, Namespace::{self, *}, - PerNS, Res, + PerNS, }; use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_middle::ty; +use rustc_middle::{bug, ty}; use rustc_resolve::ParentScope; use rustc_session::lint::{ builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}, Lint, }; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::sym; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; @@ -28,6 +27,7 @@ use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; use std::cell::Cell; +use std::convert::{TryFrom, TryInto}; use std::mem; use std::ops::Range; @@ -61,6 +61,71 @@ impl<'a> From> for ErrorKind<'a> { } } +#[derive(Copy, Clone, Debug, Hash)] +enum Res { + Def(DefKind, DefId), + Primitive(PrimitiveType), +} + +type ResolveRes = rustc_hir::def::Res; + +impl Res { + fn descr(self) -> &'static str { + match self { + Res::Def(kind, id) => ResolveRes::Def(kind, id).descr(), + Res::Primitive(_) => "builtin type", + } + } + + fn article(self) -> &'static str { + match self { + Res::Def(kind, id) => ResolveRes::Def(kind, id).article(), + Res::Primitive(_) => "a", + } + } + + fn name(self, tcx: ty::TyCtxt<'_>) -> String { + match self { + Res::Def(_, id) => tcx.item_name(id).to_string(), + Res::Primitive(prim) => prim.as_str().to_string(), + } + } + + fn def_id(self) -> DefId { + self.opt_def_id().expect("called def_id() on a primitive") + } + + fn opt_def_id(self) -> Option { + match self { + Res::Def(_, id) => Some(id), + Res::Primitive(_) => None, + } + } + + fn as_hir_res(self) -> Option { + match self { + Res::Def(kind, id) => Some(rustc_hir::def::Res::Def(kind, id)), + // FIXME: maybe this should handle the subset of PrimitiveType that fits into hir::PrimTy? + Res::Primitive(_) => None, + } + } +} + +impl TryFrom for Res { + type Error = (); + + fn try_from(res: ResolveRes) -> Result { + use rustc_hir::def::Res::*; + match res { + Def(kind, id) => Ok(Res::Def(kind, id)), + PrimTy(prim) => Ok(Res::Primitive(PrimitiveType::from_hir(prim))), + // e.g. `#[derive]` + NonMacroAttr(..) | Err => Result::Err(()), + other => bug!("unrecognized res {:?}", other), + } + } +} + #[derive(Debug)] /// A link failed to resolve. enum ResolutionFailure<'a> { @@ -253,12 +318,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }) - .map(|(_, res)| res) - .unwrap_or(Res::Err); - if let Res::Err = ty_res { - return Err(no_res().into()); - } - let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); + .and_then(|(_, res)| res.try_into()) + .map_err(|()| no_res())?; + match ty_res { Res::Def(DefKind::Enum, did) => { if cx @@ -309,7 +371,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { /// lifetimes on `&'path` will work. fn resolve_primitive_associated_item( &self, - prim_ty: hir::PrimTy, + prim_ty: PrimitiveType, ns: Namespace, module_id: DefId, item_name: Symbol, @@ -317,7 +379,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; - PrimitiveType::from_hir(prim_ty) + prim_ty .impls(cx.tcx) .into_iter() .find_map(|&impl_| { @@ -336,21 +398,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) .map(|out| { ( - Res::PrimTy(prim_ty), - Some(format!("{}#{}.{}", prim_ty.name(), out, item_str)), + Res::Primitive(prim_ty), + Some(format!("{}#{}.{}", prim_ty.as_str(), out, item_str)), ) }) }) .ok_or_else(|| { debug!( "returning primitive error for {}::{} in {} namespace", - prim_ty.name(), + prim_ty.as_str(), item_name, ns.descr() ); ResolutionFailure::NotResolved { module_id, - partial_res: Some(Res::PrimTy(prim_ty)), + partial_res: Some(Res::Primitive(prim_ty)), unresolved: item_str.into(), } .into() @@ -377,19 +439,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { false, ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { - return Ok(res.map_id(|_| panic!("unexpected id"))); + return Ok(res.try_into().unwrap()); } } - if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { - return Ok(res.map_id(|_| panic!("unexpected id"))); + if let Some(&res) = resolver.all_macros().get(&Symbol::intern(path_str)) { + return Ok(res.try_into().unwrap()); } debug!("resolving {} as a macro in the module {:?}", path_str, module_id); if let Ok((_, res)) = resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id) { // don't resolve builtins like `#[derive]` - if let Res::Def(..) = res { - let res = res.map_id(|_| panic!("unexpected node_id")); + if let Ok(res) = res.try_into() { return Ok(res); } } @@ -408,14 +469,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { /// Associated items will never be resolved by this function. fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option { let result = self.cx.enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) + resolver + .resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) + .and_then(|(_, res)| res.try_into()) }); debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); - match result.map(|(_, res)| res) { + match result { // resolver doesn't know about true and false so we'll have to resolve them // manually as bool - Ok(Res::Err) | Err(()) => is_bool_value(path_str, ns).map(|(_, res)| res), - Ok(res) => Some(res.map_id(|_| panic!("unexpected node_id"))), + Err(()) => is_bool_value(path_str, ns), + Ok(res) => Some(res), } } @@ -444,13 +507,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return handle_variant(cx, res, extra_fragment); } // Not a trait item; just return what we found. - Res::PrimTy(ty) => { + Res::Primitive(ty) => { if extra_fragment.is_some() { return Err(ErrorKind::AnchorFailure( AnchorFailure::RustdocAnchorConflict(res), )); } - return Ok((res, Some(ty.name_str().to_owned()))); + return Ok((res, Some(ty.as_str().to_owned()))); } Res::Def(DefKind::Mod, _) => { return Ok((res, extra_fragment.clone())); @@ -483,7 +546,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // FIXME: are these both necessary? let ty_res = if let Some(ty_res) = resolve_primitive(&path_root, TypeNS) - .map(|(_, res)| res) .or_else(|| self.resolve_path(&path_root, TypeNS, module_id)) { ty_res @@ -502,7 +564,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; let res = match ty_res { - Res::PrimTy(prim) => Some( + Res::Primitive(prim) => Some( self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str), ), Res::Def( @@ -1068,9 +1130,9 @@ impl LinkCollector<'_, '_> { if matches!( disambiguator, None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) - ) && !matches!(res, Res::PrimTy(_)) + ) && !matches!(res, Res::Primitive(_)) { - if let Some((path, prim)) = resolve_primitive(path_str, TypeNS) { + if let Some(prim) = resolve_primitive(path_str, TypeNS) { // `prim@char` if matches!(disambiguator, Some(Disambiguator::Primitive)) { if fragment.is_some() { @@ -1085,7 +1147,7 @@ impl LinkCollector<'_, '_> { return None; } res = prim; - fragment = Some(path.as_str().to_string()); + fragment = Some(prim.name(self.cx.tcx)); } else { // `[char]` when a `char` module is in scope let candidates = vec![res, prim]; @@ -1111,8 +1173,8 @@ impl LinkCollector<'_, '_> { }; report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, &item, dox, &link_range, callback); }; - if let Res::PrimTy(..) = res { - match disambiguator { + match res { + Res::Primitive(_) => match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { Some(ItemLink { link: ori_link, link_text, did: None, fragment }) } @@ -1120,12 +1182,11 @@ impl LinkCollector<'_, '_> { report_mismatch(other, Disambiguator::Primitive); None } - } - } else { - debug!("intra-doc link to {} resolved to {:?}", path_str, res); + }, + Res::Def(kind, id) => { + debug!("intra-doc link to {} resolved to {:?}", path_str, res); - // Disallow e.g. linking to enums with `struct@` - if let Res::Def(kind, _) = res { + // Disallow e.g. linking to enums with `struct@` debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) { | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) @@ -1144,27 +1205,26 @@ impl LinkCollector<'_, '_> { return None; } } - } - // item can be non-local e.g. when using #[doc(primitive = "pointer")] - if let Some((src_id, dst_id)) = res - .opt_def_id() - .and_then(|def_id| def_id.as_local()) - .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id))) - { - use rustc_hir::def_id::LOCAL_CRATE; - - let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id); - let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id); - - if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src) - && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst) + // item can be non-local e.g. when using #[doc(primitive = "pointer")] + if let Some((src_id, dst_id)) = id + .as_local() + .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id))) { - privacy_error(cx, &item, &path_str, dox, link_range); + use rustc_hir::def_id::LOCAL_CRATE; + + let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id); + let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id); + + if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src) + && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst) + { + privacy_error(cx, &item, &path_str, dox, link_range); + } } + let id = clean::register_res(cx, rustc_hir::def::Res::Def(kind, id)); + Some(ItemLink { link: ori_link, link_text, did: Some(id), fragment }) } - let id = clean::register_res(cx, res); - Some(ItemLink { link: ori_link, link_text, did: Some(id), fragment }) } } @@ -1296,16 +1356,18 @@ impl LinkCollector<'_, '_> { .and_then(|(res, fragment)| { // Constructors are picked up in the type namespace. match res { - Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { + Res::Def(DefKind::Ctor(..), _) => { Err(ResolutionFailure::WrongNamespace(res, TypeNS)) } - _ => match (fragment, extra_fragment.clone()) { - (Some(fragment), Some(_)) => { - // Shouldn't happen but who knows? - Ok((res, Some(fragment))) + _ => { + match (fragment, extra_fragment.clone()) { + (Some(fragment), Some(_)) => { + // Shouldn't happen but who knows? + Ok((res, Some(fragment))) + } + (fragment, None) | (None, fragment) => Ok((res, fragment)), } - (fragment, None) | (None, fragment) => Ok((res, fragment)), - }, + } } }), }; @@ -1445,12 +1507,10 @@ impl Disambiguator { } } - /// WARNING: panics on `Res::Err` fn from_res(res: Res) -> Self { match res { Res::Def(kind, _) => Disambiguator::Kind(kind), - Res::PrimTy(_) => Disambiguator::Primitive, - _ => Disambiguator::Namespace(res.ns().expect("can't call `from_res` on Res::err")), + Res::Primitive(_) => Disambiguator::Primitive, } } @@ -1631,6 +1691,7 @@ fn resolution_failure( link_range: Option>, kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { + let tcx = collector.cx.tcx; report_diagnostic( collector.cx, BROKEN_INTRA_DOC_LINKS, @@ -1639,16 +1700,9 @@ fn resolution_failure( dox, &link_range, |diag, sp| { - let item = |res: Res| { - format!( - "the {} `{}`", - res.descr(), - collector.cx.tcx.item_name(res.def_id()).to_string() - ) - }; + let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),); let assoc_item_not_allowed = |res: Res| { - let def_id = res.def_id(); - let name = collector.cx.tcx.item_name(def_id); + let name = res.name(tcx); format!( "`{}` is {} {}, not a module or type, and cannot have associated items", name, @@ -1714,7 +1768,7 @@ fn resolution_failure( if let Some(module) = last_found_module { let note = if partial_res.is_some() { // Part of the link resolved; e.g. `std::io::nonexistent` - let module_name = collector.cx.tcx.item_name(module); + let module_name = tcx.item_name(module); format!("no item named `{}` in module `{}`", unresolved, module_name) } else { // None of the link resolved; e.g. `Notimported` @@ -1738,14 +1792,10 @@ fn resolution_failure( // Otherwise, it must be an associated item or variant let res = partial_res.expect("None case was handled by `last_found_module`"); - let diagnostic_name; - let (kind, name) = match res { - Res::Def(kind, def_id) => { - diagnostic_name = collector.cx.tcx.item_name(def_id).as_str(); - (Some(kind), &*diagnostic_name) - } - Res::PrimTy(ty) => (None, ty.name_str()), - _ => unreachable!("only ADTs and primitives are in scope at module level"), + let name = res.name(tcx); + let kind = match res { + Res::Def(kind, _) => Some(kind), + Res::Primitive(_) => None, }; let path_description = if let Some(kind) = kind { match kind { @@ -2003,50 +2053,45 @@ fn handle_variant( .parent(res.def_id()) .map(|parent| { let parent_def = Res::Def(DefKind::Enum, parent); - let variant = cx.tcx.expect_variant_res(res); + let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap()); (parent_def, Some(format!("variant.{}", variant.ident.name))) }) .ok_or_else(|| ResolutionFailure::NoParentItem.into()) } -// FIXME: At this point, this is basically a copy of the PrimitiveTypeTable -const PRIMITIVES: &[(Symbol, Res)] = &[ - (sym::u8, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U8))), - (sym::u16, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U16))), - (sym::u32, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U32))), - (sym::u64, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U64))), - (sym::u128, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U128))), - (sym::usize, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::Usize))), - (sym::i8, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I8))), - (sym::i16, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I16))), - (sym::i32, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I32))), - (sym::i64, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I64))), - (sym::i128, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I128))), - (sym::isize, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::Isize))), - (sym::f32, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F32))), - (sym::f64, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))), - (sym::str, Res::PrimTy(hir::PrimTy::Str)), - (sym::bool, Res::PrimTy(hir::PrimTy::Bool)), - (sym::char, Res::PrimTy(hir::PrimTy::Char)), -]; - /// Resolve a primitive type or value. -fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> { - is_bool_value(path_str, ns).or_else(|| { - if ns == TypeNS { - // FIXME: this should be replaced by a lookup in PrimitiveTypeTable - let maybe_primitive = Symbol::intern(path_str); - PRIMITIVES.iter().find(|x| x.0 == maybe_primitive).copied() - } else { - None - } - }) +fn resolve_primitive(path_str: &str, ns: Namespace) -> Option { + if ns != TypeNS { + return None; + } + use PrimitiveType::*; + let prim = match path_str { + "u8" => U8, + "u16" => U16, + "u32" => U32, + "u64" => U64, + "u128" => U128, + "usize" => Usize, + "i8" => I8, + "i16" => I16, + "i32" => I32, + "i64" => I64, + "i128" => I128, + "isize" => Isize, + "f32" => F32, + "f64" => F64, + "str" => Str, + "bool" | "true" | "false" => Bool, + "char" => Char, + _ => return None, + }; + Some(Res::Primitive(prim)) } /// Resolve a primitive value. -fn is_bool_value(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> { +fn is_bool_value(path_str: &str, ns: Namespace) -> Option { if ns == TypeNS && (path_str == "true" || path_str == "false") { - Some((sym::bool, Res::PrimTy(hir::PrimTy::Bool))) + Some(Res::Primitive(PrimitiveType::Bool)) } else { None } From 4092891a8f2ca5947d5312e1949ecf701a4f25de Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 19 Dec 2020 01:52:43 -0500 Subject: [PATCH 512/719] Fix intra-doc links for non-path primitives This does *not* currently work for associated items that are auto-implemented by the compiler (e.g. `never::eq`), because they aren't present in the source code. I plan to fix this in a follow-up PR. --- .../passes/collect_intra_doc_links.rs | 54 +++++++-------- .../rustdoc/intra-doc/non-path-primitives.rs | 66 +++++++++++++++++++ 2 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 src/test/rustdoc/intra-doc/non-path-primitives.rs diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1f1fb9754cfe..b8db0d5a4d63 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -475,9 +475,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }); debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); match result { - // resolver doesn't know about true and false so we'll have to resolve them + // resolver doesn't know about true, false, and types that aren't paths (e.g. `()`) // manually as bool - Err(()) => is_bool_value(path_str, ns), + Err(()) => resolve_primitive(path_str, ns), Ok(res) => Some(res), } } @@ -1020,7 +1020,7 @@ impl LinkCollector<'_, '_> { (link.trim(), None) }; - if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !".contains(ch))) { + if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*()[]&;".contains(ch))) { return None; } @@ -1108,9 +1108,8 @@ impl LinkCollector<'_, '_> { // Sanity check to make sure we don't have any angle brackets after stripping generics. assert!(!path_str.contains(['<', '>'].as_slice())); - // The link is not an intra-doc link if it still contains commas or spaces after - // stripping generics. - if path_str.contains([',', ' '].as_slice()) { + // The link is not an intra-doc link if it still contains spaces after stripping generics. + if path_str.contains(' ') { return None; } @@ -1476,8 +1475,11 @@ impl Disambiguator { ("!", DefKind::Macro(MacroKind::Bang)), ]; for &(suffix, kind) in &suffixes { - if link.ends_with(suffix) { - return Ok((Kind(kind), link.trim_end_matches(suffix))); + if let Some(link) = link.strip_suffix(suffix) { + // Avoid turning `!` or `()` into an empty string + if !link.is_empty() { + return Ok((Kind(kind), link)); + } } } Err(()) @@ -2066,37 +2068,37 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option { } use PrimitiveType::*; let prim = match path_str { - "u8" => U8, - "u16" => U16, - "u32" => U32, - "u64" => U64, - "u128" => U128, - "usize" => Usize, + "isize" => Isize, "i8" => I8, "i16" => I16, "i32" => I32, "i64" => I64, "i128" => I128, - "isize" => Isize, + "usize" => Usize, + "u8" => U8, + "u16" => U16, + "u32" => U32, + "u64" => U64, + "u128" => U128, "f32" => F32, "f64" => F64, - "str" => Str, - "bool" | "true" | "false" => Bool, "char" => Char, + "bool" | "true" | "false" => Bool, + "str" => Str, + "slice" | "&[]" | "[T]" => Slice, + "array" | "[]" | "[T;N]" => Array, + "tuple" | "(,)" => Tuple, + "unit" | "()" => Unit, + "pointer" | "*" | "*const" | "*mut" => RawPointer, + "reference" | "&" | "&mut" => Reference, + "fn" => Fn, + "never" | "!" => Never, _ => return None, }; + debug!("resolved primitives {:?}", prim); Some(Res::Primitive(prim)) } -/// Resolve a primitive value. -fn is_bool_value(path_str: &str, ns: Namespace) -> Option { - if ns == TypeNS && (path_str == "true" || path_str == "false") { - Some(Res::Primitive(PrimitiveType::Bool)) - } else { - None - } -} - fn strip_generics_from_path(path_str: &str) -> Result> { let mut stripped_segments = vec![]; let mut path = path_str.chars().peekable(); diff --git a/src/test/rustdoc/intra-doc/non-path-primitives.rs b/src/test/rustdoc/intra-doc/non-path-primitives.rs new file mode 100644 index 000000000000..83d081824ff5 --- /dev/null +++ b/src/test/rustdoc/intra-doc/non-path-primitives.rs @@ -0,0 +1,66 @@ +// ignore-tidy-linelength +#![crate_name = "foo"] +#![deny(broken_intra_doc_links)] + +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'X' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'Y' +//! [slice::rotate_left] +//! [X]([T]::rotate_left) +//! [Y](&[]::rotate_left) +// These don't work because markdown syntax doesn't allow it. +// [[T]::rotate_left] +//! [&[]::rotate_left] + +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'X' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'Y' +//! [array::map] +//! [X]([]::map) +//! [Y]([T;N]::map) +// These don't work because markdown syntax doesn't allow it. +// [Z]([T; N]::map) +//! [`[T; N]::map`] +//! [[]::map] +// [Z][] +// +// [Z]: [T; N]::map + +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*::is_null' +//! [pointer::is_null] +//! [*const::is_null] +//! [*mut::is_null] +//! [*::is_null] + +// FIXME: Associated items on some primitives aren't working, because the impls +// are part of the compiler instead of being part of the source code. + +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' 'unit' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' '()' +//! [unit] +//! [()] + +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'tuple' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'X' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' '(,)' +//! [tuple] +//! [X]((,)) +//! [(,)] + +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' 'reference' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&mut' +//! [reference] +//! [&] +//! [&mut] + +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.fn.html"]' 'fn' +//! [fn] + +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' 'never' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' '!' +//! [never] +//! [!] From 8842c1ccf33649f00e72a6f0be284919a847e69b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 19 Dec 2020 09:23:34 -0500 Subject: [PATCH 513/719] Fix new ambiguity in the standard library This caught several bugs where people expected `slice` to link to the primitive, but it linked to the module instead. This also uses `cfg_attr(bootstrap)` since the ambiguity only occurs when compiling with stage 1. --- library/std/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 39b0ca63301e..b7f9bea7c2af 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -175,7 +175,7 @@ //! [`str`]: prim@str //! [`mpsc`]: sync::mpsc //! [`std::cmp`]: cmp -//! [`std::slice`]: slice +//! [`std::slice`]: mod@slice //! [`use std::env`]: env/index.html //! [`use`]: ../book/ch07-02-defining-modules-to-control-scope-and-privacy.html //! [crates.io]: https://crates.io @@ -185,7 +185,8 @@ //! [other]: #what-is-in-the-standard-library-documentation //! [primitive types]: ../book/ch03-02-data-types.html //! [rust-discord]: https://discord.gg/rust-lang - +#![cfg_attr(not(bootstrap), doc = "[array]: prim@array")] +#![cfg_attr(not(bootstrap), doc = "[slice]: prim@slice")] #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))] #![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))] #![doc( From a448f88b6986208c0da97940c86189f78a865068 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 14 Dec 2020 13:50:59 -0500 Subject: [PATCH 514/719] Utilize PGO for rustc linux dist builds This implements support for applying PGO to the rustc compilation step (not standard library or any tooling, including rustdoc). Expanding PGO to more tools is not terribly difficult but will involve more work and greater CI time commitment. For the same reason of avoiding greater time commitment, this currently avoids implementing for platforms outside of x86_64-unknown-linux-gnu, though in practice it should be quite simple to extend over time to more platforms. The initial implementation is intentionally minimal here to avoid too much work investment before we start seeing wins for a subset of Rust users. The choice of workloads to profile here is somewhat arbitrary, but the general rationale was to aim for a small set that largely avoided time regressions on perf.rust-lang.org's full suite of crates. The set chosen is libcore, cargo (and its dependencies), and a few ad-hoc stress tests from perf.rlo. The stress tests are arguably the most controversial, but they benefit those cases (avoiding regressions) and do not really remove wins from other benchmarks. The primary next step after this PR lands is to implement support for PGO in LLVM. It is unclear whether we can afford a full LLVM rebuild in CI, though, so the approach taken there may need to be more staggered. rustc-only PGO seems well affordable on linux at least, giving us up to 20% wall time wins on some crates for 15 minutes of extra CI time (1 hour up from 45 minutes). The PGO data is uploaded to allow others to reuse it if attempting to reproduce the CI build or potentially, in the future, on other platforms where an off-by-one strategy is used for dist builds at minimal performance cost. --- src/bootstrap/builder.rs | 1 + src/bootstrap/compile.rs | 37 +++++++++- src/bootstrap/config.rs | 9 +++ src/bootstrap/dist.rs | 69 +++++++++++++++++++ src/bootstrap/flags.rs | 7 ++ .../host-x86_64/dist-x86_64-linux/Dockerfile | 9 ++- src/ci/pgo.sh | 47 +++++++++++++ src/tools/build-manifest/src/main.rs | 1 + 8 files changed, 176 insertions(+), 4 deletions(-) create mode 100755 src/ci/pgo.sh diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 9af79e20630d..05b1035d843f 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -471,6 +471,7 @@ impl<'a> Builder<'a> { dist::RustDev, dist::Extended, dist::BuildManifest, + dist::ReproducibleArtifacts, ), Kind::Install => describe!( install::Docs, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index fbebb26c7462..091bd2a1c5a1 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -501,6 +501,41 @@ impl Step for Rustc { let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build"); rustc_cargo(builder, &mut cargo, target); + if builder.config.rust_profile_use.is_some() + && builder.config.rust_profile_generate.is_some() + { + panic!("Cannot use and generate PGO profiles at the same time"); + } + + let is_collecting = if let Some(path) = &builder.config.rust_profile_generate { + if compiler.stage == 1 { + cargo.rustflag(&format!("-Cprofile-generate={}", path)); + // Apparently necessary to avoid overflowing the counters during + // a Cargo build profile + cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4"); + true + } else { + false + } + } else if let Some(path) = &builder.config.rust_profile_use { + if compiler.stage == 1 { + cargo.rustflag(&format!("-Cprofile-use={}", path)); + cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function"); + true + } else { + false + } + } else { + false + }; + if is_collecting { + // Ensure paths to Rust sources are relative, not absolute. + cargo.rustflag(&format!( + "-Cllvm-args=-static-func-strip-dirname-prefix={}", + builder.config.src.components().count() + )); + } + builder.info(&format!( "Building stage{} compiler artifacts ({} -> {})", compiler.stage, &compiler.host, target @@ -752,7 +787,7 @@ fn copy_codegen_backends_to_sysroot( // Here we're looking for the output dylib of the `CodegenBackend` step and // we're copying that into the `codegen-backends` folder. let dst = builder.sysroot_codegen_backends(target_compiler); - t!(fs::create_dir_all(&dst)); + t!(fs::create_dir_all(&dst), dst); if builder.config.dry_run { return; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index fb2c6d1f92a8..58dc5f7af791 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -133,6 +133,8 @@ pub struct Config { pub rust_thin_lto_import_instr_limit: Option, pub rust_remap_debuginfo: bool, pub rust_new_symbol_mangling: bool, + pub rust_profile_use: Option, + pub rust_profile_generate: Option, pub build: TargetSelection, pub hosts: Vec, @@ -494,6 +496,8 @@ struct Rust { llvm_libunwind: Option, control_flow_guard: Option, new_symbol_mangling: Option, + profile_generate: Option, + profile_use: Option, } /// TOML representation of how each build target is configured. @@ -871,6 +875,11 @@ impl Config { config.rust_codegen_units = rust.codegen_units.map(threads_from_config); config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); + config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use); + config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate); + } else { + config.rust_profile_use = flags.rust_profile_use; + config.rust_profile_generate = flags.rust_profile_generate; } if let Some(t) = toml.target { diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index b1bb97cf83ba..823f62fa4a39 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2664,3 +2664,72 @@ impl Step for BuildManifest { distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple)) } } + +/// Tarball containing artifacts necessary to reproduce the build of rustc. +/// +/// Currently this is the PGO profile data. +/// +/// Should not be considered stable by end users. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct ReproducibleArtifacts { + pub target: TargetSelection, +} + +impl Step for ReproducibleArtifacts { + type Output = Option; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("reproducible") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(ReproducibleArtifacts { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let name = pkgname(builder, "reproducible-artifacts"); + let tmp = tmpdir(builder); + + // Prepare the image. + let image = tmp.join("reproducible-artifacts-image"); + let _ = fs::remove_dir_all(&image); + + if let Some(path) = &builder.config.rust_profile_use { + builder.install(std::path::Path::new(path), &image, 0o644); + } else { + return None; + } + + // Prepare the overlay. + let overlay = tmp.join("reproducible-artifacts-overlay"); + let _ = fs::remove_dir_all(&overlay); + builder.create_dir(&overlay); + builder.create(&overlay.join("version"), &builder.rust_version()); + for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] { + builder.install(&builder.src.join(file), &overlay, 0o644); + } + + // Create the final tarball. + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=reproducible-artifacts installed.") + .arg("--image-dir") + .arg(&image) + .arg("--work-dir") + .arg(&tmpdir(builder)) + .arg("--output-dir") + .arg(&distdir(builder)) + .arg("--non-installed-overlay") + .arg(&overlay) + .arg(format!("--package-name={}-{}", name, self.target.triple)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=reproducible-artifacts"); + + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple))) + } +} diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 5a8096674c6d..d6a45f1c1707 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -68,6 +68,9 @@ pub struct Flags { pub deny_warnings: Option, pub llvm_skip_rebuild: Option, + + pub rust_profile_use: Option, + pub rust_profile_generate: Option, } pub enum Subcommand { @@ -219,6 +222,8 @@ To learn more about a subcommand, run `./x.py -h`", VALUE overrides the skip-rebuild option in config.toml.", "VALUE", ); + opts.optopt("", "rust-profile-generate", "rustc error format", "FORMAT"); + opts.optopt("", "rust-profile-use", "rustc error format", "FORMAT"); // We can't use getopt to parse the options until we have completed specifying which // options are valid, but under the current implementation, some options are conditional on @@ -674,6 +679,8 @@ Arguments: color: matches .opt_get_default("color", Color::Auto) .expect("`color` should be `always`, `never`, or `auto`"), + rust_profile_use: matches.opt_str("rust-profile-use"), + rust_profile_generate: matches.opt_str("rust-profile-generate"), } } } diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 14700aeea05a..d1b4bbf7fffe 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -85,6 +85,8 @@ ENV CC=clang CXX=clang++ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +ENV PGO_HOST=x86_64-unknown-linux-gnu + ENV HOSTS=x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ @@ -98,9 +100,10 @@ ENV RUST_CONFIGURE_ARGS \ --set llvm.thin-lto=true \ --set llvm.ninja=false \ --set rust.jemalloc -ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS \ - --include-default-paths \ - src/tools/build-manifest +ENV SCRIPT ../src/ci/pgo.sh python2.7 ../x.py dist \ + --host $HOSTS --target $HOSTS \ + --include-default-paths \ + src/tools/build-manifest ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh new file mode 100755 index 000000000000..13b8ca91f890 --- /dev/null +++ b/src/ci/pgo.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +set -euxo pipefail + +rm -rf /tmp/rustc-pgo + +python2.7 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \ + --stage 2 library/std --rust-profile-generate=/tmp/rustc-pgo + +./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \ + --crate-type=lib ../library/core/src/lib.rs + +# Download and build a single-file stress test benchmark on perf.rust-lang.org. +function pgo_perf_benchmark { + local PERF=e095f5021bf01cf3800f50b3a9f14a9683eb3e4e + local github_prefix=https://raw.githubusercontent.com/rust-lang/rustc-perf/$PERF + local name=$1 + curl -o /tmp/$name.rs $github_prefix/collector/benchmarks/$name/src/lib.rs + ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 --crate-type=lib /tmp/$name.rs +} + +pgo_perf_benchmark externs +pgo_perf_benchmark ctfe-stress-4 + +cp -pri ../src/tools/cargo /tmp/cargo + +# Build cargo (with some flags) +function pgo_cargo { + RUSTC=./build/$PGO_HOST/stage2/bin/rustc \ + ./build/$PGO_HOST/stage0/bin/cargo $@ \ + --manifest-path /tmp/cargo/Cargo.toml +} + +# Build a couple different variants of Cargo +CARGO_INCREMENTAL=1 pgo_cargo check +echo 'pub fn barbarbar() {}' >> /tmp/cargo/src/cargo/lib.rs +CARGO_INCREMENTAL=1 pgo_cargo check +touch /tmp/cargo/src/cargo/lib.rs +CARGO_INCREMENTAL=1 pgo_cargo check +pgo_cargo build --release + +# Merge the profile data we gathered +./build/$PGO_HOST/llvm/bin/llvm-profdata \ + merge -o /tmp/rustc-pgo.profdata /tmp/rustc-pgo + +# This produces the actual final set of artifacts. +$@ --rust-profile-use=/tmp/rustc-pgo.profdata diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 0462efaa9b00..73a4cbd07924 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -299,6 +299,7 @@ impl Builder { let mut package = |name, targets| self.package(name, &mut manifest.pkg, targets); package("rustc", HOSTS); package("rustc-dev", HOSTS); + package("reproducible-artifacts", HOSTS); package("rustc-docs", HOSTS); package("cargo", HOSTS); package("rust-mingw", MINGW); From f078f7cd64302b9a3f29e11387fd0f7a547fa60c Mon Sep 17 00:00:00 2001 From: pierwill Date: Tue, 22 Dec 2020 10:50:41 -0800 Subject: [PATCH 515/719] docs: Update rustc_middle::middle::region::ScopeTree This corrects the return type in docs for yield_in_source method. Closes #80287. --- compiler/rustc_middle/src/middle/region.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index d060549ca813..eb48198991c2 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -332,7 +332,7 @@ pub struct ScopeTree { pub struct YieldData { /// The `Span` of the yield. pub span: Span, - /// The number of expressions and patterns appearing before the `yield` in the body plus one. + /// The number of expressions and patterns appearing before the `yield` in the body, plus one. pub expr_and_pat_count: usize, pub source: hir::YieldSource, } @@ -449,9 +449,7 @@ impl ScopeTree { } /// Checks whether the given scope contains a `yield`. If so, - /// returns `Some((span, expr_count))` with the span of a yield we found and - /// the number of expressions and patterns appearing before the `yield` in the body + 1. - /// If there a are multiple yields in a scope, the one with the highest number is returned. + /// returns `Some(YieldData)`. If not, returns `None`. pub fn yield_in_scope(&self, scope: Scope) -> Option { self.yield_in_scope.get(&scope).cloned() } From 4f6be466fdec69dbf6ce768d41a43acf0fc3b47b Mon Sep 17 00:00:00 2001 From: ThePuzzlemaker Date: Mon, 21 Dec 2020 20:23:21 -0600 Subject: [PATCH 516/719] Suggest fn ptr rather than fn item and suggest to use `Fn` trait bounds rather than the unique closure type in E0121 This is a squash of the titular commit along with these minor commits: - Improve note - Improve note pt2 --- compiler/rustc_typeck/src/collect.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index bc6b2037c184..ebbcf6304b65 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1544,12 +1544,27 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { let mut diag = bad_placeholder_type(tcx, visitor.0); let ret_ty = fn_sig.output(); if ret_ty != tcx.ty_error() { - diag.span_suggestion( - ty.span, - "replace with the correct return type", - ret_ty.to_string(), - Applicability::MaybeIncorrect, - ); + if !ret_ty.is_closure() { + let ret_ty_str = match ret_ty.kind() { + // Suggest a function pointer return type instead of a unique function definition + // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid + // syntax) + ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(), + _ => ret_ty.to_string(), + }; + diag.span_suggestion( + ty.span, + "replace with the correct return type", + ret_ty_str, + Applicability::MaybeIncorrect, + ); + } else { + // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds + // to prevent the user from getting a papercut while trying to use the unique closure + // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`). + diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); + diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html"); + } } diag.emit(); ty::Binder::bind(fn_sig) From 5e6dc927f7a935874a08c2c3913f24295711d8f2 Mon Sep 17 00:00:00 2001 From: ThePuzzlemaker Date: Tue, 22 Dec 2020 13:25:37 -0600 Subject: [PATCH 517/719] Add regression test for #80179 --- src/test/ui/fn/issue-80179.rs | 27 +++++++++++++++++++++++++++ src/test/ui/fn/issue-80179.stderr | 21 +++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/test/ui/fn/issue-80179.rs create mode 100644 src/test/ui/fn/issue-80179.stderr diff --git a/src/test/ui/fn/issue-80179.rs b/src/test/ui/fn/issue-80179.rs new file mode 100644 index 000000000000..7609b1525cc9 --- /dev/null +++ b/src/test/ui/fn/issue-80179.rs @@ -0,0 +1,27 @@ +// Functions with a type placeholder `_` as the return type should +// show a function pointer suggestion when given a function item +// and suggest how to return closures correctly from a function. +// This is a regression test of #80179 + +fn returns_i32() -> i32 { + 0 +} + +fn returns_fn_ptr() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121] +//~| NOTE not allowed in type signatures +//~| HELP replace with the correct return type +//~| SUGGESTION fn() -> i32 + returns_i32 +} + +fn returns_closure() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121] +//~| NOTE not allowed in type signatures +//~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound +//~| NOTE for more information on `Fn` traits and closure types, see +// https://doc.rust-lang.org/book/ch13-01-closures.html + || 0 +} + +fn main() {} diff --git a/src/test/ui/fn/issue-80179.stderr b/src/test/ui/fn/issue-80179.stderr new file mode 100644 index 000000000000..63571e71b34f --- /dev/null +++ b/src/test/ui/fn/issue-80179.stderr @@ -0,0 +1,21 @@ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-80179.rs:10:24 + | +LL | fn returns_fn_ptr() -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `fn() -> i32` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-80179.rs:18:25 + | +LL | fn returns_closure() -> _ { + | ^ not allowed in type signatures + | + = help: consider using an `Fn`, `FnMut`, or `FnOnce` trait bound + = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0121`. From f6d6b0c96d86541e8fb69d133ff6222a038e5a53 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Thu, 26 Nov 2020 01:10:43 -0800 Subject: [PATCH 518/719] rustc_query_system: share previous graph data with current graph Reduce memory consumption by taking advantage of red/green algorithm properties to share the previous dependency graph's node data with the current graph instead of storing node data redundantly. Red nodes can share the `DepNode`, and green nodes can share the `DepNode` and `Fingerprint`. Edges will be shared when possible in a later change. --- .../rustc_query_system/src/dep_graph/graph.rs | 715 ++++++++++++------ .../rustc_query_system/src/dep_graph/query.rs | 8 +- 2 files changed, 503 insertions(+), 220 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index d2f0e39ea6bb..3bc93f63905b 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -68,7 +68,7 @@ struct DepGraphData { /// The new encoding of the dependency graph, optimized for red/green /// tracking. The `current` field is the dependency graph of only the /// current compilation session: We don't merge the previous dep-graph into - /// current one anymore. + /// current one anymore, but we do reference shared data to save space. current: CurrentDepGraph, /// The dep-graph from the previous compilation session. It contains all @@ -134,16 +134,44 @@ impl DepGraph { } pub fn query(&self) -> DepGraphQuery { - let data = self.data.as_ref().unwrap().current.data.lock(); - let nodes: Vec<_> = data.iter().map(|n| n.node).collect(); - let mut edges = Vec::new(); - for (from, edge_targets) in data.iter().map(|d| (d.node, &d.edges)) { - for &edge_target in edge_targets.iter() { - let to = data[edge_target].node; - edges.push((from, to)); + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; + let data = data.current.data.lock(); + + let node_count = data.hybrid_indices.len(); + + let edge_count = data.new.edges.iter().map(|e| e.len()).sum::() + + data.red.edges.iter().map(|e| e.len()).sum::() + + data.green.edges.iter().map(|e| e.len()).sum::(); + + let mut nodes = Vec::with_capacity(node_count); + let mut edges = Vec::with_capacity(edge_count); + + for (index, &hybrid_index) in data.hybrid_indices.iter_enumerated() { + let src = index.index(); + + match hybrid_index.into() { + HybridIndex::New(new_index) => { + let new = &data.new; + nodes.push(new.nodes[new_index]); + edges.extend(new.edges[new_index].iter().map(|dst| (src, dst.index()))); + } + HybridIndex::Red(red_index) => { + let red = &data.red; + nodes.push(previous.index_to_node(red.node_indices[red_index])); + edges.extend(red.edges[red_index].iter().map(|dst| (src, dst.index()))); + } + HybridIndex::Green(green_index) => { + let green = &data.green; + nodes.push(previous.index_to_node(green.node_indices[green_index])); + edges.extend(green.edges[green_index].iter().map(|dst| (src, dst.index()))); + } } } + debug_assert_eq!(nodes.len(), node_count); + debug_assert_eq!(edges.len(), edge_count); + DepGraphQuery::new(&nodes[..], &edges[..]) } @@ -212,7 +240,6 @@ impl DepGraph { phantom_data: PhantomData, }) }, - |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint), hash_result, ) } @@ -225,12 +252,6 @@ impl DepGraph { no_tcx: bool, task: fn(Ctxt, A) -> R, create_task: fn(DepNode) -> Option>, - finish_task_and_alloc_depnode: fn( - &CurrentDepGraph, - DepNode, - Fingerprint, - Option>, - ) -> DepNodeIndex, hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option, ) -> (R, DepNodeIndex) { if let Some(ref data) = self.data { @@ -249,39 +270,54 @@ impl DepGraph { K::with_deps(task_deps.as_ref(), || task(cx, arg)) }; - let current_fingerprint = hash_result(&mut hcx, &result); + let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); - let dep_node_index = finish_task_and_alloc_depnode( - &data.current, - key, - current_fingerprint.unwrap_or(Fingerprint::ZERO), - task_deps.map(|lock| lock.into_inner()), - ); + let current_fingerprint = hash_result(&mut hcx, &result); let print_status = cfg!(debug_assertions) && cx.debug_dep_tasks(); - // Determine the color of the new DepNode. - if let Some(prev_index) = data.previous.node_to_index_opt(&key) { - let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); - - let color = if let Some(current_fingerprint) = current_fingerprint { - if current_fingerprint == prev_fingerprint { + // Intern the new `DepNode`. + let dep_node_index = if let Some(prev_index) = data.previous.node_to_index_opt(&key) { + // Determine the color and index of the new `DepNode`. + let (color, dep_node_index) = if let Some(current_fingerprint) = current_fingerprint + { + if current_fingerprint == data.previous.fingerprint_by_index(prev_index) { if print_status { eprintln!("[task::green] {:?}", key); } - DepNodeColor::Green(dep_node_index) + + let dep_node_index = + data.current.intern_green_node(&data.previous, prev_index, edges); + + (DepNodeColor::Green(dep_node_index), dep_node_index) } else { if print_status { eprintln!("[task::red] {:?}", key); } - DepNodeColor::Red + + let dep_node_index = data.current.intern_red_node( + &data.previous, + prev_index, + edges, + current_fingerprint, + ); + + (DepNodeColor::Red, dep_node_index) } } else { if print_status { eprintln!("[task::unknown] {:?}", key); } + + let dep_node_index = data.current.intern_red_node( + &data.previous, + prev_index, + edges, + Fingerprint::ZERO, + ); + // Mark the node as Red if we can't hash the result - DepNodeColor::Red + (DepNodeColor::Red, dep_node_index) }; debug_assert!( @@ -292,9 +328,19 @@ impl DepGraph { ); data.colors.insert(prev_index, color); - } else if print_status { - eprintln!("[task::new] {:?}", key); - } + dep_node_index + } else { + if print_status { + eprintln!("[task::new] {:?}", key); + } + + data.current.intern_node( + &data.previous, + key, + edges, + current_fingerprint.unwrap_or(Fingerprint::ZERO), + ) + }; (result, dep_node_index) } else { @@ -308,13 +354,36 @@ impl DepGraph { where OP: FnOnce() -> R, { + debug_assert!(!dep_kind.is_eval_always()); + if let Some(ref data) = self.data { let task_deps = Lock::new(TaskDeps::default()); - let result = K::with_deps(Some(&task_deps), op); let task_deps = task_deps.into_inner(); - let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps); + // The dep node indices are hashed here instead of hashing the dep nodes of the + // dependencies. These indices may refer to different nodes per session, but this isn't + // a problem here because we that ensure the final dep node hash is per session only by + // combining it with the per session random number `anon_id_seed`. This hash only need + // to map the dependencies to a single value on a per session basis. + let mut hasher = StableHasher::new(); + task_deps.reads.hash(&mut hasher); + + let target_dep_node = DepNode { + kind: dep_kind, + // Fingerprint::combine() is faster than sending Fingerprint + // through the StableHasher (at least as long as StableHasher + // is so slow). + hash: data.current.anon_id_seed.combine(hasher.finish()).into(), + }; + + let dep_node_index = data.current.intern_node( + &data.previous, + target_dep_node, + task_deps.reads, + Fingerprint::ZERO, + ); + (result, dep_node_index) } else { (op(), self.next_virtual_depnode_index()) @@ -331,69 +400,104 @@ impl DepGraph { task: fn(Ctxt, A) -> R, hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option, ) -> (R, DepNodeIndex) { - self.with_task_impl( - key, - cx, - arg, - false, - task, - |_| None, - |data, key, fingerprint, _| data.alloc_node(key, smallvec![], fingerprint), - hash_result, - ) - } - - #[inline] - pub fn read(&self, v: DepNode) { - if let Some(ref data) = self.data { - let map = data.current.node_to_node_index.get_shard_by_value(&v).lock(); - if let Some(dep_node_index) = map.get(&v).copied() { - std::mem::drop(map); - data.read_index(dep_node_index); - } else { - panic!("DepKind {:?} should be pre-allocated but isn't.", v.kind) - } - } + self.with_task_impl(key, cx, arg, false, task, |_| None, hash_result) } #[inline] pub fn read_index(&self, dep_node_index: DepNodeIndex) { if let Some(ref data) = self.data { - data.read_index(dep_node_index); + K::read_deps(|task_deps| { + if let Some(task_deps) = task_deps { + let mut task_deps = task_deps.lock(); + let task_deps = &mut *task_deps; + if cfg!(debug_assertions) { + data.current.total_read_count.fetch_add(1, Relaxed); + } + + // As long as we only have a low number of reads we can avoid doing a hash + // insert and potentially allocating/reallocating the hashmap + let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { + task_deps.reads.iter().all(|other| *other != dep_node_index) + } else { + task_deps.read_set.insert(dep_node_index) + }; + if new_read { + task_deps.reads.push(dep_node_index); + if task_deps.reads.len() == TASK_DEPS_READS_CAP { + // Fill `read_set` with what we have so far so we can use the hashset + // next time + task_deps.read_set.extend(task_deps.reads.iter().copied()); + } + + #[cfg(debug_assertions)] + { + if let Some(target) = task_deps.node { + if let Some(ref forbidden_edge) = data.current.forbidden_edge { + let src = self.dep_node_of(dep_node_index); + if forbidden_edge.test(&src, &target) { + panic!("forbidden edge {:?} -> {:?} created", src, target) + } + } + } + } + } else if cfg!(debug_assertions) { + data.current.total_duplicate_read_count.fetch_add(1, Relaxed); + } + } + }) } } #[inline] pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { - self.data - .as_ref() - .unwrap() - .current - .node_to_node_index - .get_shard_by_value(dep_node) - .lock() - .get(dep_node) - .cloned() - .unwrap() + self.dep_node_index_of_opt(dep_node).unwrap() + } + + #[inline] + pub fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option { + let data = self.data.as_ref().unwrap(); + let current = &data.current; + + if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { + current.prev_index_to_index.lock()[prev_index] + } else { + current.new_node_to_index.get_shard_by_value(dep_node).lock().get(dep_node).copied() + } } #[inline] pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { - if let Some(ref data) = self.data { - data.current - .node_to_node_index - .get_shard_by_value(&dep_node) - .lock() - .contains_key(dep_node) - } else { - false + self.data.is_some() && self.dep_node_index_of_opt(dep_node).is_some() + } + + #[inline] + pub fn dep_node_of(&self, dep_node_index: DepNodeIndex) -> DepNode { + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; + let data = data.current.data.lock(); + + match data.hybrid_indices[dep_node_index].into() { + HybridIndex::New(new_index) => data.new.nodes[new_index], + HybridIndex::Red(red_index) => previous.index_to_node(data.red.node_indices[red_index]), + HybridIndex::Green(green_index) => { + previous.index_to_node(data.green.node_indices[green_index]) + } } } #[inline] pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { - let data = self.data.as_ref().expect("dep graph enabled").current.data.lock(); - data[dep_node_index].fingerprint + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; + let data = data.current.data.lock(); + + match data.hybrid_indices[dep_node_index].into() { + HybridIndex::New(new_index) => data.new.fingerprints[new_index], + HybridIndex::Red(red_index) => data.red.fingerprints[red_index], + HybridIndex::Green(green_index) => { + previous.fingerprint_by_index(data.green.node_indices[green_index]) + } + } } pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { @@ -444,29 +548,62 @@ impl DepGraph { } pub fn serialize(&self) -> SerializedDepGraph { - let data = self.data.as_ref().unwrap().current.data.lock(); + type SDNI = SerializedDepNodeIndex; - let fingerprints: IndexVec = - data.iter().map(|d| d.fingerprint).collect(); - let nodes: IndexVec = data.iter().map(|d| d.node).collect(); + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; + let data = data.current.data.lock(); - let total_edge_count: usize = data.iter().map(|d| d.edges.len()).sum(); + let node_count = data.hybrid_indices.len(); - let mut edge_list_indices = IndexVec::with_capacity(nodes.len()); - let mut edge_list_data = Vec::with_capacity(total_edge_count); + let edge_count = data.new.edges.iter().map(|e| e.len()).sum::() + + data.red.edges.iter().map(|e| e.len()).sum::() + + data.green.edges.iter().map(|e| e.len()).sum::(); - for (current_dep_node_index, edges) in data.iter_enumerated().map(|(i, d)| (i, &d.edges)) { + let mut nodes = IndexVec::with_capacity(node_count); + let mut fingerprints = IndexVec::with_capacity(node_count); + let mut edge_list_indices = IndexVec::with_capacity(node_count); + let mut edge_list_data = Vec::with_capacity(edge_count); + + fn add_edges<'a, I: Iterator>( + edge_list_indices: &mut IndexVec, + edge_list_data: &mut Vec, + iter: I, + ) { let start = edge_list_data.len() as u32; - // This should really just be a memcpy :/ - edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index()))); + edge_list_data.extend(iter.map(|i| SDNI::new(i.index()))); let end = edge_list_data.len() as u32; - - debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len()); edge_list_indices.push((start, end)); + }; + + for &hybrid_index in data.hybrid_indices.iter() { + match hybrid_index.into() { + HybridIndex::New(i) => { + let new = &data.new; + nodes.push(new.nodes[i]); + fingerprints.push(new.fingerprints[i]); + add_edges(&mut edge_list_indices, &mut edge_list_data, new.edges[i].iter()); + } + HybridIndex::Red(i) => { + let red = &data.red; + nodes.push(previous.index_to_node(red.node_indices[i])); + fingerprints.push(red.fingerprints[i]); + add_edges(&mut edge_list_indices, &mut edge_list_data, red.edges[i].iter()); + } + HybridIndex::Green(i) => { + let green = &data.green; + nodes.push(previous.index_to_node(green.node_indices[i])); + fingerprints.push(previous.fingerprint_by_index(green.node_indices[i])); + add_edges(&mut edge_list_indices, &mut edge_list_data, green.edges[i].iter()); + } + } } + debug_assert_eq!(nodes.len(), node_count); + debug_assert_eq!(fingerprints.len(), node_count); + debug_assert_eq!(edge_list_indices.len(), node_count); + debug_assert_eq!(edge_list_data.len(), edge_count); debug_assert!(edge_list_data.len() <= u32::MAX as usize); - debug_assert_eq!(edge_list_data.len(), total_edge_count); SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data } } @@ -540,14 +677,7 @@ impl DepGraph { #[cfg(not(parallel_compiler))] { - debug_assert!( - !data - .current - .node_to_node_index - .get_shard_by_value(dep_node) - .lock() - .contains_key(dep_node) - ); + debug_assert!(!self.dep_node_exists(dep_node)); debug_assert!(data.colors.get(prev_dep_node_index).is_none()); } @@ -690,13 +820,9 @@ impl DepGraph { // There may be multiple threads trying to mark the same dep node green concurrently let dep_node_index = { - // Copy the fingerprint from the previous graph, - // so we don't have to recompute it - let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index); - // We allocating an entry for the node in the current dependency graph and // adding all the appropriate edges imported from the previous graph - data.current.intern_node(*dep_node, current_deps, fingerprint) + data.current.intern_green_node(&data.previous, prev_dep_node_index, current_deps) }; // ... emitting any stored diagnostic ... @@ -871,31 +997,181 @@ pub struct WorkProduct { pub saved_file: Option, } -#[derive(Clone)] -struct DepNodeData { - node: DepNode, - edges: EdgesVec, - fingerprint: Fingerprint, +// The maximum value of the follow index types leaves the upper two bits unused +// so that we can store multiple index types in `CompressedHybridIndex`, and use +// those bits to encode which index type it contains. + +// Index type for `NewDepNodeData`. +rustc_index::newtype_index! { + struct NewDepNodeIndex { + MAX = 0x7FFF_FFFF + } } -/// `CurrentDepGraph` stores the dependency graph for the current session. -/// It will be populated as we run queries or tasks. +// Index type for `RedDepNodeData`. +rustc_index::newtype_index! { + struct RedDepNodeIndex { + MAX = 0x7FFF_FFFF + } +} + +// Index type for `GreenDepNodeData`. +rustc_index::newtype_index! { + struct GreenDepNodeIndex { + MAX = 0x7FFF_FFFF + } +} + +/// Compressed representation of `HybridIndex` enum. Bits unused by the +/// contained index types are used to encode which index type it contains. +#[derive(Copy, Clone)] +struct CompressedHybridIndex(u32); + +impl CompressedHybridIndex { + const NEW_TAG: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000; + const RED_TAG: u32 = 0b0100_0000_0000_0000_0000_0000_0000_0000; + const GREEN_TAG: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000; + + const TAG_MASK: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000; + const INDEX_MASK: u32 = !Self::TAG_MASK; +} + +impl From for CompressedHybridIndex { + #[inline] + fn from(index: NewDepNodeIndex) -> Self { + CompressedHybridIndex(Self::NEW_TAG | index.as_u32()) + } +} + +impl From for CompressedHybridIndex { + #[inline] + fn from(index: RedDepNodeIndex) -> Self { + CompressedHybridIndex(Self::RED_TAG | index.as_u32()) + } +} + +impl From for CompressedHybridIndex { + #[inline] + fn from(index: GreenDepNodeIndex) -> Self { + CompressedHybridIndex(Self::GREEN_TAG | index.as_u32()) + } +} + +/// Contains an index into one of several node data collections. Elsewhere, we +/// store `CompressedHyridIndex` instead of this to save space, but convert to +/// this type during processing to take advantage of the enum match ergonomics. +enum HybridIndex { + New(NewDepNodeIndex), + Red(RedDepNodeIndex), + Green(GreenDepNodeIndex), +} + +impl From for HybridIndex { + #[inline] + fn from(hybrid_index: CompressedHybridIndex) -> Self { + let index = hybrid_index.0 & CompressedHybridIndex::INDEX_MASK; + + match hybrid_index.0 & CompressedHybridIndex::TAG_MASK { + CompressedHybridIndex::NEW_TAG => HybridIndex::New(NewDepNodeIndex::from_u32(index)), + CompressedHybridIndex::RED_TAG => HybridIndex::Red(RedDepNodeIndex::from_u32(index)), + CompressedHybridIndex::GREEN_TAG => { + HybridIndex::Green(GreenDepNodeIndex::from_u32(index)) + } + _ => unreachable!(), + } + } +} + +/// Data for nodes in the current graph, divided into different collections +/// based on their presence in the previous graph, and if present, their color. +/// We divide nodes this way because different types of nodes are able to share +/// more or less data with the previous graph. /// -/// The nodes in it are identified by an index (`DepNodeIndex`). -/// The data for each node is stored in its `DepNodeData`, found in the `data` field. +/// Node data is stored in parallel vectors to eliminate the padding between +/// elements that would be needed to satisfy alignment requirements of the +/// structure that would contain all of a node's data. We could group tightly +/// packing subsets of node data together and use fewer vectors, but for +/// consistency's sake, we use separate vectors for each piece of data. +struct DepNodeData { + /// Data for nodes not in previous graph. + new: NewDepNodeData, + + /// Data for nodes in previous graph that have been marked red. + red: RedDepNodeData, + + /// Data for nodes in previous graph that have been marked green. + green: GreenDepNodeData, + + /// Mapping from `DepNodeIndex` to an index into a collection above. + /// Indicates which of the above collections contains a node's data. + /// + /// This collection is wasteful in time and space during incr-full builds, + /// because for those, all nodes are new. However, the waste is relatively + /// small, and the maintenance cost of avoiding using this for incr-full + /// builds is somewhat high and prone to bugginess. It does not seem worth + /// it at the time of this writing, but we may want to revisit the idea. + hybrid_indices: IndexVec, +} + +/// Data for nodes not in previous graph. Since we cannot share any data with +/// the previous graph, so we must store all of such a node's data here. +struct NewDepNodeData { + nodes: IndexVec>, + edges: IndexVec, + fingerprints: IndexVec, +} + +/// Data for nodes in previous graph that have been marked red. We can share the +/// dep node with the previous graph, but the edges may be different, and the +/// fingerprint is known to be different, so we store the latter two directly. +struct RedDepNodeData { + node_indices: IndexVec, + edges: IndexVec, + fingerprints: IndexVec, +} + +/// Data for nodes in previous graph that have been marked green. We can share +/// both the dep node and the fingerprint with previous graph, but the edges may +/// be different, so we store the latter directly. +struct GreenDepNodeData { + node_indices: IndexVec, + edges: IndexVec, +} + +/// `CurrentDepGraph` stores the dependency graph for the current session. It +/// will be populated as we run queries or tasks. We never remove nodes from the +/// graph: they are only added. /// -/// We never remove nodes from the graph: they are only added. +/// The nodes in it are identified by a `DepNodeIndex`. Internally, this maps to +/// a `HybridIndex`, which identifies which collection in the `data` field +/// contains a node's data. Which collection is used for a node depends on +/// whether the node was present in the `PreviousDepGraph`, and if so, the color +/// of the node. Each type of node can share more or less data with the previous +/// graph. When possible, we can store just the index of the node in the +/// previous graph, rather than duplicating its data in our own collections. +/// This is important, because these graph structures are some of the largest in +/// the compiler. /// -/// This struct uses two locks internally. The `data` and `node_to_node_index` fields are -/// locked separately. Operations that take a `DepNodeIndex` typically just access -/// the data field. +/// For the same reason, we also avoid storing `DepNode`s more than once as map +/// keys. The `new_node_to_index` map only contains nodes not in the previous +/// graph, and we map nodes in the previous graph to indices via a two-step +/// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`, +/// and the `prev_index_to_index` vector (which is more compact and faster than +/// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`. /// -/// The only operation that must manipulate both locks is adding new nodes, in which case -/// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted, -/// acquire the lock on `data.` +/// This struct uses three locks internally. The `data`, `new_node_to_index`, +/// and `prev_index_to_index` fields are locked separately. Operations that take +/// a `DepNodeIndex` typically just access the `data` field. +/// +/// We only need to manipulate at most two locks simultaneously: +/// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. The +/// only operation that must manipulate both locks is adding new nodes, in which +/// case we first acquire the `new_node_to_index` or `prev_index_to_index` lock +/// and then, once a new node is to be inserted, acquire the lock on `data`. pub(super) struct CurrentDepGraph { - data: Lock>>, - node_to_node_index: Sharded, DepNodeIndex>>, + data: Lock>, + new_node_to_index: Sharded, DepNodeIndex>>, + prev_index_to_index: Lock>>, /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. @@ -944,18 +1220,46 @@ impl CurrentDepGraph { // Pre-allocate the dep node structures. We over-allocate a little so // that we hopefully don't have to re-allocate during this compilation - // session. The over-allocation is 2% plus a small constant to account - // for the fact that in very small crates 2% might not be enough. - let new_node_count_estimate = (prev_graph_node_count * 102) / 100 + 200; + // session. The over-allocation for new nodes is 2% plus a small + // constant to account for the fact that in very small crates 2% might + // not be enough. The allocation for red and green node data doesn't + // include a constant, as we don't want to allocate anything for these + // structures during full incremental builds, where they aren't used. + let new_node_count_estimate = (prev_graph_node_count * 2) / 100 + 200; + let red_node_count_estimate = (prev_graph_node_count * 3) / 100; + let green_node_count_estimate = (prev_graph_node_count * 95) / 100; + let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate; + + // We store a large collection of these in `prev_index_to_index` during + // non-full incremental builds, and want to ensure that the element size + // doesn't inadvertently increase. + static_assert_size!(Option, 4); CurrentDepGraph { - data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)), - node_to_node_index: Sharded::new(|| { + data: Lock::new(DepNodeData { + new: NewDepNodeData { + nodes: IndexVec::with_capacity(new_node_count_estimate), + edges: IndexVec::with_capacity(new_node_count_estimate), + fingerprints: IndexVec::with_capacity(new_node_count_estimate), + }, + red: RedDepNodeData { + node_indices: IndexVec::with_capacity(red_node_count_estimate), + edges: IndexVec::with_capacity(red_node_count_estimate), + fingerprints: IndexVec::with_capacity(red_node_count_estimate), + }, + green: GreenDepNodeData { + node_indices: IndexVec::with_capacity(green_node_count_estimate), + edges: IndexVec::with_capacity(green_node_count_estimate), + }, + hybrid_indices: IndexVec::with_capacity(total_node_count_estimate), + }), + new_node_to_index: Sharded::new(|| { FxHashMap::with_capacity_and_hasher( new_node_count_estimate / sharded::SHARDS, Default::default(), ) }), + prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)), anon_id_seed: stable_hasher.finish(), forbidden_edge, total_read_count: AtomicU64::new(0), @@ -963,113 +1267,92 @@ impl CurrentDepGraph { } } - fn complete_task( - &self, - node: DepNode, - task_deps: TaskDeps, - fingerprint: Fingerprint, - ) -> DepNodeIndex { - self.alloc_node(node, task_deps.reads, fingerprint) - } - - fn complete_anon_task(&self, kind: K, task_deps: TaskDeps) -> DepNodeIndex { - debug_assert!(!kind.is_eval_always()); - - let mut hasher = StableHasher::new(); - - // The dep node indices are hashed here instead of hashing the dep nodes of the - // dependencies. These indices may refer to different nodes per session, but this isn't - // a problem here because we that ensure the final dep node hash is per session only by - // combining it with the per session random number `anon_id_seed`. This hash only need - // to map the dependencies to a single value on a per session basis. - task_deps.reads.hash(&mut hasher); - - let target_dep_node = DepNode { - kind, - - // Fingerprint::combine() is faster than sending Fingerprint - // through the StableHasher (at least as long as StableHasher - // is so slow). - hash: self.anon_id_seed.combine(hasher.finish()).into(), - }; - - self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO) - } - - fn alloc_node( + fn intern_node( &self, + prev_graph: &PreviousDepGraph, dep_node: DepNode, edges: EdgesVec, fingerprint: Fingerprint, ) -> DepNodeIndex { debug_assert!( - !self.node_to_node_index.get_shard_by_value(&dep_node).lock().contains_key(&dep_node) + prev_graph.node_to_index_opt(&dep_node).is_none(), + "node in previous graph should be interned using \ + `intern_red_node` or `intern_green_node`" ); - self.intern_node(dep_node, edges, fingerprint) - } - fn intern_node( - &self, - dep_node: DepNode, - edges: EdgesVec, - fingerprint: Fingerprint, - ) -> DepNodeIndex { - match self.node_to_node_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { + match self.new_node_to_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { let mut data = self.data.lock(); - let dep_node_index = DepNodeIndex::new(data.len()); - data.push(DepNodeData { node: dep_node, edges, fingerprint }); + let new_index = data.new.nodes.push(dep_node); + data.new.edges.push(edges); + data.new.fingerprints.push(fingerprint); + let dep_node_index = data.hybrid_indices.push(new_index.into()); entry.insert(dep_node_index); dep_node_index } } } -} -impl DepGraphData { - #[inline(never)] - fn read_index(&self, source: DepNodeIndex) { - K::read_deps(|task_deps| { - if let Some(task_deps) = task_deps { - let mut task_deps = task_deps.lock(); - let task_deps = &mut *task_deps; - if cfg!(debug_assertions) { - self.current.total_read_count.fetch_add(1, Relaxed); - } + fn intern_red_node( + &self, + prev_graph: &PreviousDepGraph, + prev_index: SerializedDepNodeIndex, + edges: EdgesVec, + fingerprint: Fingerprint, + ) -> DepNodeIndex { + self.debug_assert_not_in_new_nodes(prev_graph, prev_index); - // As long as we only have a low number of reads we can avoid doing a hash - // insert and potentially allocating/reallocating the hashmap - let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { - task_deps.reads.iter().all(|other| *other != source) - } else { - task_deps.read_set.insert(source) - }; - if new_read { - task_deps.reads.push(source); - if task_deps.reads.len() == TASK_DEPS_READS_CAP { - // Fill `read_set` with what we have so far so we can use the hashset next - // time - task_deps.read_set.extend(task_deps.reads.iter().copied()); - } + let mut prev_index_to_index = self.prev_index_to_index.lock(); - #[cfg(debug_assertions)] - { - if let Some(target) = task_deps.node { - let data = self.current.data.lock(); - if let Some(ref forbidden_edge) = self.current.forbidden_edge { - let source = data[source].node; - if forbidden_edge.test(&source, &target) { - panic!("forbidden edge {:?} -> {:?} created", source, target) - } - } - } - } - } else if cfg!(debug_assertions) { - self.current.total_duplicate_read_count.fetch_add(1, Relaxed); - } + match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let mut data = self.data.lock(); + let red_index = data.red.node_indices.push(prev_index); + data.red.edges.push(edges); + data.red.fingerprints.push(fingerprint); + let dep_node_index = data.hybrid_indices.push(red_index.into()); + prev_index_to_index[prev_index] = Some(dep_node_index); + dep_node_index } - }) + } + } + + fn intern_green_node( + &self, + prev_graph: &PreviousDepGraph, + prev_index: SerializedDepNodeIndex, + edges: EdgesVec, + ) -> DepNodeIndex { + self.debug_assert_not_in_new_nodes(prev_graph, prev_index); + + let mut prev_index_to_index = self.prev_index_to_index.lock(); + + match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let mut data = self.data.lock(); + let green_index = data.green.node_indices.push(prev_index); + data.green.edges.push(edges); + let dep_node_index = data.hybrid_indices.push(green_index.into()); + prev_index_to_index[prev_index] = Some(dep_node_index); + dep_node_index + } + } + } + + #[inline] + fn debug_assert_not_in_new_nodes( + &self, + prev_graph: &PreviousDepGraph, + prev_index: SerializedDepNodeIndex, + ) { + let node = &prev_graph.index_to_node(prev_index); + debug_assert!( + !self.new_node_to_index.get_shard_by_value(node).lock().contains_key(node), + "node from previous graph present in new node collection" + ); } } diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index a27b716b95ae..82e99d64afeb 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -9,16 +9,16 @@ pub struct DepGraphQuery { } impl DepGraphQuery { - pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { + pub fn new(nodes: &[DepNode], edges: &[(usize, usize)]) -> DepGraphQuery { let mut graph = Graph::with_capacity(nodes.len(), edges.len()); let mut indices = FxHashMap::default(); for node in nodes { indices.insert(*node, graph.add_node(*node)); } - for &(ref source, ref target) in edges { - let source = indices[source]; - let target = indices[target]; + for &(source, target) in edges { + let source = indices[&nodes[source]]; + let target = indices[&nodes[target]]; graph.add_edge(source, target, ()); } From ea47269f5f50cd7804141ba00811b79be1e156c6 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Sat, 28 Nov 2020 17:42:41 -0800 Subject: [PATCH 519/719] rustc_query_system: share previous graph edges with current graph Reduce memory consumption by sharing the previous dependency graph's edges with the current graph when it is known to be valid to do so. It is known to be valid whenever we mark a node green because all of its dependencies were green. It is *not* known to be valid when we mark a node green because we re-executed its query and its result was the same as in the previous compilation session. In that case, the dependency set might have changed (we don't try to determine whether or not it changed and whether or not we can share). --- .../rustc_query_system/src/dep_graph/graph.rs | 221 ++++++++++++------ .../src/dep_graph/serialized.rs | 7 +- 2 files changed, 161 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 3bc93f63905b..24508a523736 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -134,16 +134,14 @@ impl DepGraph { } pub fn query(&self) -> DepGraphQuery { + // We call this before acquiring locks, since it also acquires them. + let edge_count = self.edge_count(); let data = self.data.as_ref().unwrap(); let previous = &data.previous; + let prev_index_to_index = data.current.prev_index_to_index.lock(); let data = data.current.data.lock(); - let node_count = data.hybrid_indices.len(); - let edge_count = data.new.edges.iter().map(|e| e.len()).sum::() - + data.red.edges.iter().map(|e| e.len()).sum::() - + data.green.edges.iter().map(|e| e.len()).sum::(); - let mut nodes = Vec::with_capacity(node_count); let mut edges = Vec::with_capacity(edge_count); @@ -161,10 +159,18 @@ impl DepGraph { nodes.push(previous.index_to_node(red.node_indices[red_index])); edges.extend(red.edges[red_index].iter().map(|dst| (src, dst.index()))); } - HybridIndex::Green(green_index) => { - let green = &data.green; - nodes.push(previous.index_to_node(green.node_indices[green_index])); - edges.extend(green.edges[green_index].iter().map(|dst| (src, dst.index()))); + HybridIndex::LightGreen(lg_index) => { + let lg = &data.light_green; + nodes.push(previous.index_to_node(lg.node_indices[lg_index])); + edges.extend(lg.edges[lg_index].iter().map(|dst| (src, dst.index()))); + } + HybridIndex::DarkGreen(prev_index) => { + nodes.push(previous.index_to_node(prev_index)); + let edges_iter = previous + .edge_targets_from(prev_index) + .iter() + .map(|&dst| (src, prev_index_to_index[dst].unwrap().index())); + edges.extend(edges_iter); } } } @@ -287,7 +293,7 @@ impl DepGraph { } let dep_node_index = - data.current.intern_green_node(&data.previous, prev_index, edges); + data.current.intern_light_green_node(&data.previous, prev_index, edges); (DepNodeColor::Green(dep_node_index), dep_node_index) } else { @@ -479,9 +485,10 @@ impl DepGraph { match data.hybrid_indices[dep_node_index].into() { HybridIndex::New(new_index) => data.new.nodes[new_index], HybridIndex::Red(red_index) => previous.index_to_node(data.red.node_indices[red_index]), - HybridIndex::Green(green_index) => { - previous.index_to_node(data.green.node_indices[green_index]) + HybridIndex::LightGreen(light_green_index) => { + previous.index_to_node(data.light_green.node_indices[light_green_index]) } + HybridIndex::DarkGreen(prev_index) => previous.index_to_node(prev_index), } } @@ -494,9 +501,10 @@ impl DepGraph { match data.hybrid_indices[dep_node_index].into() { HybridIndex::New(new_index) => data.new.fingerprints[new_index], HybridIndex::Red(red_index) => data.red.fingerprints[red_index], - HybridIndex::Green(green_index) => { - previous.fingerprint_by_index(data.green.node_indices[green_index]) + HybridIndex::LightGreen(light_green_index) => { + previous.fingerprint_by_index(data.light_green.node_indices[light_green_index]) } + HybridIndex::DarkGreen(prev_index) => previous.fingerprint_by_index(prev_index), } } @@ -547,18 +555,37 @@ impl DepGraph { } } - pub fn serialize(&self) -> SerializedDepGraph { - type SDNI = SerializedDepNodeIndex; - + #[inline] + fn edge_count(&self) -> usize { let data = self.data.as_ref().unwrap(); let previous = &data.previous; let data = data.current.data.lock(); - let node_count = data.hybrid_indices.len(); - - let edge_count = data.new.edges.iter().map(|e| e.len()).sum::() + // Linearly scanning each collection is a bit faster than scanning + // `hybrid_indices` and bouncing around the different collections. + let mut edge_count = data.new.edges.iter().map(|e| e.len()).sum::() + data.red.edges.iter().map(|e| e.len()).sum::() - + data.green.edges.iter().map(|e| e.len()).sum::(); + + data.light_green.edges.iter().map(|e| e.len()).sum::(); + + for &hybrid_index in data.hybrid_indices.iter() { + if let HybridIndex::DarkGreen(prev_index) = hybrid_index.into() { + edge_count += previous.edge_targets_from(prev_index).len() + } + } + + edge_count + } + + pub fn serialize(&self) -> SerializedDepGraph { + type SDNI = SerializedDepNodeIndex; + + // We call this before acquiring locks, since it also acquires them. + let edge_count = self.edge_count(); + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; + let prev_index_to_index = data.current.prev_index_to_index.lock(); + let data = data.current.data.lock(); + let node_count = data.hybrid_indices.len(); let mut nodes = IndexVec::with_capacity(node_count); let mut fingerprints = IndexVec::with_capacity(node_count); @@ -590,11 +617,20 @@ impl DepGraph { fingerprints.push(red.fingerprints[i]); add_edges(&mut edge_list_indices, &mut edge_list_data, red.edges[i].iter()); } - HybridIndex::Green(i) => { - let green = &data.green; - nodes.push(previous.index_to_node(green.node_indices[i])); - fingerprints.push(previous.fingerprint_by_index(green.node_indices[i])); - add_edges(&mut edge_list_indices, &mut edge_list_data, green.edges[i].iter()); + HybridIndex::LightGreen(i) => { + let lg = &data.light_green; + nodes.push(previous.index_to_node(lg.node_indices[i])); + fingerprints.push(previous.fingerprint_by_index(lg.node_indices[i])); + add_edges(&mut edge_list_indices, &mut edge_list_data, lg.edges[i].iter()); + } + HybridIndex::DarkGreen(prev_index) => { + nodes.push(previous.index_to_node(prev_index)); + fingerprints.push(previous.fingerprint_by_index(prev_index)); + let edges_iter = previous + .edge_targets_from(prev_index) + .iter() + .map(|&dst| prev_index_to_index[dst].as_ref().unwrap()); + add_edges(&mut edge_list_indices, &mut edge_list_data, edges_iter); } } } @@ -688,13 +724,11 @@ impl DepGraph { let prev_deps = data.previous.edge_targets_from(prev_dep_node_index); - let mut current_deps = SmallVec::new(); - for &dep_dep_node_index in prev_deps { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { - Some(DepNodeColor::Green(node_index)) => { + Some(DepNodeColor::Green(_)) => { // This dependency has been marked as green before, we are // still fine and can continue with checking the other // dependencies. @@ -704,7 +738,6 @@ impl DepGraph { dep_node, data.previous.index_to_node(dep_dep_node_index) ); - current_deps.push(node_index); } Some(DepNodeColor::Red) => { // We found a dependency the value of which has changed @@ -737,13 +770,12 @@ impl DepGraph { dep_dep_node_index, dep_dep_node, ); - if let Some(node_index) = node_index { + if node_index.is_some() { debug!( "try_mark_previous_green({:?}) --- managed to MARK \ dependency {:?} as green", dep_node, dep_dep_node ); - current_deps.push(node_index); continue; } } @@ -758,13 +790,12 @@ impl DepGraph { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { - Some(DepNodeColor::Green(node_index)) => { + Some(DepNodeColor::Green(_)) => { debug!( "try_mark_previous_green({:?}) --- managed to \ FORCE dependency {:?} to green", dep_node, dep_dep_node ); - current_deps.push(node_index); } Some(DepNodeColor::Red) => { debug!( @@ -822,7 +853,7 @@ impl DepGraph { let dep_node_index = { // We allocating an entry for the node in the current dependency graph and // adding all the appropriate edges imported from the previous graph - data.current.intern_green_node(&data.previous, prev_dep_node_index, current_deps) + data.current.intern_dark_green_node(&data.previous, prev_dep_node_index) }; // ... emitting any stored diagnostic ... @@ -1015,9 +1046,9 @@ rustc_index::newtype_index! { } } -// Index type for `GreenDepNodeData`. +// Index type for `LightGreenDepNodeData`. rustc_index::newtype_index! { - struct GreenDepNodeIndex { + struct LightGreenDepNodeIndex { MAX = 0x7FFF_FFFF } } @@ -1030,7 +1061,8 @@ struct CompressedHybridIndex(u32); impl CompressedHybridIndex { const NEW_TAG: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000; const RED_TAG: u32 = 0b0100_0000_0000_0000_0000_0000_0000_0000; - const GREEN_TAG: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000; + const LIGHT_GREEN_TAG: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000; + const DARK_GREEN_TAG: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000; const TAG_MASK: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000; const INDEX_MASK: u32 = !Self::TAG_MASK; @@ -1050,10 +1082,17 @@ impl From for CompressedHybridIndex { } } -impl From for CompressedHybridIndex { +impl From for CompressedHybridIndex { #[inline] - fn from(index: GreenDepNodeIndex) -> Self { - CompressedHybridIndex(Self::GREEN_TAG | index.as_u32()) + fn from(index: LightGreenDepNodeIndex) -> Self { + CompressedHybridIndex(Self::LIGHT_GREEN_TAG | index.as_u32()) + } +} + +impl From for CompressedHybridIndex { + #[inline] + fn from(index: SerializedDepNodeIndex) -> Self { + CompressedHybridIndex(Self::DARK_GREEN_TAG | index.as_u32()) } } @@ -1063,7 +1102,8 @@ impl From for CompressedHybridIndex { enum HybridIndex { New(NewDepNodeIndex), Red(RedDepNodeIndex), - Green(GreenDepNodeIndex), + LightGreen(LightGreenDepNodeIndex), + DarkGreen(SerializedDepNodeIndex), } impl From for HybridIndex { @@ -1074,8 +1114,11 @@ impl From for HybridIndex { match hybrid_index.0 & CompressedHybridIndex::TAG_MASK { CompressedHybridIndex::NEW_TAG => HybridIndex::New(NewDepNodeIndex::from_u32(index)), CompressedHybridIndex::RED_TAG => HybridIndex::Red(RedDepNodeIndex::from_u32(index)), - CompressedHybridIndex::GREEN_TAG => { - HybridIndex::Green(GreenDepNodeIndex::from_u32(index)) + CompressedHybridIndex::LIGHT_GREEN_TAG => { + HybridIndex::LightGreen(LightGreenDepNodeIndex::from_u32(index)) + } + CompressedHybridIndex::DARK_GREEN_TAG => { + HybridIndex::DarkGreen(SerializedDepNodeIndex::from_u32(index)) } _ => unreachable!(), } @@ -1087,6 +1130,32 @@ impl From for HybridIndex { /// We divide nodes this way because different types of nodes are able to share /// more or less data with the previous graph. /// +/// To enable more sharing, we distinguish between two kinds of green nodes. +/// Light green nodes are nodes in the previous graph that have been marked +/// green because we re-executed their queries and the results were the same as +/// in the previous session. Dark green nodes are nodes in the previous graph +/// that have been marked green because we were able to mark all of their +/// dependencies green. +/// +/// Both light and dark green nodes can share the dep node and fingerprint with +/// the previous graph, but for light green nodes, we can't be sure that the +/// edges may be shared without comparing them against the previous edges, so we +/// store them directly (an approach in which we compare edges with the previous +/// edges to see if they can be shared was evaluated, but was not found to be +/// very profitable). +/// +/// For dark green nodes, we can share everything with the previous graph, which +/// is why the `HybridIndex::DarkGreen` enum variant contains the index of the +/// node in the previous graph, and why we don't have a separate collection for +/// dark green node data--the collection is the `PreviousDepGraph` itself. +/// +/// (Note that for dark green nodes, the edges in the previous graph +/// (`SerializedDepNodeIndex`s) must be converted to edges in the current graph +/// (`DepNodeIndex`s). `CurrentDepGraph` contains `prev_index_to_index`, which +/// can perform this conversion. It should always be possible, as by definition, +/// a dark green node is one whose dependencies from the previous session have +/// all been marked green--which means `prev_index_to_index` contains them.) +/// /// Node data is stored in parallel vectors to eliminate the padding between /// elements that would be needed to satisfy alignment requirements of the /// structure that would contain all of a node's data. We could group tightly @@ -1099,8 +1168,8 @@ struct DepNodeData { /// Data for nodes in previous graph that have been marked red. red: RedDepNodeData, - /// Data for nodes in previous graph that have been marked green. - green: GreenDepNodeData, + /// Data for nodes in previous graph that have been marked light green. + light_green: LightGreenDepNodeData, /// Mapping from `DepNodeIndex` to an index into a collection above. /// Indicates which of the above collections contains a node's data. @@ -1130,12 +1199,13 @@ struct RedDepNodeData { fingerprints: IndexVec, } -/// Data for nodes in previous graph that have been marked green. We can share -/// both the dep node and the fingerprint with previous graph, but the edges may -/// be different, so we store the latter directly. -struct GreenDepNodeData { - node_indices: IndexVec, - edges: IndexVec, +/// Data for nodes in previous graph that have been marked green because we +/// re-executed their queries and the results were the same as in the previous +/// session. We can share the dep node and the fingerprint with the previous +/// graph, but the edges may be different, so we store them directly. +struct LightGreenDepNodeData { + node_indices: IndexVec, + edges: IndexVec, } /// `CurrentDepGraph` stores the dependency graph for the current session. It @@ -1164,10 +1234,9 @@ struct GreenDepNodeData { /// a `DepNodeIndex` typically just access the `data` field. /// /// We only need to manipulate at most two locks simultaneously: -/// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. The -/// only operation that must manipulate both locks is adding new nodes, in which -/// case we first acquire the `new_node_to_index` or `prev_index_to_index` lock -/// and then, once a new node is to be inserted, acquire the lock on `data`. +/// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When +/// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index` +/// first, and `data` second. pub(super) struct CurrentDepGraph { data: Lock>, new_node_to_index: Sharded, DepNodeIndex>>, @@ -1227,7 +1296,7 @@ impl CurrentDepGraph { // structures during full incremental builds, where they aren't used. let new_node_count_estimate = (prev_graph_node_count * 2) / 100 + 200; let red_node_count_estimate = (prev_graph_node_count * 3) / 100; - let green_node_count_estimate = (prev_graph_node_count * 95) / 100; + let light_green_node_count_estimate = (prev_graph_node_count * 25) / 100; let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate; // We store a large collection of these in `prev_index_to_index` during @@ -1247,9 +1316,9 @@ impl CurrentDepGraph { edges: IndexVec::with_capacity(red_node_count_estimate), fingerprints: IndexVec::with_capacity(red_node_count_estimate), }, - green: GreenDepNodeData { - node_indices: IndexVec::with_capacity(green_node_count_estimate), - edges: IndexVec::with_capacity(green_node_count_estimate), + light_green: LightGreenDepNodeData { + node_indices: IndexVec::with_capacity(light_green_node_count_estimate), + edges: IndexVec::with_capacity(light_green_node_count_estimate), }, hybrid_indices: IndexVec::with_capacity(total_node_count_estimate), }), @@ -1276,8 +1345,8 @@ impl CurrentDepGraph { ) -> DepNodeIndex { debug_assert!( prev_graph.node_to_index_opt(&dep_node).is_none(), - "node in previous graph should be interned using \ - `intern_red_node` or `intern_green_node`" + "node in previous graph should be interned using one \ + of `intern_red_node`, `intern_light_green_node`, etc." ); match self.new_node_to_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { @@ -1319,7 +1388,7 @@ impl CurrentDepGraph { } } - fn intern_green_node( + fn intern_light_green_node( &self, prev_graph: &PreviousDepGraph, prev_index: SerializedDepNodeIndex, @@ -1333,9 +1402,29 @@ impl CurrentDepGraph { Some(dep_node_index) => dep_node_index, None => { let mut data = self.data.lock(); - let green_index = data.green.node_indices.push(prev_index); - data.green.edges.push(edges); - let dep_node_index = data.hybrid_indices.push(green_index.into()); + let light_green_index = data.light_green.node_indices.push(prev_index); + data.light_green.edges.push(edges); + let dep_node_index = data.hybrid_indices.push(light_green_index.into()); + prev_index_to_index[prev_index] = Some(dep_node_index); + dep_node_index + } + } + } + + fn intern_dark_green_node( + &self, + prev_graph: &PreviousDepGraph, + prev_index: SerializedDepNodeIndex, + ) -> DepNodeIndex { + self.debug_assert_not_in_new_nodes(prev_graph, prev_index); + + let mut prev_index_to_index = self.prev_index_to_index.lock(); + + match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let mut data = self.data.lock(); + let dep_node_index = data.hybrid_indices.push(prev_index.into()); prev_index_to_index[prev_index] = Some(dep_node_index); dep_node_index } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 932c6d2a2f18..28e074069185 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -4,8 +4,13 @@ use super::{DepKind, DepNode}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_index::vec::IndexVec; +// The maximum value of `SerializedDepNodeIndex` leaves the upper two bits +// unused so that we can store multiple index types in `CompressedHybridIndex`, +// and use those bits to encode which index type it contains. rustc_index::newtype_index! { - pub struct SerializedDepNodeIndex { .. } + pub struct SerializedDepNodeIndex { + MAX = 0x7FFF_FFFF + } } /// Data for use when recompiling the **current crate**. From dd1ab840d279c96adf5d7778670f14a6398b595a Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Mon, 30 Nov 2020 21:07:08 -0800 Subject: [PATCH 520/719] rustc_query_system: use more space-efficient edges representation Use single vector of edges rather than per-node vector. There is a small hit to instruction counts (< 0.5%), but the memory savings make up for it. --- .../rustc_query_system/src/dep_graph/graph.rs | 137 ++++++++++++------ .../rustc_query_system/src/dep_graph/query.rs | 18 ++- 2 files changed, 103 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 24508a523736..076dcb4fed1f 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -15,6 +15,7 @@ use std::env; use std::hash::Hash; use std::marker::PhantomData; use std::mem; +use std::ops::Range; use std::sync::atomic::Ordering::Relaxed; use super::debug::EdgeFilter; @@ -143,42 +144,48 @@ impl DepGraph { let node_count = data.hybrid_indices.len(); let mut nodes = Vec::with_capacity(node_count); - let mut edges = Vec::with_capacity(edge_count); - - for (index, &hybrid_index) in data.hybrid_indices.iter_enumerated() { - let src = index.index(); + let mut edge_list_indices = Vec::with_capacity(node_count); + let mut edge_list_data = Vec::with_capacity(edge_count); + edge_list_data.extend(data.unshared_edges.iter().map(|i| i.index())); + for &hybrid_index in data.hybrid_indices.iter() { match hybrid_index.into() { HybridIndex::New(new_index) => { - let new = &data.new; - nodes.push(new.nodes[new_index]); - edges.extend(new.edges[new_index].iter().map(|dst| (src, dst.index()))); + nodes.push(data.new.nodes[new_index]); + let edges = &data.new.edges[new_index]; + edge_list_indices.push((edges.start.index(), edges.end.index())); } HybridIndex::Red(red_index) => { - let red = &data.red; - nodes.push(previous.index_to_node(red.node_indices[red_index])); - edges.extend(red.edges[red_index].iter().map(|dst| (src, dst.index()))); + nodes.push(previous.index_to_node(data.red.node_indices[red_index])); + let edges = &data.red.edges[red_index]; + edge_list_indices.push((edges.start.index(), edges.end.index())); } HybridIndex::LightGreen(lg_index) => { - let lg = &data.light_green; - nodes.push(previous.index_to_node(lg.node_indices[lg_index])); - edges.extend(lg.edges[lg_index].iter().map(|dst| (src, dst.index()))); + nodes.push(previous.index_to_node(data.light_green.node_indices[lg_index])); + let edges = &data.light_green.edges[lg_index]; + edge_list_indices.push((edges.start.index(), edges.end.index())); } HybridIndex::DarkGreen(prev_index) => { nodes.push(previous.index_to_node(prev_index)); + let edges_iter = previous .edge_targets_from(prev_index) .iter() - .map(|&dst| (src, prev_index_to_index[dst].unwrap().index())); - edges.extend(edges_iter); + .map(|&dst| prev_index_to_index[dst].unwrap().index()); + + let start = edge_list_data.len(); + edge_list_data.extend(edges_iter); + let end = edge_list_data.len(); + edge_list_indices.push((start, end)); } } } debug_assert_eq!(nodes.len(), node_count); - debug_assert_eq!(edges.len(), edge_count); + debug_assert_eq!(edge_list_indices.len(), node_count); + debug_assert_eq!(edge_list_data.len(), edge_count); - DepGraphQuery::new(&nodes[..], &edges[..]) + DepGraphQuery::new(&nodes[..], &edge_list_indices[..], &edge_list_data[..]) } pub fn assert_ignored(&self) { @@ -561,11 +568,7 @@ impl DepGraph { let previous = &data.previous; let data = data.current.data.lock(); - // Linearly scanning each collection is a bit faster than scanning - // `hybrid_indices` and bouncing around the different collections. - let mut edge_count = data.new.edges.iter().map(|e| e.len()).sum::() - + data.red.edges.iter().map(|e| e.len()).sum::() - + data.light_green.edges.iter().map(|e| e.len()).sum::(); + let mut edge_count = data.unshared_edges.len(); for &hybrid_index in data.hybrid_indices.iter() { if let HybridIndex::DarkGreen(prev_index) = hybrid_index.into() { @@ -591,17 +594,7 @@ impl DepGraph { let mut fingerprints = IndexVec::with_capacity(node_count); let mut edge_list_indices = IndexVec::with_capacity(node_count); let mut edge_list_data = Vec::with_capacity(edge_count); - - fn add_edges<'a, I: Iterator>( - edge_list_indices: &mut IndexVec, - edge_list_data: &mut Vec, - iter: I, - ) { - let start = edge_list_data.len() as u32; - edge_list_data.extend(iter.map(|i| SDNI::new(i.index()))); - let end = edge_list_data.len() as u32; - edge_list_indices.push((start, end)); - }; + edge_list_data.extend(data.unshared_edges.iter().map(|i| SDNI::new(i.index()))); for &hybrid_index in data.hybrid_indices.iter() { match hybrid_index.into() { @@ -609,28 +602,36 @@ impl DepGraph { let new = &data.new; nodes.push(new.nodes[i]); fingerprints.push(new.fingerprints[i]); - add_edges(&mut edge_list_indices, &mut edge_list_data, new.edges[i].iter()); + let edges = &new.edges[i]; + edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32())); } HybridIndex::Red(i) => { let red = &data.red; nodes.push(previous.index_to_node(red.node_indices[i])); fingerprints.push(red.fingerprints[i]); - add_edges(&mut edge_list_indices, &mut edge_list_data, red.edges[i].iter()); + let edges = &red.edges[i]; + edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32())); } HybridIndex::LightGreen(i) => { let lg = &data.light_green; nodes.push(previous.index_to_node(lg.node_indices[i])); fingerprints.push(previous.fingerprint_by_index(lg.node_indices[i])); - add_edges(&mut edge_list_indices, &mut edge_list_data, lg.edges[i].iter()); + let edges = &lg.edges[i]; + edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32())); } HybridIndex::DarkGreen(prev_index) => { nodes.push(previous.index_to_node(prev_index)); fingerprints.push(previous.fingerprint_by_index(prev_index)); + let edges_iter = previous .edge_targets_from(prev_index) .iter() .map(|&dst| prev_index_to_index[dst].as_ref().unwrap()); - add_edges(&mut edge_list_indices, &mut edge_list_data, edges_iter); + + let start = edge_list_data.len() as u32; + edge_list_data.extend(edges_iter.map(|i| SDNI::new(i.index()))); + let end = edge_list_data.len() as u32; + edge_list_indices.push((start, end)); } } } @@ -1125,6 +1126,11 @@ impl From for HybridIndex { } } +// Index type for `DepNodeData`'s edges. +rustc_index::newtype_index! { + struct EdgeIndex { .. } +} + /// Data for nodes in the current graph, divided into different collections /// based on their presence in the previous graph, and if present, their color. /// We divide nodes this way because different types of nodes are able to share @@ -1171,6 +1177,16 @@ struct DepNodeData { /// Data for nodes in previous graph that have been marked light green. light_green: LightGreenDepNodeData, + // Edges for all nodes other than dark-green ones. Edges for each node + // occupy a contiguous region of this collection, which a node can reference + // using two indices. Storing edges this way rather than using an `EdgesVec` + // for each node reduces memory consumption by a not insignificant amount + // when compiling large crates. The downside is that we have to copy into + // this collection the edges from the `EdgesVec`s that are built up during + // query execution. But this is mostly balanced out by the more efficient + // implementation of `DepGraph::serialize` enabled by this representation. + unshared_edges: IndexVec, + /// Mapping from `DepNodeIndex` to an index into a collection above. /// Indicates which of the above collections contains a node's data. /// @@ -1186,7 +1202,7 @@ struct DepNodeData { /// the previous graph, so we must store all of such a node's data here. struct NewDepNodeData { nodes: IndexVec>, - edges: IndexVec, + edges: IndexVec>, fingerprints: IndexVec, } @@ -1195,7 +1211,7 @@ struct NewDepNodeData { /// fingerprint is known to be different, so we store the latter two directly. struct RedDepNodeData { node_indices: IndexVec, - edges: IndexVec, + edges: IndexVec>, fingerprints: IndexVec, } @@ -1205,7 +1221,7 @@ struct RedDepNodeData { /// graph, but the edges may be different, so we store them directly. struct LightGreenDepNodeData { node_indices: IndexVec, - edges: IndexVec, + edges: IndexVec>, } /// `CurrentDepGraph` stores the dependency graph for the current session. It @@ -1294,11 +1310,27 @@ impl CurrentDepGraph { // not be enough. The allocation for red and green node data doesn't // include a constant, as we don't want to allocate anything for these // structures during full incremental builds, where they aren't used. + // + // These estimates are based on the distribution of node and edge counts + // seen in rustc-perf benchmarks, adjusted somewhat to account for the + // fact that these benchmarks aren't perfectly representative. + // + // FIXME Use a collection type that doesn't copy node and edge data and + // grow multiplicatively on reallocation. Without such a collection or + // solution having the same effect, there is a performance hazard here + // in both time and space, as growing these collections means copying a + // large amount of data and doubling already large buffer capacities. A + // solution for this will also mean that it's less important to get + // these estimates right. let new_node_count_estimate = (prev_graph_node_count * 2) / 100 + 200; let red_node_count_estimate = (prev_graph_node_count * 3) / 100; let light_green_node_count_estimate = (prev_graph_node_count * 25) / 100; let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate; + let average_edges_per_node_estimate = 6; + let unshared_edge_count_estimate = average_edges_per_node_estimate + * (new_node_count_estimate + red_node_count_estimate + light_green_node_count_estimate); + // We store a large collection of these in `prev_index_to_index` during // non-full incremental builds, and want to ensure that the element size // doesn't inadvertently increase. @@ -1320,6 +1352,7 @@ impl CurrentDepGraph { node_indices: IndexVec::with_capacity(light_green_node_count_estimate), edges: IndexVec::with_capacity(light_green_node_count_estimate), }, + unshared_edges: IndexVec::with_capacity(unshared_edge_count_estimate), hybrid_indices: IndexVec::with_capacity(total_node_count_estimate), }), new_node_to_index: Sharded::new(|| { @@ -1352,9 +1385,9 @@ impl CurrentDepGraph { match self.new_node_to_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { - let mut data = self.data.lock(); + let data = &mut *self.data.lock(); let new_index = data.new.nodes.push(dep_node); - data.new.edges.push(edges); + add_edges(&mut data.unshared_edges, &mut data.new.edges, edges); data.new.fingerprints.push(fingerprint); let dep_node_index = data.hybrid_indices.push(new_index.into()); entry.insert(dep_node_index); @@ -1377,9 +1410,9 @@ impl CurrentDepGraph { match prev_index_to_index[prev_index] { Some(dep_node_index) => dep_node_index, None => { - let mut data = self.data.lock(); + let data = &mut *self.data.lock(); let red_index = data.red.node_indices.push(prev_index); - data.red.edges.push(edges); + add_edges(&mut data.unshared_edges, &mut data.red.edges, edges); data.red.fingerprints.push(fingerprint); let dep_node_index = data.hybrid_indices.push(red_index.into()); prev_index_to_index[prev_index] = Some(dep_node_index); @@ -1401,9 +1434,9 @@ impl CurrentDepGraph { match prev_index_to_index[prev_index] { Some(dep_node_index) => dep_node_index, None => { - let mut data = self.data.lock(); + let data = &mut *self.data.lock(); let light_green_index = data.light_green.node_indices.push(prev_index); - data.light_green.edges.push(edges); + add_edges(&mut data.unshared_edges, &mut data.light_green.edges, edges); let dep_node_index = data.hybrid_indices.push(light_green_index.into()); prev_index_to_index[prev_index] = Some(dep_node_index); dep_node_index @@ -1445,6 +1478,18 @@ impl CurrentDepGraph { } } +#[inline] +fn add_edges( + edges: &mut IndexVec, + edge_indices: &mut IndexVec>, + new_edges: EdgesVec, +) { + let start = edges.next_index(); + edges.extend(new_edges); + let end = edges.next_index(); + edge_indices.push(start..end); +} + /// The capacity of the `reads` field `SmallVec` const TASK_DEPS_READS_CAP: usize = 8; type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index 82e99d64afeb..cc25d08cb54f 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -9,17 +9,23 @@ pub struct DepGraphQuery { } impl DepGraphQuery { - pub fn new(nodes: &[DepNode], edges: &[(usize, usize)]) -> DepGraphQuery { - let mut graph = Graph::with_capacity(nodes.len(), edges.len()); + pub fn new( + nodes: &[DepNode], + edge_list_indices: &[(usize, usize)], + edge_list_data: &[usize], + ) -> DepGraphQuery { + let mut graph = Graph::with_capacity(nodes.len(), edge_list_data.len()); let mut indices = FxHashMap::default(); for node in nodes { indices.insert(*node, graph.add_node(*node)); } - for &(source, target) in edges { - let source = indices[&nodes[source]]; - let target = indices[&nodes[target]]; - graph.add_edge(source, target, ()); + for (source, &(start, end)) in edge_list_indices.iter().enumerate() { + for &target in &edge_list_data[start..end] { + let source = indices[&nodes[source]]; + let target = indices[&nodes[target]]; + graph.add_edge(source, target, ()); + } } DepGraphQuery { graph, indices } From 4f76266295ce1a3ecedc7de178c8b82fc8ba5206 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Mon, 30 Nov 2020 21:13:49 -0800 Subject: [PATCH 521/719] rustc_query_system: minor cleanup Remove effectively unused parameter and delete out of date comment. --- .../rustc_query_system/src/dep_graph/graph.rs | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 076dcb4fed1f..fefc8ed6f1a9 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -242,7 +242,6 @@ impl DepGraph { key, cx, arg, - false, task, |_key| { Some(TaskDeps { @@ -262,29 +261,16 @@ impl DepGraph { key: DepNode, cx: Ctxt, arg: A, - no_tcx: bool, task: fn(Ctxt, A) -> R, create_task: fn(DepNode) -> Option>, hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option, ) -> (R, DepNodeIndex) { if let Some(ref data) = self.data { let task_deps = create_task(key).map(Lock::new); - - // In incremental mode, hash the result of the task. We don't - // do anything with the hash yet, but we are computing it - // anyway so that - // - we make sure that the infrastructure works and - // - we can get an idea of the runtime cost. - let mut hcx = cx.create_stable_hashing_context(); - - let result = if no_tcx { - task(cx, arg) - } else { - K::with_deps(task_deps.as_ref(), || task(cx, arg)) - }; - + let result = K::with_deps(task_deps.as_ref(), || task(cx, arg)); let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); + let mut hcx = cx.create_stable_hashing_context(); let current_fingerprint = hash_result(&mut hcx, &result); let print_status = cfg!(debug_assertions) && cx.debug_dep_tasks(); @@ -413,7 +399,7 @@ impl DepGraph { task: fn(Ctxt, A) -> R, hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option, ) -> (R, DepNodeIndex) { - self.with_task_impl(key, cx, arg, false, task, |_| None, hash_result) + self.with_task_impl(key, cx, arg, task, |_| None, hash_result) } #[inline] From 712fcae13a17940d180a4756eb8fff40470c86d4 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Tue, 15 Dec 2020 22:42:38 -0800 Subject: [PATCH 522/719] rustc_query_system: remove inline annotation from edge_count This isn't called frequently enough to justify inlining. --- compiler/rustc_query_system/src/dep_graph/graph.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index fefc8ed6f1a9..87087dc7b7bf 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -548,7 +548,6 @@ impl DepGraph { } } - #[inline] fn edge_count(&self) -> usize { let data = self.data.as_ref().unwrap(); let previous = &data.previous; From d6b2aaed7d67e0e24e9120830697196a847a0b43 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Tue, 15 Dec 2020 22:57:21 -0800 Subject: [PATCH 523/719] rustc_query_system: rename intern_node to intern_new_node --- compiler/rustc_query_system/src/dep_graph/graph.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 87087dc7b7bf..c739ec3e6fd4 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -333,7 +333,7 @@ impl DepGraph { eprintln!("[task::new] {:?}", key); } - data.current.intern_node( + data.current.intern_new_node( &data.previous, key, edges, @@ -376,7 +376,7 @@ impl DepGraph { hash: data.current.anon_id_seed.combine(hasher.finish()).into(), }; - let dep_node_index = data.current.intern_node( + let dep_node_index = data.current.intern_new_node( &data.previous, target_dep_node, task_deps.reads, @@ -1354,7 +1354,7 @@ impl CurrentDepGraph { } } - fn intern_node( + fn intern_new_node( &self, prev_graph: &PreviousDepGraph, dep_node: DepNode, From 22ed75158bd1ef32d1ba08a58b56f2608c105c0d Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Tue, 15 Dec 2020 22:58:19 -0800 Subject: [PATCH 524/719] rustc_query_system: add more comments for dependency graph --- .../rustc_query_system/src/dep_graph/graph.rs | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index c739ec3e6fd4..8c7217dd3294 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -136,9 +136,12 @@ impl DepGraph { pub fn query(&self) -> DepGraphQuery { // We call this before acquiring locks, since it also acquires them. + // The extra locking is not a big deal, as this gets called rarely. let edge_count = self.edge_count(); let data = self.data.as_ref().unwrap(); let previous = &data.previous; + + // Note locking order: `prev_index_to_index`, then `data`. let prev_index_to_index = data.current.prev_index_to_index.lock(); let data = data.current.data.lock(); let node_count = data.hybrid_indices.len(); @@ -146,6 +149,9 @@ impl DepGraph { let mut nodes = Vec::with_capacity(node_count); let mut edge_list_indices = Vec::with_capacity(node_count); let mut edge_list_data = Vec::with_capacity(edge_count); + + // See `serialize` for notes on the approach used here. + edge_list_data.extend(data.unshared_edges.iter().map(|i| i.index())); for &hybrid_index in data.hybrid_indices.iter() { @@ -285,6 +291,8 @@ impl DepGraph { eprintln!("[task::green] {:?}", key); } + // This is a light green node: it existed in the previous compilation, + // its query was re-executed, and it has the same result as before. let dep_node_index = data.current.intern_light_green_node(&data.previous, prev_index, edges); @@ -294,6 +302,8 @@ impl DepGraph { eprintln!("[task::red] {:?}", key); } + // This is a red node: it existed in the previous compilation, its query + // was re-executed, but it has a different result from before. let dep_node_index = data.current.intern_red_node( &data.previous, prev_index, @@ -308,6 +318,10 @@ impl DepGraph { eprintln!("[task::unknown] {:?}", key); } + // This is a red node, effectively: it existed in the previous compilation + // session, its query was re-executed, but it doesn't compute a result hash + // (i.e. it represents a `no_hash` query), so we have no way of determining + // whether or not the result was the same as before. let dep_node_index = data.current.intern_red_node( &data.previous, prev_index, @@ -315,7 +329,6 @@ impl DepGraph { Fingerprint::ZERO, ); - // Mark the node as Red if we can't hash the result (DepNodeColor::Red, dep_node_index) }; @@ -333,6 +346,7 @@ impl DepGraph { eprintln!("[task::new] {:?}", key); } + // This is a new node: it didn't exist in the previous compilation session. data.current.intern_new_node( &data.previous, key, @@ -343,6 +357,10 @@ impl DepGraph { (result, dep_node_index) } else { + // Incremental compilation is turned off. We just execute the task + // without tracking. We still provide a dep-node index that uniquely + // identifies the task so that we have a cheap way of referring to + // the query for self-profiling. (task(cx, arg), self.next_virtual_depnode_index()) } } @@ -568,9 +586,12 @@ impl DepGraph { type SDNI = SerializedDepNodeIndex; // We call this before acquiring locks, since it also acquires them. + // The extra locking is not a big deal, as this only gets called once. let edge_count = self.edge_count(); let data = self.data.as_ref().unwrap(); let previous = &data.previous; + + // Note locking order: `prev_index_to_index`, then `data`. let prev_index_to_index = data.current.prev_index_to_index.lock(); let data = data.current.data.lock(); let node_count = data.hybrid_indices.len(); @@ -579,6 +600,17 @@ impl DepGraph { let mut fingerprints = IndexVec::with_capacity(node_count); let mut edge_list_indices = IndexVec::with_capacity(node_count); let mut edge_list_data = Vec::with_capacity(edge_count); + + // `rustc_middle::ty::query::OnDiskCache` expects nodes to be in + // `DepNodeIndex` order. The edges in `edge_list_data`, on the other + // hand, don't need to be in a particular order, as long as each node + // can reference its edges as a contiguous range within it. This is why + // we're able to copy `unshared_edges` directly into `edge_list_data`. + // It meets the above requirements, and each non-dark-green node already + // knows the range of edges to reference within it, which they'll push + // onto `edge_list_indices`. Dark green nodes, however, don't have their + // edges in `unshared_edges`, so need to add them to `edge_list_data`. + edge_list_data.extend(data.unshared_edges.iter().map(|i| SDNI::new(i.index()))); for &hybrid_index in data.hybrid_indices.iter() { From 03eb75f759a0c027d07b7d6460f630a373b03638 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Tue, 22 Dec 2020 10:38:48 -0800 Subject: [PATCH 525/719] rustc_query_system: avoid race condition when using edge_count --- .../rustc_query_system/src/dep_graph/graph.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 8c7217dd3294..605d7ae4af67 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::QueryInvocationId; use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; +use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, LockGuard, Lrc, Ordering}; use rustc_data_structures::unlikely; use rustc_errors::Diagnostic; use rustc_index::vec::{Idx, IndexVec}; @@ -135,9 +135,6 @@ impl DepGraph { } pub fn query(&self) -> DepGraphQuery { - // We call this before acquiring locks, since it also acquires them. - // The extra locking is not a big deal, as this gets called rarely. - let edge_count = self.edge_count(); let data = self.data.as_ref().unwrap(); let previous = &data.previous; @@ -145,6 +142,7 @@ impl DepGraph { let prev_index_to_index = data.current.prev_index_to_index.lock(); let data = data.current.data.lock(); let node_count = data.hybrid_indices.len(); + let edge_count = self.edge_count(&data); let mut nodes = Vec::with_capacity(node_count); let mut edge_list_indices = Vec::with_capacity(node_count); @@ -566,14 +564,13 @@ impl DepGraph { } } - fn edge_count(&self) -> usize { + fn edge_count(&self, node_data: &LockGuard<'_, DepNodeData>) -> usize { let data = self.data.as_ref().unwrap(); let previous = &data.previous; - let data = data.current.data.lock(); - let mut edge_count = data.unshared_edges.len(); + let mut edge_count = node_data.unshared_edges.len(); - for &hybrid_index in data.hybrid_indices.iter() { + for &hybrid_index in node_data.hybrid_indices.iter() { if let HybridIndex::DarkGreen(prev_index) = hybrid_index.into() { edge_count += previous.edge_targets_from(prev_index).len() } @@ -585,9 +582,6 @@ impl DepGraph { pub fn serialize(&self) -> SerializedDepGraph { type SDNI = SerializedDepNodeIndex; - // We call this before acquiring locks, since it also acquires them. - // The extra locking is not a big deal, as this only gets called once. - let edge_count = self.edge_count(); let data = self.data.as_ref().unwrap(); let previous = &data.previous; @@ -595,6 +589,7 @@ impl DepGraph { let prev_index_to_index = data.current.prev_index_to_index.lock(); let data = data.current.data.lock(); let node_count = data.hybrid_indices.len(); + let edge_count = self.edge_count(&data); let mut nodes = IndexVec::with_capacity(node_count); let mut fingerprints = IndexVec::with_capacity(node_count); From 32716814a2d9a26674503122d0b91aca39e5ab28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 23 Dec 2020 00:00:00 +0000 Subject: [PATCH 526/719] Ignore proc-macros when assembling rustc libdir --- src/bootstrap/compile.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index fbebb26c7462..81a5b4c8960f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -7,6 +7,7 @@ //! goes along from the output of the previous stage. use std::borrow::Cow; +use std::collections::HashSet; use std::env; use std::fs; use std::io::prelude::*; @@ -956,13 +957,26 @@ impl Step for Assemble { builder.info(&format!("Assembling stage{} compiler ({})", stage, host)); // Link in all dylibs to the libdir + let stamp = librustc_stamp(builder, build_compiler, target_compiler.host); + let proc_macros = builder + .read_stamp_file(&stamp) + .into_iter() + .filter_map(|(path, dependency_type)| { + if dependency_type == DependencyType::Host { + Some(path.file_name().unwrap().to_owned().into_string().unwrap()) + } else { + None + } + }) + .collect::>(); + let sysroot = builder.sysroot(target_compiler); let rustc_libdir = builder.rustc_libdir(target_compiler); t!(fs::create_dir_all(&rustc_libdir)); let src_libdir = builder.sysroot_libdir(build_compiler, host); for f in builder.read_dir(&src_libdir) { let filename = f.file_name().into_string().unwrap(); - if is_dylib(&filename) { + if is_dylib(&filename) && !proc_macros.contains(&filename) { builder.copy(&f.path(), &rustc_libdir.join(&filename)); } } From a6d377d56560350976ccb46f33ae14ad65eb9372 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 22 Dec 2020 16:33:36 -0800 Subject: [PATCH 527/719] Include rustdoc in the compiler docs index. --- src/bootstrap/doc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 8cacc2512eff..30a8229036fd 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -628,6 +628,8 @@ impl Step for Rustdoc { cargo.arg("-p").arg("rustdoc"); cargo.rustdocflag("--document-private-items"); + cargo.rustdocflag("--enable-index-page"); + cargo.rustdocflag("-Zunstable-options"); builder.run(&mut cargo.into()); } } From 530c33cd5fd92c17e44c692bbe7a4006d57340f8 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 22 Dec 2020 20:22:47 -0500 Subject: [PATCH 528/719] Fix elided lifetimes shown as `'_` on async functions --- src/librustdoc/clean/mod.rs | 25 +++++++++++++++++++++++-- src/test/rustdoc/async-fn.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 07255168d068..e7fdf76ba797 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -635,6 +635,18 @@ impl Clean for hir::Generics<'_> { _ => false, } } + /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`. + /// + /// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information. + /// + /// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param + fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool { + match param.kind { + hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided } => true, + _ => false, + } + } + let impl_trait_params = self .params .iter() @@ -653,7 +665,7 @@ impl Clean for hir::Generics<'_> { .collect::>(); let mut params = Vec::with_capacity(self.params.len()); - for p in self.params.iter().filter(|p| !is_impl_trait(p)) { + for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { let p = p.clean(cx); params.push(p); } @@ -1433,7 +1445,16 @@ impl Clean for hir::Ty<'_> { TyKind::Never => Never, TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)), TyKind::Rptr(ref l, ref m) => { - let lifetime = if l.is_elided() { None } else { Some(l.clean(cx)) }; + // There are two times a `Fresh` lifetime can be created: + // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`. + // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`. + // See commit 749349fc9f7b12f212bca9ba2297e463328cb701 for more information. + // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it. + // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though; + // there's no case where it could cause the function to fail to compile. + let elided = + l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_))); + let lifetime = if elided { None } else { Some(l.clean(cx)) }; BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) } } TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs index e7a7d1831f73..7a673b9f6706 100644 --- a/src/test/rustdoc/async-fn.rs +++ b/src/test/rustdoc/async-fn.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // edition:2018 #![feature(min_const_generics)] @@ -52,3 +53,31 @@ pub trait Trait {} // @has async_fn/fn.const_generics.html // @has - '//pre[@class="rust fn"]' 'pub async fn const_generics(_: impl Trait)' pub async fn const_generics(_: impl Trait) {} + +// test that elided lifetimes are properly elided and not displayed as `'_` +// regression test for #63037 +// @has async_fn/fn.elided.html +// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str' +pub async fn elided(foo: &str) -> &str {} +// This should really be shown as written, but for implementation reasons it's difficult. +// See `impl Clean for TyKind::Rptr`. +// @has async_fn/fn.user_elided.html +// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str' +pub async fn user_elided(foo: &'_ str) -> &str {} +// @has async_fn/fn.static_trait.html +// @has - '//pre[@class="rust fn"]' 'pub async fn static_trait(foo: &str) -> Box' +pub async fn static_trait(foo: &str) -> Box {} +// @has async_fn/fn.lifetime_for_trait.html +// @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box" +pub async fn lifetime_for_trait(foo: &str) -> Box {} + +struct AsyncFdReadyGuard<'a, T> { x: &'a T } + +impl Foo { + // @has async_fn/struct.Foo.html + // @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator' + pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator {} + // taken from `tokio` as an example of a method that was particularly bad before + // @has - '//h4[@class="method"]' "pub async fn readable(&self) -> Result, ()>" + pub async fn readable(&self) -> Result, ()> {} +} From 732afd41cff1d562e03a6e1611ef7baf9d7f5962 Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Sat, 19 Dec 2020 22:36:35 +1100 Subject: [PATCH 529/719] Exclude unnecessary info from CodegenResults `foreign_module` and `wasm_import_module` are not needed for linking, and hence can be removed from CodegenResults. --- compiler/rustc_codegen_ssa/src/back/link.rs | 5 +++-- compiler/rustc_codegen_ssa/src/base.rs | 5 +++-- compiler/rustc_codegen_ssa/src/lib.rs | 21 ++++++++++++++++++--- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ccd4d103ddb7..a3a2ef041756 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib}; +use rustc_middle::middle::cstore::{EncodedMetadata, LibSource}; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet}; @@ -22,7 +22,8 @@ use super::command::Command; use super::linker::{self, Linker}; use super::rpath::{self, RPathConfig}; use crate::{ - looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, METADATA_FILENAME, + looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib, + METADATA_FILENAME, }; use cc::windows_registry; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 21138f967a27..18132a2c7a3c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -766,7 +766,7 @@ impl CrateInfo { profiler_runtime: None, is_no_builtins: Default::default(), native_libraries: Default::default(), - used_libraries: tcx.native_libraries(LOCAL_CRATE), + used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(), link_args: tcx.link_args(LOCAL_CRATE), crate_name: Default::default(), used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), @@ -787,7 +787,8 @@ impl CrateInfo { info.missing_lang_items.reserve(n_crates); for &cnum in crates.iter() { - info.native_libraries.insert(cnum, tcx.native_libraries(cnum)); + info.native_libraries + .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect()); info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum)); if tcx.is_panic_runtime(cnum) { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index ee889d552412..bc93bd8b7bd9 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -21,15 +21,17 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; +use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLib}; +use rustc_middle::middle::cstore::{self, CrateSource, LibSource}; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::ty::query::Providers; use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT}; +use rustc_session::utils::NativeLibKind; use rustc_span::symbol::Symbol; use std::path::{Path, PathBuf}; @@ -105,6 +107,19 @@ bitflags::bitflags! { } } +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +pub struct NativeLib { + pub kind: NativeLibKind, + pub name: Option, + pub cfg: Option, +} + +impl From<&cstore::NativeLib> for NativeLib { + fn from(lib: &cstore::NativeLib) -> Self { + NativeLib { kind: lib.kind.clone(), name: lib.name.clone(), cfg: lib.cfg.clone() } + } +} + /// Misc info we load from metadata to persist beyond the tcx. /// /// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo` @@ -119,9 +134,9 @@ pub struct CrateInfo { pub compiler_builtins: Option, pub profiler_runtime: Option, pub is_no_builtins: FxHashSet, - pub native_libraries: FxHashMap>>, + pub native_libraries: FxHashMap>, pub crate_name: FxHashMap, - pub used_libraries: Lrc>, + pub used_libraries: Vec, pub link_args: Lrc>, pub used_crate_source: FxHashMap>, pub used_crates_static: Vec<(CrateNum, LibSource)>, From e8a564edc0a0c19633039848c68d5f81fcfcc00d Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Wed, 23 Dec 2020 12:17:45 +1100 Subject: [PATCH 530/719] Add a test that rustc compiles and links separately --- src/test/run-make-fulldeps/separate-link/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/test/run-make-fulldeps/separate-link/Makefile diff --git a/src/test/run-make-fulldeps/separate-link/Makefile b/src/test/run-make-fulldeps/separate-link/Makefile new file mode 100644 index 000000000000..060484e89f93 --- /dev/null +++ b/src/test/run-make-fulldeps/separate-link/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + echo 'fn main(){}' | $(RUSTC) -Z no-link - + $(RUSTC) -Z link-only $(TMPDIR)/rust_out.rlink + $(call RUN,rust_out) From 5b32ab671a03e0804e864907d7be4c775b4c6403 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 22 Dec 2020 19:37:23 -0800 Subject: [PATCH 531/719] Update and improve `rustc_codegen_{llvm,ssa}` docs These docs were very out of date and misleading. They even said that they codegen'd the *AST*! For some reason, the `rustc_codegen_ssa::base` docs were exactly identical to the `rustc_codegen_llvm::base` docs. They didn't really make sense, because they had LLVM-specific information even though `rustc_codegen_ssa` is supposed to be somewhat generic. So I removed them as they were misleading. --- compiler/rustc_codegen_llvm/src/base.rs | 18 ++++++++---------- compiler/rustc_codegen_llvm/src/common.rs | 1 + compiler/rustc_codegen_ssa/src/base.rs | 15 --------------- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 7d01f6a54995..d5be3132dee1 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -1,17 +1,15 @@ -//! Codegen the completed AST to the LLVM IR. -//! -//! Some functions here, such as codegen_block and codegen_expr, return a value -- -//! the result of the codegen to LLVM -- while others, such as codegen_fn -//! and mono_item, are called only for the side effect of adding a -//! particular definition to the LLVM IR output we're producing. +//! Codegen the MIR to the LLVM IR. //! //! Hopefully useful general knowledge about codegen: //! -//! * There's no way to find out the `Ty` type of a Value. Doing so +//! * There's no way to find out the [`Ty`] type of a [`Value`]. Doing so //! would be "trying to get the eggs out of an omelette" (credit: -//! pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`, -//! but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int, -//! int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`. +//! pcwalton). You can, instead, find out its [`llvm::Type`] by calling [`val_ty`], +//! but one [`llvm::Type`] corresponds to many [`Ty`]s; for instance, `tup(int, int, +//! int)` and `rec(x=int, y=int, z=int)` will have the same [`llvm::Type`]. +//! +//! [`Ty`]: rustc_middle::ty::Ty +//! [`val_ty`]: common::val_ty use super::ModuleLlvm; diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 34e1b7a60451..58af9d4cd04a 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -314,6 +314,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } +/// Get the [LLVM type][Type] of a [`Value`]. pub fn val_ty(v: &Value) -> &Type { unsafe { llvm::LLVMTypeOf(v) } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 21138f967a27..a10e35e02f3c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1,18 +1,3 @@ -//! Codegen the completed AST to the LLVM IR. -//! -//! Some functions here, such as `codegen_block` and `codegen_expr`, return a value -- -//! the result of the codegen to LLVM -- while others, such as `codegen_fn` -//! and `mono_item`, are called only for the side effect of adding a -//! particular definition to the LLVM IR output we're producing. -//! -//! Hopefully useful general knowledge about codegen: -//! -//! * There's no way to find out the `Ty` type of a `Value`. Doing so -//! would be "trying to get the eggs out of an omelette" (credit: -//! pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`, -//! but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int, -//! int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`. - use crate::back::write::{ compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen, From c625d3183cfc64184f5f68687a964ef83f41f199 Mon Sep 17 00:00:00 2001 From: PankajChaudhary5 Date: Wed, 23 Dec 2020 11:02:04 +0530 Subject: [PATCH 532/719] Updated the match with the matches macro --- compiler/rustc_middle/src/ty/sty.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a955cca53cc8..aa0751ae6045 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -205,10 +205,7 @@ pub enum TyKind<'tcx> { impl TyKind<'tcx> { #[inline] pub fn is_primitive(&self) -> bool { - match self { - Bool | Char | Int(_) | Uint(_) | Float(_) => true, - _ => false, - } + matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_)) } } From e89801553ddbaccdeb2eac4db08900edb51ac7ff Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 22 Dec 2020 19:17:59 +0100 Subject: [PATCH 533/719] Revert "Pass Clippy args also trough RUSTFLAGS" --- Cargo.toml | 1 + README.md | 1 + src/driver.rs | 116 ++++++++++++----------------------------------- src/main.rs | 98 ++++++--------------------------------- tests/dogfood.rs | 2 +- 5 files changed, 47 insertions(+), 171 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7f9d22e594b9..a765390c6032 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ publish = false [[bin]] name = "cargo-clippy" +test = false path = "src/main.rs" [[bin]] diff --git a/README.md b/README.md index dc931963726b..aaa55e11c7db 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,7 @@ the lint(s) you are interested in: ```terminal cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... ``` +Note that if you've run clippy before, this may only take effect after you've modified a file or ran `cargo clean`. ### Specifying the minimum supported Rust version diff --git a/src/driver.rs b/src/driver.rs index 40f1b802e60e..e490ee54c0be 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,6 +1,5 @@ #![feature(rustc_private)] #![feature(once_cell)] -#![feature(bool_to_option)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] @@ -20,7 +19,6 @@ use rustc_tools_util::VersionInfo; use std::borrow::Cow; use std::env; -use std::iter; use std::lazy::SyncLazy; use std::ops::Deref; use std::panic; @@ -49,6 +47,20 @@ fn arg_value<'a, T: Deref>( None } +#[test] +fn test_arg_value() { + let args = &["--bar=bar", "--foobar", "123", "--foo"]; + + assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None); + assert_eq!(arg_value(args, "--bar", |_| false), None); + assert_eq!(arg_value(args, "--bar", |_| true), Some("bar")); + assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar")); + assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None); + assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None); + assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123")); + assert_eq!(arg_value(args, "--foo", |_| true), None); +} + struct DefaultCallbacks; impl rustc_driver::Callbacks for DefaultCallbacks {} @@ -170,28 +182,6 @@ fn toolchain_path(home: Option, toolchain: Option) -> Option(args: &mut Vec, clippy_args: I) -where - T: AsRef, - U: AsRef + ?Sized + 'a, - I: Iterator + Clone, -{ - let args_iter = clippy_args.map(AsRef::as_ref); - let args_count = args_iter.clone().count(); - - if args_count > 0 { - if let Some(start) = args.windows(args_count).enumerate().find_map(|(current, window)| { - window - .iter() - .map(AsRef::as_ref) - .eq(args_iter.clone()) - .then_some(current) - }) { - args.drain(start..start + args_count); - } - } -} - #[allow(clippy::too_many_lines)] pub fn main() { rustc_driver::init_rustc_env_logger(); @@ -288,9 +278,20 @@ pub fn main() { args.extend(vec!["--sysroot".into(), sys_root]); }; - let clippy_args = env::var("CLIPPY_ARGS").unwrap_or_default(); - let clippy_args = clippy_args.split_whitespace(); - let no_deps = clippy_args.clone().any(|flag| flag == "--no-deps"); + let mut no_deps = false; + let clippy_args = env::var("CLIPPY_ARGS") + .unwrap_or_default() + .split("__CLIPPY_HACKERY__") + .filter_map(|s| match s { + "" => None, + "--no-deps" => { + no_deps = true; + None + }, + _ => Some(s.to_string()), + }) + .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]) + .collect::>(); // We enable Clippy if one of the following conditions is met // - IF Clippy is run on its test suite OR @@ -303,11 +304,7 @@ pub fn main() { let clippy_enabled = clippy_tests_set || (!cap_lints_allow && (!no_deps || in_primary_package)); if clippy_enabled { - remove_clippy_args(&mut args, iter::once("--no-deps")); - args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]); - } else { - // Remove all flags passed through RUSTFLAGS if Clippy is not enabled. - remove_clippy_args(&mut args, clippy_args); + args.extend(clippy_args); } let mut clippy = ClippyCallbacks; @@ -318,58 +315,3 @@ pub fn main() { rustc_driver::RunCompiler::new(&args, callbacks).run() })) } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_arg_value() { - let args = &["--bar=bar", "--foobar", "123", "--foo"]; - - assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None); - assert_eq!(arg_value(args, "--bar", |_| false), None); - assert_eq!(arg_value(args, "--bar", |_| true), Some("bar")); - assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar")); - assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None); - assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None); - assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123")); - assert_eq!(arg_value(args, "--foo", |_| true), None); - } - - #[test] - fn removes_clippy_args_from_start() { - let mut args = vec!["-D", "clippy::await_holding_lock", "--cfg", r#"feature="some_feat""#]; - let clippy_args = ["-D", "clippy::await_holding_lock"].iter(); - - remove_clippy_args(&mut args, clippy_args); - assert_eq!(args, &["--cfg", r#"feature="some_feat""#]); - } - - #[test] - fn removes_clippy_args_from_end() { - let mut args = vec!["-Zui-testing", "-A", "clippy::empty_loop", "--no-deps"]; - let clippy_args = ["-A", "clippy::empty_loop", "--no-deps"].iter(); - - remove_clippy_args(&mut args, clippy_args); - assert_eq!(args, &["-Zui-testing"]); - } - - #[test] - fn removes_clippy_args_from_middle() { - let mut args = vec!["-Zui-testing", "-W", "clippy::filter_map", "-L", "serde"]; - let clippy_args = ["-W", "clippy::filter_map"].iter(); - - remove_clippy_args(&mut args, clippy_args); - assert_eq!(args, &["-Zui-testing", "-L", "serde"]); - } - - #[test] - fn no_clippy_args_to_remove() { - let mut args = vec!["-Zui-testing", "-L", "serde"]; - let clippy_args: [&str; 0] = []; - - remove_clippy_args(&mut args, clippy_args.iter()); - assert_eq!(args, &["-Zui-testing", "-L", "serde"]); - } -} diff --git a/src/main.rs b/src/main.rs index 1c0e04689a9f..ea06743394d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,3 @@ -#![feature(bool_to_option)] -#![feature(command_access)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] @@ -64,7 +62,7 @@ struct ClippyCmd { unstable_options: bool, cargo_subcommand: &'static str, args: Vec, - clippy_args: Option, + clippy_args: Vec, } impl ClippyCmd { @@ -101,17 +99,16 @@ impl ClippyCmd { args.insert(0, "+nightly".to_string()); } - let mut clippy_args = old_args.collect::>().join(" "); - if cargo_subcommand == "fix" && !clippy_args.contains("--no-deps") { - clippy_args = format!("{} --no-deps", clippy_args); + let mut clippy_args: Vec = old_args.collect(); + if cargo_subcommand == "fix" && !clippy_args.iter().any(|arg| arg == "--no-deps") { + clippy_args.push("--no-deps".into()); } - let has_args = !clippy_args.is_empty(); ClippyCmd { unstable_options, cargo_subcommand, args, - clippy_args: has_args.then_some(clippy_args), + clippy_args, } } @@ -151,24 +148,20 @@ impl ClippyCmd { .map(|p| ("CARGO_TARGET_DIR", p)) } - fn into_std_cmd(self, rustflags: Option) -> Command { + fn into_std_cmd(self) -> Command { let mut cmd = Command::new("cargo"); + let clippy_args: String = self + .clippy_args + .iter() + .map(|arg| format!("{}__CLIPPY_HACKERY__", arg)) + .collect(); cmd.env(self.path_env(), Self::path()) .envs(ClippyCmd::target_dir()) + .env("CLIPPY_ARGS", clippy_args) .arg(self.cargo_subcommand) .args(&self.args); - // HACK: pass Clippy args to the driver *also* through RUSTFLAGS. - // This guarantees that new builds will be triggered when Clippy flags change. - if let Some(clippy_args) = self.clippy_args { - cmd.env( - "RUSTFLAGS", - rustflags.map_or(clippy_args.clone(), |flags| format!("{} {}", clippy_args, flags)), - ); - cmd.env("CLIPPY_ARGS", clippy_args); - } - cmd } } @@ -179,7 +172,7 @@ where { let cmd = ClippyCmd::new(old_args); - let mut cmd = cmd.into_std_cmd(env::var("RUSTFLAGS").ok()); + let mut cmd = cmd.into_std_cmd(); let exit_status = cmd .spawn() @@ -197,7 +190,6 @@ where #[cfg(test)] mod tests { use super::ClippyCmd; - use std::ffi::OsStr; #[test] #[should_panic] @@ -212,7 +204,6 @@ mod tests { .split_whitespace() .map(ToString::to_string); let cmd = ClippyCmd::new(args); - assert_eq!("fix", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); assert!(cmd.args.iter().any(|arg| arg.ends_with("unstable-options"))); @@ -224,8 +215,7 @@ mod tests { .split_whitespace() .map(ToString::to_string); let cmd = ClippyCmd::new(args); - - assert!(cmd.clippy_args.unwrap().contains("--no-deps")); + assert!(cmd.clippy_args.iter().any(|arg| arg == "--no-deps")); } #[test] @@ -234,15 +224,13 @@ mod tests { .split_whitespace() .map(ToString::to_string); let cmd = ClippyCmd::new(args); - - assert_eq!(1, cmd.clippy_args.unwrap().matches("--no-deps").count()); + assert_eq!(cmd.clippy_args.iter().filter(|arg| *arg == "--no-deps").count(), 1); } #[test] fn check() { let args = "cargo clippy".split_whitespace().map(ToString::to_string); let cmd = ClippyCmd::new(args); - assert_eq!("check", cmd.cargo_subcommand); assert_eq!("RUSTC_WRAPPER", cmd.path_env()); } @@ -253,63 +241,7 @@ mod tests { .split_whitespace() .map(ToString::to_string); let cmd = ClippyCmd::new(args); - assert_eq!("check", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); } - - #[test] - fn clippy_args_into_rustflags() { - let args = "cargo clippy -- -W clippy::as_conversions" - .split_whitespace() - .map(ToString::to_string); - let cmd = ClippyCmd::new(args); - - let rustflags = None; - let cmd = cmd.into_std_cmd(rustflags); - - assert!(cmd - .get_envs() - .any(|(key, val)| key == "RUSTFLAGS" && val == Some(OsStr::new("-W clippy::as_conversions")))); - } - - #[test] - fn clippy_args_respect_existing_rustflags() { - let args = "cargo clippy -- -D clippy::await_holding_lock" - .split_whitespace() - .map(ToString::to_string); - let cmd = ClippyCmd::new(args); - - let rustflags = Some(r#"--cfg feature="some_feat""#.into()); - let cmd = cmd.into_std_cmd(rustflags); - - assert!(cmd.get_envs().any(|(key, val)| key == "RUSTFLAGS" - && val == Some(OsStr::new(r#"-D clippy::await_holding_lock --cfg feature="some_feat""#)))); - } - - #[test] - fn no_env_change_if_no_clippy_args() { - let args = "cargo clippy".split_whitespace().map(ToString::to_string); - let cmd = ClippyCmd::new(args); - - let rustflags = Some(r#"--cfg feature="some_feat""#.into()); - let cmd = cmd.into_std_cmd(rustflags); - - assert!(!cmd - .get_envs() - .any(|(key, _)| key == "RUSTFLAGS" || key == "CLIPPY_ARGS")); - } - - #[test] - fn no_env_change_if_no_clippy_args_nor_rustflags() { - let args = "cargo clippy".split_whitespace().map(ToString::to_string); - let cmd = ClippyCmd::new(args); - - let rustflags = None; - let cmd = cmd.into_std_cmd(rustflags); - - assert!(!cmd - .get_envs() - .any(|(key, _)| key == "RUSTFLAGS" || key == "CLIPPY_ARGS")) - } } diff --git a/tests/dogfood.rs b/tests/dogfood.rs index fda1413868e8..052223d6d6ff 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -23,7 +23,7 @@ fn dogfood_clippy() { .current_dir(root_dir) .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") - .arg("clippy") + .arg("clippy-preview") .arg("--all-targets") .arg("--all-features") .arg("--") From 510616fc0705c94c389710ad5fd47bc97eb2bfa1 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 23 Dec 2020 12:47:20 +0100 Subject: [PATCH 534/719] Rustup to rustc 1.50.0-nightly (bb1fbbf84 2020-12-22) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index fca771e13e14..d6ad24bcf26d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2020-12-18 +nightly-2020-12-23 From 87397080b697384a9dfb42993c86a0d17182b85a Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Wed, 23 Dec 2020 21:11:59 +0900 Subject: [PATCH 535/719] Fix typo in simplify_try.rs assigment -> assignment --- compiler/rustc_mir/src/transform/simplify_try.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index bea95bf43d21..a3459887a9a7 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -306,7 +306,7 @@ fn optimization_applies<'tcx>( return false; } - // Verify the assigment chain consists of the form b = a; c = b; d = c; etc... + // Verify the assignment chain consists of the form b = a; c = b; d = c; etc... if opt_info.field_tmp_assignments.is_empty() { trace!("NO: no assignments found"); return false; From ceb66ad464287d9f2232d7b81857c514a22236c0 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 22 Dec 2020 21:26:17 -0500 Subject: [PATCH 536/719] Add more tests --- src/librustdoc/clean/mod.rs | 2 +- src/test/rustdoc/async-fn.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e7fdf76ba797..6e4ec016aad4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1448,7 +1448,7 @@ impl Clean for hir::Ty<'_> { // There are two times a `Fresh` lifetime can be created: // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`. // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`. - // See commit 749349fc9f7b12f212bca9ba2297e463328cb701 for more information. + // See #59286 for more information. // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it. // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though; // there's no case where it could cause the function to fail to compile. diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs index 7a673b9f6706..f0fd9703915e 100644 --- a/src/test/rustdoc/async-fn.rs +++ b/src/test/rustdoc/async-fn.rs @@ -49,6 +49,8 @@ impl Foo { pub async fn mut_self(mut self, mut first: usize) {} } +pub trait Pattern<'a> {} + pub trait Trait {} // @has async_fn/fn.const_generics.html // @has - '//pre[@class="rust fn"]' 'pub async fn const_generics(_: impl Trait)' @@ -70,6 +72,9 @@ pub async fn static_trait(foo: &str) -> Box {} // @has async_fn/fn.lifetime_for_trait.html // @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box" pub async fn lifetime_for_trait(foo: &str) -> Box {} +// @has async_fn/fn.elided_in_input_trait.html +// @has - '//pre[@class="rust fn"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)" +pub async fn elided_in_input_trait(t: impl Pattern<'_>) {} struct AsyncFdReadyGuard<'a, T> { x: &'a T } @@ -80,4 +85,14 @@ impl Foo { // taken from `tokio` as an example of a method that was particularly bad before // @has - '//h4[@class="method"]' "pub async fn readable(&self) -> Result, ()>" pub async fn readable(&self) -> Result, ()> {} + // @has - '//h4[@class="method"]' "pub async fn mut_self(&mut self)" + pub async fn mut_self(&mut self) {} } + +// test named lifetimes, just in case +// @has async_fn/fn.named.html +// @has - '//pre[@class="rust fn"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str" +pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {} +// @has async_fn/fn.named_trait.html +// @has - '//pre[@class="rust fn"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>" +pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {} From 979d3ce6eafa1e9147a1a5282f6eea12126b29c9 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 23 Dec 2020 10:24:29 -0500 Subject: [PATCH 537/719] Add more comments to trait queries This also adds back a comment that was mistakenly removed in ac9dfc3e7785c9bba96ebac4fd51726189e1bf91. --- compiler/rustc_middle/src/query/mod.rs | 45 ++++++++++++++++++-------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1b5f7a2c12e7..1e836d0a8425 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -576,11 +576,13 @@ rustc_queries! { desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } } - query impl_trait_ref(key: DefId) -> Option> { - desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(key) } + /// Given an `impl_id`, return the trait it implements. + /// Return `None` if this is an inherent impl. + query impl_trait_ref(impl_id: DefId) -> Option> { + desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } } - query impl_polarity(key: DefId) -> ty::ImplPolarity { - desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(key) } + query impl_polarity(impl_id: DefId) -> ty::ImplPolarity { + desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) } } query issue33140_self_ty(key: DefId) -> Option> { @@ -917,8 +919,10 @@ rustc_queries! { } TypeChecking { - query trait_of_item(def_id: DefId) -> Option { - desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(def_id) } + /// Given an `associated_item`, find the trait it belongs to. + /// Return `None` if the `DefId` is not an associated item. + query trait_of_item(associated_item: DefId) -> Option { + desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) } } } @@ -948,20 +952,29 @@ rustc_queries! { } TypeChecking { - query all_local_trait_impls(key: CrateNum) -> &'tcx BTreeMap> { + /// Return all `impl` blocks in the current crate. + /// + /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number. + /// Passing in any other crate will cause an ICE. + /// + /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE + query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap> { desc { "local trait impls" } } - query trait_impls_of(key: DefId) -> ty::trait_def::TraitImpls { + + /// Given a trait `trait_id`, return all known `impl` blocks. + query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls { storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) } + desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) } } - query specialization_graph_of(key: DefId) -> specialization_graph::Graph { + + query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph { storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) } + desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } } - query object_safety_violations(key: DefId) -> &'tcx [traits::ObjectSafetyViolation] { - desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } + query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] { + desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) } } /// Gets the ParameterEnvironment for a given item; this environment @@ -969,6 +982,7 @@ rustc_queries! { /// type-checking etc, and it does not normalize specializable /// associated types. This is almost always what you want, /// unless you are doing MIR optimizations, in which case you + /// might want to use `reveal_all()` method to change modes. query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> { desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } } @@ -1229,10 +1243,15 @@ rustc_queries! { } TypeChecking { + /// Given a crate and a trait, look up all impls of that trait in the crate. + /// Return `(impl_id, self_ty)`. query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [(DefId, Option)] { desc { "looking up implementations of a trait in a crate" } } + + /// Given a crate, look up all trait impls in that crate. + /// Return `(impl_id, self_ty)`. query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option)] { desc { "looking up all (?) trait implementations" } From 468af39ef2f689ed151018fc76c571c2c9804893 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 22 Dec 2020 19:42:03 -0800 Subject: [PATCH 538/719] Update cargo --- Cargo.lock | 20 ++++++++++---------- src/tools/cargo | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcfd23f2dae5..8fbfa8d64282 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -895,9 +895,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.31" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9447ad28eee2a5cfb031c329d46bef77487244fff6a724b378885b8691a35f78" +checksum = "e268162af1a5fe89917ae25ba3b0a77c8da752bdc58e7dbb4f15b91fbd33756e" dependencies = [ "curl-sys", "libc", @@ -910,9 +910,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.34+curl-7.71.1" +version = "0.4.39+curl-7.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad4eff0be6985b7e709f64b5a541f700e9ad1407190a29f4884319eb663ed1d6" +checksum = "07a8ce861e7b68a0b394e814d7ee9f1b2750ff8bd10372c6ad3bacc10e86f874" dependencies = [ "cc", "libc", @@ -1330,9 +1330,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.12" +version = "0.13.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224" +checksum = "186dd99cc77576e58344ad614fa9bb27bad9d048f85de3ca850c1f4e8b048260" dependencies = [ "bitflags", "libc", @@ -1345,9 +1345,9 @@ dependencies = [ [[package]] name = "git2-curl" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502d532a2d06184beb3bc869d4d90236e60934e3382c921b203fa3c33e212bd7" +checksum = "883539cb0ea94bab3f8371a98cd8e937bbe9ee7c044499184aa4c17deb643a50" dependencies = [ "curl", "git2", @@ -1759,9 +1759,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.12.14+1.1.0" +version = "0.12.16+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" +checksum = "9f91b2f931ee975a98155195be8cd82d02e8e029d7d793d2bac1b8181ac97020" dependencies = [ "cc", "libc", diff --git a/src/tools/cargo b/src/tools/cargo index a3c2627fbc2f..75d5d8cffe34 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit a3c2627fbc2f5391c65ba45ab53b81bf71fa323c +Subproject commit 75d5d8cffe3464631f82dcd3c470b78dc1dda8bb From 4a4426377e8f1ad61dd6d4bb3525bbf2997889b9 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 13 Dec 2020 11:32:57 -0500 Subject: [PATCH 539/719] Box ItemKind to reduce the size of `Item` This brings the size of `Item` from ``` [src/librustdoc/lib.rs:103] std::mem::size_of::() = 680 ``` to ``` [src/librustdoc/lib.rs:103] std::mem::size_of::() = 280 ``` --- src/librustdoc/clean/auto_trait.rs | 2 +- src/librustdoc/clean/blanket_impl.rs | 2 +- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 6 +- src/librustdoc/clean/types.rs | 12 ++-- src/librustdoc/clean/utils.rs | 6 +- src/librustdoc/fold.rs | 8 +-- src/librustdoc/formats/cache.rs | 55 +++++++++---------- src/librustdoc/formats/item_type.rs | 2 +- src/librustdoc/formats/mod.rs | 2 +- src/librustdoc/formats/renderer.rs | 2 +- src/librustdoc/html/render/cache.rs | 2 +- src/librustdoc/html/render/mod.rs | 53 +++++++++--------- src/librustdoc/json/conversions.rs | 4 +- src/librustdoc/json/mod.rs | 4 +- .../passes/calculate_doc_coverage.rs | 2 +- src/librustdoc/passes/collect_trait_impls.rs | 8 +-- src/librustdoc/passes/doc_test_lints.rs | 2 +- src/librustdoc/passes/strip_hidden.rs | 2 +- src/librustdoc/passes/stripper.rs | 8 +-- 20 files changed, 90 insertions(+), 94 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 96d19e8e17de..3ca02b610634 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -123,7 +123,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { attrs: Default::default(), visibility: Inherited, def_id: self.cx.next_def_id(param_env_def_id.krate), - kind: ImplItem(Impl { + kind: box ImplItem(Impl { unsafety: hir::Unsafety::Normal, generics: new_generics, provided_trait_methods: Default::default(), diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index d99055e1145b..ba3eb007e384 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { attrs: Default::default(), visibility: Inherited, def_id: self.cx.next_def_id(impl_def_id.krate), - kind: ImplItem(Impl { + kind: box ImplItem(Impl { unsafety: hir::Unsafety::Normal, generics: ( self.cx.tcx.generics_of(impl_def_id), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index be4c62d891d0..c168c56d30d0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -482,7 +482,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet) source: clean::Span::dummy(), def_id: DefId::local(CRATE_DEF_INDEX), visibility: clean::Public, - kind: clean::ImportItem(clean::Import::new_simple( + kind: box clean::ImportItem(clean::Import::new_simple( item.ident.name, clean::ImportSource { path: clean::Path { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index de53ce8d95c1..a81ea1630cd4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2144,7 +2144,7 @@ fn clean_extern_crate( source: krate.span.clean(cx), def_id: crate_def_id, visibility: krate.vis.clean(cx), - kind: ExternCrateItem(name, orig_name), + kind: box ExternCrateItem(name, orig_name), }] } @@ -2212,7 +2212,7 @@ impl Clean> for doctree::Import<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - kind: ImportItem(Import::new_simple( + kind: box ImportItem(Import::new_simple( self.name, resolve_use_source(cx, path), false, @@ -2230,7 +2230,7 @@ impl Clean> for doctree::Import<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - kind: ImportItem(inner), + kind: box ImportItem(inner), }] } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9b2003911a70..fc977704e449 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -84,7 +84,7 @@ crate struct Item { crate name: Option, crate attrs: Attributes, crate visibility: Visibility, - crate kind: ItemKind, + crate kind: Box, crate def_id: DefId, } @@ -152,7 +152,7 @@ impl Item { Item { def_id, - kind, + kind: box kind, name, source: source.clean(cx), attrs: cx.tcx.get_attrs(def_id).clean(cx), @@ -171,7 +171,7 @@ impl Item { } crate fn is_crate(&self) -> bool { - match self.kind { + match *self.kind { StrippedItem(box ModuleItem(Module { is_crate: true, .. })) | ModuleItem(Module { is_crate: true, .. }) => true, _ => false, @@ -223,14 +223,14 @@ impl Item { self.type_() == ItemType::Keyword } crate fn is_stripped(&self) -> bool { - match self.kind { + match *self.kind { StrippedItem(..) => true, ImportItem(ref i) => !i.should_be_displayed, _ => false, } } crate fn has_stripped_fields(&self) -> Option { - match self.kind { + match *self.kind { StructItem(ref _struct) => Some(_struct.fields_stripped), UnionItem(ref union) => Some(union.fields_stripped), VariantItem(Variant { kind: VariantKind::Struct(ref vstruct) }) => { @@ -281,7 +281,7 @@ impl Item { } crate fn is_default(&self) -> bool { - match self.kind { + match *self.kind { ItemKind::MethodItem(_, Some(defaultness)) => { defaultness.has_value() && !defaultness.is_final() } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 270321aaa118..2e479d25203d 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -43,7 +43,7 @@ crate fn krate(mut cx: &mut DocContext<'_>) -> Crate { let mut module = module.clean(cx); let mut masked_crates = FxHashSet::default(); - match module.kind { + match *module.kind { ItemKind::ModuleItem(ref module) => { for it in &module.items { // `compiler_builtins` should be masked too, but we can't apply @@ -61,7 +61,7 @@ crate fn krate(mut cx: &mut DocContext<'_>) -> Crate { let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); { - let m = match module.kind { + let m = match *module.kind { ItemKind::ModuleItem(ref mut m) => m, _ => unreachable!(), }; @@ -338,7 +338,7 @@ crate fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut let tcx = cx.tcx; for item in items { - let target = match item.kind { + let target = match *item.kind { ItemKind::TypedefItem(ref t, true) => &t.type_, _ => continue, }; diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 285fabdc3723..343c6e779c15 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -5,9 +5,9 @@ crate struct StripItem(pub Item); impl StripItem { crate fn strip(self) -> Option { match self.0 { - Item { kind: StrippedItem(..), .. } => Some(self.0), + Item { kind: box StrippedItem(..), .. } => Some(self.0), mut i => { - i.kind = StrippedItem(box i.kind); + i.kind = box StrippedItem(i.kind); Some(i) } } @@ -72,9 +72,9 @@ crate trait DocFolder: Sized { /// don't override! fn fold_item_recur(&mut self, mut item: Item) -> Item { - item.kind = match item.kind { + item.kind = box match *item.kind { StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)), - _ => self.fold_inner_recur(item.kind), + _ => self.fold_inner_recur(*item.kind), }; item } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 77a3e9fa9549..899d61d8e43d 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -219,7 +219,7 @@ impl DocFolder for Cache { // If this is a stripped module, // we don't want it or its children in the search index. - let orig_stripped_mod = match item.kind { + let orig_stripped_mod = match *item.kind { clean::StrippedItem(box clean::ModuleItem(..)) => { mem::replace(&mut self.stripped_mod, true) } @@ -228,7 +228,7 @@ impl DocFolder for Cache { // If the impl is from a masked crate or references something from a // masked crate then remove it completely. - if let clean::ImplItem(ref i) = item.kind { + if let clean::ImplItem(ref i) = *item.kind { if self.masked_crates.contains(&item.def_id.krate) || i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) || i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) @@ -239,12 +239,12 @@ impl DocFolder for Cache { // Propagate a trait method's documentation to all implementors of the // trait. - if let clean::TraitItem(ref t) = item.kind { + if let clean::TraitItem(ref t) = *item.kind { self.traits.entry(item.def_id).or_insert_with(|| t.clone()); } // Collect all the implementors of traits. - if let clean::ImplItem(ref i) = item.kind { + if let clean::ImplItem(ref i) = *item.kind { if let Some(did) = i.trait_.def_id() { if i.blanket_impl.is_none() { self.implementors @@ -257,7 +257,7 @@ impl DocFolder for Cache { // Index this method for searching later on. if let Some(ref s) = item.name { - let (parent, is_inherent_impl_item) = match item.kind { + let (parent, is_inherent_impl_item) = match *item.kind { clean::StrippedItem(..) => ((None, None), false), clean::AssocConstItem(..) | clean::TypedefItem(_, true) if self.parent_is_trait_impl => @@ -348,7 +348,7 @@ impl DocFolder for Cache { _ => false, }; - match item.kind { + match *item.kind { clean::StructItem(..) | clean::EnumItem(..) | clean::TypedefItem(..) @@ -387,7 +387,7 @@ impl DocFolder for Cache { // Maintain the parent stack let orig_parent_is_trait_impl = self.parent_is_trait_impl; - let parent_pushed = match item.kind { + let parent_pushed = match *item.kind { clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem @@ -425,38 +425,33 @@ impl DocFolder for Cache { // Once we've recursively found all the generics, hoard off all the // implementations elsewhere. let item = self.fold_item_recur(item); - let ret = if let clean::Item { kind: clean::ImplItem(_), .. } = item { + let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item { // Figure out the id of this impl. This may map to a // primitive rather than always to a struct/enum. // Note: matching twice to restrict the lifetime of the `i` borrow. let mut dids = FxHashSet::default(); - if let clean::Item { kind: clean::ImplItem(ref i), .. } = item { - match i.for_ { - clean::ResolvedPath { did, .. } - | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => { + match i.for_ { + clean::ResolvedPath { did, .. } + | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => { + dids.insert(did); + } + ref t => { + let did = + t.primitive_type().and_then(|t| self.primitive_locations.get(&t).cloned()); + + if let Some(did) = did { dids.insert(did); } - ref t => { - let did = t - .primitive_type() - .and_then(|t| self.primitive_locations.get(&t).cloned()); + } + } - if let Some(did) = did { - dids.insert(did); - } + if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { + for bound in generics { + if let Some(did) = bound.def_id() { + dids.insert(did); } } - - if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { - for bound in generics { - if let Some(did) = bound.def_id() { - dids.insert(did); - } - } - } - } else { - unreachable!() - }; + } let impl_item = Impl { impl_item: item }; if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) { for did in dids { diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index af512e374609..ad51adf2fe3f 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -60,7 +60,7 @@ impl Serialize for ItemType { impl<'a> From<&'a clean::Item> for ItemType { fn from(item: &'a clean::Item) -> ItemType { - let kind = match item.kind { + let kind = match *item.kind { clean::StrippedItem(box ref item) => item, ref kind => kind, }; diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs index 55fd4948f452..58b9f5fbf0f6 100644 --- a/src/librustdoc/formats/mod.rs +++ b/src/librustdoc/formats/mod.rs @@ -32,7 +32,7 @@ crate struct Impl { impl Impl { crate fn inner_impl(&self) -> &clean::Impl { - match self.impl_item.kind { + match *self.impl_item.kind { clean::ImplItem(ref impl_) => impl_, _ => panic!("non-impl item found in impl"), } diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index fbbd3c1ccf51..e84a9853d9b7 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -89,7 +89,7 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( } cx.mod_item_in(&item, &name, &cache)?; - let module = match item.kind { + let module = match *item.kind { clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m, _ => unreachable!(), }; diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 25fe31aab594..c408e576639d 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -165,7 +165,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { } crate fn get_index_search_type(item: &clean::Item) -> Option { - let (all_types, ret_types) = match item.kind { + let (all_types, ret_types) = match *item.kind { clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types), clean::MethodItem(ref m, _) => (&m.all_types, &m.ret_types), clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types), diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 97e7c38ecb8c..db1744f28539 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -633,7 +633,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // Render sidebar-items.js used throughout this module. if !self.render_redirect_pages { - let module = match item.kind { + let module = match *item.kind { clean::StrippedItem(box clean::ModuleItem(ref m)) | clean::ModuleItem(ref m) => m, _ => unreachable!(), }; @@ -1739,7 +1739,7 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Ca write!(buf, ""); // out-of-band write!(buf, ""); - let name = match item.kind { + let name = match *item.kind { clean::ModuleItem(ref m) => { if m.is_crate { "Crate " @@ -1788,7 +1788,7 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, cache: &Ca write!(buf, "

"); // in-band - match item.kind { + match *item.kind { clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items), clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => { item_function(buf, cx, item, f) @@ -2149,7 +2149,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl ); } - match myitem.kind { + match *myitem.kind { clean::ExternCrateItem(ref name, ref src) => { use crate::html::format::anchor; @@ -2185,7 +2185,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl continue; } - let unsafety_flag = match myitem.kind { + let unsafety_flag = match *myitem.kind { clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func) if func.header.unsafety == hir::Unsafety::Unsafe => { @@ -2624,7 +2624,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra } for (pos, m) in provided.iter().enumerate() { render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx); - match m.kind { + match *m.kind { clean::MethodItem(ref inner, _) if !inner.generics.where_predicates.is_empty() => { @@ -3051,7 +3051,7 @@ fn render_assoc_item( where_clause = WhereClause { gens: g, indent, end_newline } ) } - match item.kind { + match *item.kind { clean::StrippedItem(..) => {} clean::TyMethodItem(ref m) => { method(w, item, m.header, &m.generics, &m.decl, link, parent, cx) @@ -3098,7 +3098,7 @@ fn item_struct( let mut fields = s .fields .iter() - .filter_map(|f| match f.kind { + .filter_map(|f| match *f.kind { clean::StructFieldItem(ref ty) => Some((f, ty)), _ => None, }) @@ -3148,7 +3148,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni let mut fields = s .fields .iter() - .filter_map(|f| match f.kind { + .filter_map(|f| match *f.kind { clean::StructFieldItem(ref ty) => Some((f, ty)), _ => None, }) @@ -3201,7 +3201,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum for v in &e.variants { write!(w, " "); let name = v.name.as_ref().unwrap(); - match v.kind { + match *v.kind { clean::VariantItem(ref var) => match var.kind { clean::VariantKind::CLike => write!(w, "{}", name), clean::VariantKind::Tuple(ref tys) => { @@ -3251,7 +3251,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum id = id, name = variant.name.as_ref().unwrap() ); - if let clean::VariantItem(ref var) = variant.kind { + if let clean::VariantItem(ref var) = *variant.kind { if let clean::VariantKind::Tuple(ref tys) = var.kind { write!(w, "("); for (i, ty) in tys.iter().enumerate() { @@ -3268,7 +3268,8 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum document_non_exhaustive(w, variant); use crate::clean::{Variant, VariantKind}; - if let clean::VariantItem(Variant { kind: VariantKind::Struct(ref s) }) = variant.kind { + if let clean::VariantItem(Variant { kind: VariantKind::Struct(ref s) }) = *variant.kind + { let variant_id = cx.derive_id(format!( "{}.{}.fields", ItemType::Variant, @@ -3282,7 +3283,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum ); for field in &s.fields { use crate::clean::StructFieldItem; - if let StructFieldItem(ref ty) = field.kind { + if let StructFieldItem(ref ty) = *field.kind { let id = cx.derive_id(format!( "variant.{}.field.{}", variant.name.as_ref().unwrap(), @@ -3379,7 +3380,7 @@ fn render_struct( let mut has_visible_fields = false; write!(w, " {{"); for field in fields { - if let clean::StructFieldItem(ref ty) = field.kind { + if let clean::StructFieldItem(ref ty) = *field.kind { write!( w, "\n{} {}{}: {},", @@ -3410,7 +3411,7 @@ fn render_struct( if i > 0 { write!(w, ", "); } - match field.kind { + match *field.kind { clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), clean::StructFieldItem(ref ty) => { write!(w, "{}{}", field.visibility.print_with_space(cx.tcx()), ty.print()) @@ -3457,7 +3458,7 @@ fn render_union( write!(w, " {{\n{}", tab); for field in fields { - if let clean::StructFieldItem(ref ty) = field.kind { + if let clean::StructFieldItem(ref ty) = *field.kind { write!( w, " {}{}: {},\n{}", @@ -3619,7 +3620,7 @@ fn render_deref_methods( .inner_impl() .items .iter() - .find_map(|item| match item.kind { + .find_map(|item| match *item.kind { clean::TypedefItem(ref t, true) => Some(match *t { clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_), _ => (&t.type_, &t.type_), @@ -3641,7 +3642,7 @@ fn render_deref_methods( } fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { - let self_type_opt = match item.kind { + let self_type_opt = match *item.kind { clean::MethodItem(ref method, _) => method.decl.self_type(), clean::TyMethodItem(ref method) => method.decl.self_type(), _ => None, @@ -3692,7 +3693,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String { )); let t_did = impl_.trait_.def_id().unwrap(); for it in &impl_.items { - if let clean::TypedefItem(ref tydef, _) = it.kind { + if let clean::TypedefItem(ref tydef, _) = *it.kind { out.push_str(" "); assoc_type( &mut out, @@ -3764,7 +3765,7 @@ fn render_impl( fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute); if show_def_docs { for it in &i.inner_impl().items { - if let clean::TypedefItem(ref tydef, _) = it.kind { + if let clean::TypedefItem(ref tydef, _) = *it.kind { write!(w, " "); assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), ""); write!(w, ";"); @@ -3846,7 +3847,7 @@ fn render_impl( } else { (true, " hidden") }; - match item.kind { + match *item.kind { clean::MethodItem(..) | clean::TyMethodItem(_) => { // Only render when the method is not static or we allow static methods if render_method_item { @@ -4123,7 +4124,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache: write!( buffer, "

{}{}

", - match it.kind { + match *it.kind { clean::StructItem(..) => "Struct ", clean::TraitItem(..) => "Trait ", clean::PrimitiveItem(..) => "Primitive Type ", @@ -4163,7 +4164,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache: it.name.as_ref().expect("crates always have a name") ); } - match it.kind { + match *it.kind { clean::StructItem(ref s) => sidebar_struct(buffer, it, s), clean::TraitItem(ref t) => sidebar_trait(buffer, it, t), clean::PrimitiveItem(_) => sidebar_primitive(buffer, it), @@ -4303,7 +4304,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { .find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did) { if let Some((target, real_target)) = - impl_.inner_impl().items.iter().find_map(|item| match item.kind { + impl_.inner_impl().items.iter().find_map(|item| match *item.kind { clean::TypedefItem(ref t, true) => Some(match *t { clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_), _ => (&t.type_, &t.type_), @@ -4442,7 +4443,7 @@ fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) -> } fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> { - match item.kind { + match *item.kind { clean::ItemKind::ImplItem(ref i) => { if let Some(ref trait_) = i.trait_ { Some(( @@ -4593,7 +4594,7 @@ fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item) { fn get_struct_fields_name(fields: &[clean::Item]) -> String { let mut fields = fields .iter() - .filter(|f| if let clean::StructFieldItem(..) = f.kind { true } else { false }) + .filter(|f| matches!(*f.kind, clean::StructFieldItem(..))) .filter_map(|f| match f.name { Some(ref name) => { Some(format!("{name}", name = name)) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 3b7ac624ccd7..e347f7f84116 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -19,9 +19,9 @@ impl JsonRenderer<'_> { let item_type = ItemType::from(&item); let deprecation = item.deprecation(self.tcx); let clean::Item { source, name, attrs, kind, visibility, def_id } = item; - match kind { + match *kind { clean::StrippedItem(_) => None, - _ => Some(Item { + kind => Some(Item { id: def_id.into(), crate_id: def_id.krate.as_u32(), name: name.map(|sym| sym.to_string()), diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index dc2bc14e7ceb..df7ab9b7361a 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -178,9 +178,9 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { cache: &Cache, ) -> Result<(), Error> { use clean::types::ItemKind::*; - if let ModuleItem(m) = &item.kind { + if let ModuleItem(m) = &*item.kind { for item in &m.items { - match &item.kind { + match &*item.kind { // These don't have names so they don't get added to the output by default ImportItem(_) => self.item(item.clone(), cache).unwrap(), ExternCrateItem(_, _) => self.item(item.clone(), cache).unwrap(), diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 52f6a97089bd..6951b01e03d2 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -187,7 +187,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { fn fold_item(&mut self, i: clean::Item) -> Option { - match i.kind { + match *i.kind { _ if !i.def_id.is_local() => { // non-local items are skipped because they can be out of the users control, // especially in the case of trait impls, which rustdoc eagerly inlines diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 60fcbe748727..9b0ae09cb3fd 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -58,11 +58,11 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { // scan through included items ahead of time to splice in Deref targets to the "valid" sets for it in &new_items { - if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.kind { + if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind { if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() { let target = items .iter() - .find_map(|item| match item.kind { + .find_map(|item| match *item.kind { TypedefItem(ref t, true) => Some(&t.type_), _ => None, }) @@ -78,7 +78,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { } new_items.retain(|it| { - if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.kind { + if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind { cleaner.keep_item(for_) || trait_.as_ref().map_or(false, |t| cleaner.keep_item(t)) || blanket_impl.is_some() @@ -124,7 +124,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { } if let Some(ref mut it) = krate.module { - if let ModuleItem(Module { ref mut items, .. }) = it.kind { + if let ModuleItem(Module { ref mut items, .. }) = *it.kind { items.extend(synth.impls); items.extend(new_items); } else { diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 1c1141e7c812..68ce73f944b8 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -59,7 +59,7 @@ impl crate::doctest::Tester for Tests { crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool { if matches!( - item.kind, + *item.kind, clean::StructFieldItem(_) | clean::VariantItem(_) | clean::AssocConstItem(_, _) diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 6b59eb8cf288..5694ce27de84 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -41,7 +41,7 @@ impl<'a> DocFolder for Stripper<'a> { if i.attrs.lists(sym::doc).has_word(sym::hidden) { debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name); // use a dedicated hidden item for given item type if any - match i.kind { + match *i.kind { clean::StructFieldItem(..) | clean::ModuleItem(..) => { // We need to recurse into stripped modules to // strip things like impl methods but when doing so diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 444fd593ec9c..f872e403ab0f 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -13,7 +13,7 @@ crate struct Stripper<'a> { impl<'a> DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { - match i.kind { + match *i.kind { clean::StrippedItem(..) => { // We need to recurse into stripped modules to strip things // like impl methods but when doing so we must not add any @@ -86,7 +86,7 @@ impl<'a> DocFolder for Stripper<'a> { clean::KeywordItem(..) => {} } - let fastreturn = match i.kind { + let fastreturn = match *i.kind { // nothing left to do for traits (don't want to filter their // methods out, visibility controlled by the trait) clean::TraitItem(..) => true, @@ -121,7 +121,7 @@ crate struct ImplStripper<'a> { impl<'a> DocFolder for ImplStripper<'a> { fn fold_item(&mut self, i: Item) -> Option { - if let clean::ImplItem(ref imp) = i.kind { + if let clean::ImplItem(ref imp) = *i.kind { // emptied none trait impls can be stripped if imp.trait_.is_none() && imp.items.is_empty() { return None; @@ -160,7 +160,7 @@ crate struct ImportStripper; impl DocFolder for ImportStripper { fn fold_item(&mut self, i: Item) -> Option { - match i.kind { + match *i.kind { clean::ExternCrateItem(..) | clean::ImportItem(..) if !i.visibility.is_public() => None, _ => Some(self.fold_item_recur(i)), } From ddf82636c6b2d42a1fe9d25b51ec9b006043f529 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 26 Nov 2020 16:52:20 +0100 Subject: [PATCH 540/719] bootstrap: convert build-manifest to use the new Tarball struct --- src/bootstrap/dist.rs | 109 +++++++--------------------------- src/bootstrap/lib.rs | 1 + src/bootstrap/tarball.rs | 124 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 88 deletions(-) create mode 100644 src/bootstrap/tarball.rs diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index fcbde9c438cb..0ec896ed2115 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -19,6 +19,7 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; use crate::config::TargetSelection; +use crate::tarball::{OverlayKind, Tarball}; use crate::tool::{self, Tool}; use crate::util::{exe, is_dylib, timeit}; use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; @@ -2517,68 +2518,36 @@ impl Step for RustDev { builder.info(&format!("Dist RustDev ({})", target)); let _time = timeit(builder); - let src = builder.src.join("src/llvm-project/llvm"); - let name = pkgname(builder, "rust-dev"); - let tmp = tmpdir(builder); - let image = tmp.join("rust-dev-image"); - drop(fs::remove_dir_all(&image)); - - // Prepare the image directory - let dst_bindir = image.join("bin"); - t!(fs::create_dir_all(&dst_bindir)); + let mut tarball = Tarball::new(builder, "rust-dev", &target.triple); + tarball.set_overlay(OverlayKind::LLVM); let src_bindir = builder.llvm_out(target).join("bin"); - let install_bin = - |name| builder.install(&src_bindir.join(exe(name, target)), &dst_bindir, 0o755); - install_bin("llvm-config"); - install_bin("llvm-ar"); - install_bin("llvm-objdump"); - install_bin("llvm-profdata"); - install_bin("llvm-bcanalyzer"); - install_bin("llvm-cov"); - install_bin("llvm-dwp"); - builder.install(&builder.llvm_filecheck(target), &dst_bindir, 0o755); + for bin in &[ + "llvm-config", + "llvm-ar", + "llvm-objdump", + "llvm-profdata", + "llvm-bcanalyzer", + "llvm-cov", + "llvm-dwp", + ] { + tarball.add_file(src_bindir.join(exe(bin, target)), "bin", 0o755); + } + tarball.add_file(&builder.llvm_filecheck(target), "bin", 0o755); // Copy the include directory as well; needed mostly to build // librustc_llvm properly (e.g., llvm-config.h is in here). But also // just broadly useful to be able to link against the bundled LLVM. - builder.cp_r(&builder.llvm_out(target).join("include"), &image.join("include")); + tarball.add_dir(&builder.llvm_out(target).join("include"), "."); // Copy libLLVM.so to the target lib dir as well, so the RPATH like // `$ORIGIN/../lib` can find it. It may also be used as a dependency // of `rustc-dev` to support the inherited `-lLLVM` when using the // compiler libraries. - maybe_install_llvm(builder, target, &image.join("lib")); + maybe_install_llvm(builder, target, &tarball.image_dir().join("lib")); - // Prepare the overlay - let overlay = tmp.join("rust-dev-overlay"); - drop(fs::remove_dir_all(&overlay)); - builder.create_dir(&overlay); - builder.install(&src.join("README.txt"), &overlay, 0o644); - builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644); - builder.create(&overlay.join("version"), &builder.rust_version()); - - // Generate the installer tarball - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=rust-dev-installed.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--component-name=rust-dev"); - - builder.run(&mut cmd); - Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) + Some(tarball.generate()) } } @@ -2607,45 +2576,9 @@ impl Step for BuildManifest { fn run(self, builder: &Builder<'_>) -> PathBuf { let build_manifest = builder.tool_exe(Tool::BuildManifest); - let name = pkgname(builder, "build-manifest"); - let tmp = tmpdir(builder); - - // Prepare the image. - let image = tmp.join("build-manifest-image"); - let image_bin = image.join("bin"); - let _ = fs::remove_dir_all(&image); - t!(fs::create_dir_all(&image_bin)); - builder.install(&build_manifest, &image_bin, 0o755); - - // Prepare the overlay. - let overlay = tmp.join("build-manifest-overlay"); - let _ = fs::remove_dir_all(&overlay); - builder.create_dir(&overlay); - builder.create(&overlay.join("version"), &builder.rust_version()); - for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] { - builder.install(&builder.src.join(file), &overlay, 0o644); - } - - // Create the final tarball. - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=build-manifest installed.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, self.target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--component-name=build-manifest"); - - builder.run(&mut cmd); - distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple)) + let tarball = Tarball::new(builder, "build-manifest", &self.target.triple); + tarball.add_file(&build_manifest, "bin", 0o755); + tarball.generate() } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index ece9bdc7a649..3b51bf272fcb 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -142,6 +142,7 @@ mod native; mod run; mod sanity; mod setup; +mod tarball; mod test; mod tool; mod toolstate; diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs new file mode 100644 index 000000000000..728d13443495 --- /dev/null +++ b/src/bootstrap/tarball.rs @@ -0,0 +1,124 @@ +use std::path::{Path, PathBuf}; + +use build_helper::t; + +use crate::builder::Builder; + +#[derive(Copy, Clone)] +pub(crate) enum OverlayKind { + Rust, + LLVM, +} + +impl OverlayKind { + fn included_files(&self) -> &[&str] { + match self { + OverlayKind::Rust => &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"], + OverlayKind::LLVM => { + &["src/llvm-project/llvm/LICENSE.TXT", "src/llvm-project/llvm/README.txt"] + } + } + } +} + +pub(crate) struct Tarball<'a> { + builder: &'a Builder<'a>, + + pkgname: String, + component: String, + target: String, + overlay: OverlayKind, + + temp_dir: PathBuf, + image_dir: PathBuf, + overlay_dir: PathBuf, + work_dir: PathBuf, +} + +impl<'a> Tarball<'a> { + pub(crate) fn new(builder: &'a Builder<'a>, component: &str, target: &str) -> Self { + let pkgname = crate::dist::pkgname(builder, component); + + let temp_dir = builder.out.join("tmp").join("tarball").join(component); + let _ = std::fs::remove_dir_all(&temp_dir); + + let image_dir = temp_dir.join("image"); + let overlay_dir = temp_dir.join("overlay"); + let work_dir = temp_dir.join("work"); + + Self { + builder, + + pkgname, + component: component.into(), + target: target.into(), + overlay: OverlayKind::Rust, + + temp_dir, + image_dir, + overlay_dir, + work_dir, + } + } + + pub(crate) fn set_overlay(&mut self, overlay: OverlayKind) { + self.overlay = overlay; + } + + pub(crate) fn image_dir(&self) -> &Path { + t!(std::fs::create_dir_all(&self.image_dir)); + &self.image_dir + } + + pub(crate) fn add_file(&self, src: impl AsRef, destdir: impl AsRef, perms: u32) { + // create_dir_all fails to create `foo/bar/.`, so when the destination is "." this simply + // uses the base directory as the destination directory. + let destdir = if destdir.as_ref() == Path::new(".") { + self.image_dir.clone() + } else { + self.image_dir.join(destdir.as_ref()) + }; + + t!(std::fs::create_dir_all(&destdir)); + self.builder.install(src.as_ref(), &destdir, perms); + } + + pub(crate) fn add_dir(&self, src: impl AsRef, destdir: impl AsRef) { + t!(std::fs::create_dir_all(destdir.as_ref())); + self.builder.cp_r( + src.as_ref(), + &self.image_dir.join(destdir.as_ref()).join(src.as_ref().file_name().unwrap()), + ); + } + + pub(crate) fn generate(self) -> PathBuf { + t!(std::fs::create_dir_all(&self.overlay_dir)); + self.builder.create(&self.overlay_dir.join("version"), &self.builder.rust_version()); + for file in self.overlay.included_files() { + self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644); + } + + let distdir = crate::dist::distdir(self.builder); + let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg(format!("--success-message={} installed.", self.component)) + .arg("--image-dir") + .arg(self.image_dir) + .arg("--work-dir") + .arg(self.work_dir) + .arg("--output-dir") + .arg(&distdir) + .arg("--non-installed-overlay") + .arg(self.overlay_dir) + .arg(format!("--package-name={}-{}", self.pkgname, self.target)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg(format!("--component-name={}", self.component)); + self.builder.run(&mut cmd); + + t!(std::fs::remove_dir_all(&self.temp_dir)); + + distdir.join(format!("{}-{}.tar.gz", self.pkgname, self.target)) + } +} From 7be85701cda29bbe715e462be856a61aed5bd4b4 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 26 Nov 2020 17:47:48 +0100 Subject: [PATCH 541/719] bootstrap: convert llvm-tools to use Tarball --- src/bootstrap/dist.rs | 44 +++++++--------------------------------- src/bootstrap/lib.rs | 4 ---- src/bootstrap/tarball.rs | 15 +++++++++++++- 3 files changed, 21 insertions(+), 42 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 0ec896ed2115..9b0a6e6e19d7 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2431,56 +2431,26 @@ impl Step for LlvmTools { builder.info(&format!("Dist LlvmTools ({})", target)); let _time = timeit(builder); - let src = builder.src.join("src/llvm-project/llvm"); - let name = pkgname(builder, "llvm-tools"); - let tmp = tmpdir(builder); - let image = tmp.join("llvm-tools-image"); - drop(fs::remove_dir_all(&image)); + let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple); + tarball.set_overlay(OverlayKind::LLVM); + tarball.is_preview(true); // Prepare the image directory let src_bindir = builder.llvm_out(target).join("bin"); - let dst_bindir = image.join("lib/rustlib").join(&*target.triple).join("bin"); - t!(fs::create_dir_all(&dst_bindir)); + let dst_bindir = format!("lib/rustlib/{}/bin", target.triple); for tool in LLVM_TOOLS { let exe = src_bindir.join(exe(tool, target)); - builder.install(&exe, &dst_bindir, 0o755); + tarball.add_file(&exe, &dst_bindir, 0o755); } // Copy libLLVM.so to the target lib dir as well, so the RPATH like // `$ORIGIN/../lib` can find it. It may also be used as a dependency // of `rustc-dev` to support the inherited `-lLLVM` when using the // compiler libraries. - maybe_install_llvm_target(builder, target, &image); + maybe_install_llvm_target(builder, target, tarball.image_dir()); - // Prepare the overlay - let overlay = tmp.join("llvm-tools-overlay"); - drop(fs::remove_dir_all(&overlay)); - builder.create_dir(&overlay); - builder.install(&src.join("README.txt"), &overlay, 0o644); - builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644); - builder.create(&overlay.join("version"), &builder.llvm_tools_vers()); - - // Generate the installer tarball - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=llvm-tools-installed.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--component-name=llvm-tools-preview"); - - builder.run(&mut cmd); - Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) + Some(tarball.generate()) } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 3b51bf272fcb..a47ddfbcc1f1 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1069,10 +1069,6 @@ impl Build { self.package_vers(&self.version) } - fn llvm_tools_vers(&self) -> String { - self.rust_version() - } - fn llvm_link_tools_dynamically(&self, target: TargetSelection) -> bool { target.contains("linux-gnu") || target.contains("apple-darwin") } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 728d13443495..2c110a7fb24b 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -33,6 +33,8 @@ pub(crate) struct Tarball<'a> { image_dir: PathBuf, overlay_dir: PathBuf, work_dir: PathBuf, + + is_preview: bool, } impl<'a> Tarball<'a> { @@ -58,6 +60,8 @@ impl<'a> Tarball<'a> { image_dir, overlay_dir, work_dir, + + is_preview: false, } } @@ -65,6 +69,10 @@ impl<'a> Tarball<'a> { self.overlay = overlay; } + pub(crate) fn is_preview(&mut self, is: bool) { + self.is_preview = is; + } + pub(crate) fn image_dir(&self) -> &Path { t!(std::fs::create_dir_all(&self.image_dir)); &self.image_dir @@ -98,6 +106,11 @@ impl<'a> Tarball<'a> { self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644); } + let mut component_name = self.component.clone(); + if self.is_preview { + component_name.push_str("-preview"); + } + let distdir = crate::dist::distdir(self.builder); let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller); cmd.arg("generate") @@ -114,7 +127,7 @@ impl<'a> Tarball<'a> { .arg(self.overlay_dir) .arg(format!("--package-name={}-{}", self.pkgname, self.target)) .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg(format!("--component-name={}", self.component)); + .arg(format!("--component-name={}", component_name)); self.builder.run(&mut cmd); t!(std::fs::remove_dir_all(&self.temp_dir)); From c768ce138427b1844c1f6594daba9c0e33928032 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 26 Nov 2020 22:20:45 +0100 Subject: [PATCH 542/719] bootstrap: convert rust-docs to use Tarball --- src/bootstrap/dist.rs | 45 ++++++++++------------------------------ src/bootstrap/tarball.rs | 19 ++++++++++------- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 9b0a6e6e19d7..26a621c41cae 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -55,7 +55,7 @@ pub struct Docs { } impl Step for Docs { - type Output = PathBuf; + type Output = Option; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -67,13 +67,10 @@ impl Step for Docs { } /// Builds the `rust-docs` installer component. - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; - - let name = pkgname(builder, "rust-docs"); - if !builder.config.docs { - return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple)); + return None; } builder.default_doc(None); @@ -81,34 +78,14 @@ impl Step for Docs { builder.info(&format!("Dist docs ({})", host)); let _time = timeit(builder); - let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple)); - let _ = fs::remove_dir_all(&image); + let dest = "share/doc/rust/html"; - let dst = image.join("share/doc/rust/html"); - t!(fs::create_dir_all(&dst)); - let src = builder.doc_out(host); - builder.cp_r(&src, &dst); - builder.install(&builder.src.join("src/doc/robots.txt"), &dst, 0o644); + let mut tarball = Tarball::new(builder, "rust-docs", &host.triple); + tarball.set_product_name("Rust Documentation"); + tarball.add_dir(&builder.doc_out(host), dest); + tarball.add_file(&builder.src.join("src/doc/robots.txt"), dest, 0o644); - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust-Documentation") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=Rust-documentation-is-installed.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg(format!("--package-name={}-{}", name, host.triple)) - .arg("--component-name=rust-docs") - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--bulk-dirs=share/doc/rust/html"); - builder.run(&mut cmd); - builder.remove_dir(&image); - - distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple)) + Some(tarball.generate()) } } @@ -1826,7 +1803,7 @@ impl Step for Extended { tarballs.extend(llvm_tools_installer); tarballs.push(analysis_installer); tarballs.push(std_installer); - if builder.config.docs { + if let Some(docs_installer) = docs_installer { tarballs.push(docs_installer); } if target.contains("pc-windows-gnu") { @@ -2509,7 +2486,7 @@ impl Step for RustDev { // Copy the include directory as well; needed mostly to build // librustc_llvm properly (e.g., llvm-config.h is in here). But also // just broadly useful to be able to link against the bundled LLVM. - tarball.add_dir(&builder.llvm_out(target).join("include"), "."); + tarball.add_dir(&builder.llvm_out(target).join("include"), "include"); // Copy libLLVM.so to the target lib dir as well, so the RPATH like // `$ORIGIN/../lib` can find it. It may also be used as a dependency diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 2c110a7fb24b..50d58d00a66e 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -27,6 +27,7 @@ pub(crate) struct Tarball<'a> { pkgname: String, component: String, target: String, + product_name: String, overlay: OverlayKind, temp_dir: PathBuf, @@ -54,6 +55,7 @@ impl<'a> Tarball<'a> { pkgname, component: component.into(), target: target.into(), + product_name: "Rust".into(), overlay: OverlayKind::Rust, temp_dir, @@ -69,6 +71,10 @@ impl<'a> Tarball<'a> { self.overlay = overlay; } + pub(crate) fn set_product_name(&mut self, name: &str) { + self.product_name = name.into(); + } + pub(crate) fn is_preview(&mut self, is: bool) { self.is_preview = is; } @@ -91,12 +97,11 @@ impl<'a> Tarball<'a> { self.builder.install(src.as_ref(), &destdir, perms); } - pub(crate) fn add_dir(&self, src: impl AsRef, destdir: impl AsRef) { - t!(std::fs::create_dir_all(destdir.as_ref())); - self.builder.cp_r( - src.as_ref(), - &self.image_dir.join(destdir.as_ref()).join(src.as_ref().file_name().unwrap()), - ); + pub(crate) fn add_dir(&self, src: impl AsRef, dest: impl AsRef) { + let dest = self.image_dir.join(dest.as_ref()); + + t!(std::fs::create_dir_all(&dest)); + self.builder.cp_r(src.as_ref(), &dest); } pub(crate) fn generate(self) -> PathBuf { @@ -114,7 +119,7 @@ impl<'a> Tarball<'a> { let distdir = crate::dist::distdir(self.builder); let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller); cmd.arg("generate") - .arg("--product-name=Rust") + .arg(format!("--product-name={}", self.product_name)) .arg("--rel-manifest-dir=rustlib") .arg(format!("--success-message={} installed.", self.component)) .arg("--image-dir") From 8ca46fc7a83734c9622f11f25d16b82316f44bcc Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 26 Nov 2020 22:24:34 +0100 Subject: [PATCH 543/719] bootstrap: convert rustc-docs to use Tarball --- src/bootstrap/dist.rs | 42 ++++++++---------------------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 26a621c41cae..5a9c82c52a6f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -95,7 +95,7 @@ pub struct RustcDocs { } impl Step for RustcDocs { - type Output = PathBuf; + type Output = Option; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -107,47 +107,21 @@ impl Step for RustcDocs { } /// Builds the `rustc-docs` installer component. - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; - - let name = pkgname(builder, "rustc-docs"); - if !builder.config.compiler_docs { - return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple)); + return None; } builder.default_doc(None); - - let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple)); - let _ = fs::remove_dir_all(&image); - - let dst = image.join("share/doc/rust/html/rustc"); - t!(fs::create_dir_all(&dst)); - let src = builder.compiler_doc_out(host); - builder.cp_r(&src, &dst); - - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rustc-Documentation") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=Rustc-documentation-is-installed.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg(format!("--package-name={}-{}", name, host.triple)) - .arg("--component-name=rustc-docs") - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--bulk-dirs=share/doc/rust/html/rustc"); - builder.info(&format!("Dist compiler docs ({})", host)); let _time = timeit(builder); - builder.run(&mut cmd); - builder.remove_dir(&image); - distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple)) + let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple); + tarball.set_product_name("Rustc Documentation"); + tarball.add_dir(&builder.compiler_doc_out(host), "share/doc/rust/html/rustc"); + + Some(tarball.generate()) } } From 82d9eaa54d3a60edc2dd664355e390ec9aa36fa5 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 26 Nov 2020 22:29:33 +0100 Subject: [PATCH 544/719] bootstrap: convert rust-mingw to use Tarball --- src/bootstrap/dist.rs | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 5a9c82c52a6f..cee8c411fa1f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -297,41 +297,23 @@ impl Step for Mingw { /// without any extra installed software (e.g., we bundle gcc, libraries, etc). fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; - if !host.contains("pc-windows-gnu") { return None; } builder.info(&format!("Dist mingw ({})", host)); let _time = timeit(builder); - let name = pkgname(builder, "rust-mingw"); - let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple)); - let _ = fs::remove_dir_all(&image); - t!(fs::create_dir_all(&image)); + + let mut tarball = Tarball::new(builder, "rust-mingw", &host.triple); + tarball.set_product_name("Rust MinGW"); // The first argument is a "temporary directory" which is just // thrown away (this contains the runtime DLLs included in the rustc package // above) and the second argument is where to place all the MinGW components // (which is what we want). - make_win_dist(&tmpdir(builder), &image, host, &builder); + make_win_dist(&tmpdir(builder), tarball.image_dir(), host, &builder); - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust-MinGW") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=Rust-MinGW-is-installed.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg(format!("--package-name={}-{}", name, host.triple)) - .arg("--component-name=rust-mingw") - .arg("--legacy-manifest-dirs=rustlib,cargo"); - builder.run(&mut cmd); - t!(fs::remove_dir_all(&image)); - Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple))) + Some(tarball.generate()) } } From 0a2e1c5a2c85ff27f2677aa7db1c2deacf34242d Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 26 Nov 2020 22:42:52 +0100 Subject: [PATCH 545/719] bootstrap: convert rustc to use Tarball --- src/bootstrap/dist.rs | 60 ++++++---------------------------------- src/bootstrap/tarball.rs | 3 ++ 2 files changed, 11 insertions(+), 52 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index cee8c411fa1f..db792886c166 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -341,30 +341,13 @@ impl Step for Rustc { let compiler = self.compiler; let host = self.compiler.host; - let name = pkgname(builder, "rustc"); - let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple)); - let _ = fs::remove_dir_all(&image); - let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host.triple)); - let _ = fs::remove_dir_all(&overlay); + builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host.triple)); + let _time = timeit(builder); + + let tarball = Tarball::new(builder, "rustc", &host.triple); // Prepare the rustc "image", what will actually end up getting installed - prepare_image(builder, compiler, &image); - - // Prepare the overlay which is part of the tarball but won't actually be - // installed - let cp = |file: &str| { - builder.install(&builder.src.join(file), &overlay, 0o644); - }; - cp("COPYRIGHT"); - cp("LICENSE-APACHE"); - cp("LICENSE-MIT"); - cp("README.md"); - // tiny morsel of metadata is used by rust-packaging - let version = builder.rust_version(); - builder.create(&overlay.join("version"), &version); - if let Some(sha) = builder.rust_sha() { - builder.create(&overlay.join("git-commit-hash"), &sha); - } + prepare_image(builder, compiler, tarball.image_dir()); // On MinGW we've got a few runtime DLL dependencies that we need to // include. The first argument to this script is where to put these DLLs @@ -377,38 +360,11 @@ impl Step for Rustc { // install will *also* include the rust-mingw package, which also needs // licenses, so to be safe we just include it here in all MinGW packages. if host.contains("pc-windows-gnu") { - make_win_dist(&image, &tmpdir(builder), host, builder); - - let dst = image.join("share/doc"); - t!(fs::create_dir_all(&dst)); - builder.cp_r(&builder.src.join("src/etc/third-party"), &dst); + make_win_dist(tarball.image_dir(), &tmpdir(builder), host, builder); + tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc"); } - // Finally, wrap everything up in a nice tarball! - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=Rust-is-ready-to-roll.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, host.triple)) - .arg("--component-name=rustc") - .arg("--legacy-manifest-dirs=rustlib,cargo"); - - builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host.triple)); - let _time = timeit(builder); - builder.run(&mut cmd); - builder.remove_dir(&image); - builder.remove_dir(&overlay); - - return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple)); + return tarball.generate(); fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) { let host = compiler.host; diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 50d58d00a66e..294b69c85f48 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -107,6 +107,9 @@ impl<'a> Tarball<'a> { pub(crate) fn generate(self) -> PathBuf { t!(std::fs::create_dir_all(&self.overlay_dir)); self.builder.create(&self.overlay_dir.join("version"), &self.builder.rust_version()); + if let Some(sha) = self.builder.rust_sha() { + self.builder.create(&self.overlay_dir.join("git-commit-hash"), &sha); + } for file in self.overlay.included_files() { self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644); } From fd4515cb3f8a8e21d3640ffa8f2b3040a381b87c Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 26 Nov 2020 22:50:38 +0100 Subject: [PATCH 546/719] bootstrap: refactor showing the "dist" info --- src/bootstrap/dist.rs | 21 --------------------- src/bootstrap/tarball.rs | 7 +++++-- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index db792886c166..0e00649fc032 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -72,19 +72,14 @@ impl Step for Docs { if !builder.config.docs { return None; } - builder.default_doc(None); - builder.info(&format!("Dist docs ({})", host)); - let _time = timeit(builder); - let dest = "share/doc/rust/html"; let mut tarball = Tarball::new(builder, "rust-docs", &host.triple); tarball.set_product_name("Rust Documentation"); tarball.add_dir(&builder.doc_out(host), dest); tarball.add_file(&builder.src.join("src/doc/robots.txt"), dest, 0o644); - Some(tarball.generate()) } } @@ -112,15 +107,11 @@ impl Step for RustcDocs { if !builder.config.compiler_docs { return None; } - builder.default_doc(None); - builder.info(&format!("Dist compiler docs ({})", host)); - let _time = timeit(builder); let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple); tarball.set_product_name("Rustc Documentation"); tarball.add_dir(&builder.compiler_doc_out(host), "share/doc/rust/html/rustc"); - Some(tarball.generate()) } } @@ -301,9 +292,6 @@ impl Step for Mingw { return None; } - builder.info(&format!("Dist mingw ({})", host)); - let _time = timeit(builder); - let mut tarball = Tarball::new(builder, "rust-mingw", &host.triple); tarball.set_product_name("Rust MinGW"); @@ -341,9 +329,6 @@ impl Step for Rustc { let compiler = self.compiler; let host = self.compiler.host; - builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host.triple)); - let _time = timeit(builder); - let tarball = Tarball::new(builder, "rustc", &host.triple); // Prepare the rustc "image", what will actually end up getting installed @@ -2318,9 +2303,6 @@ impl Step for LlvmTools { } } - builder.info(&format!("Dist LlvmTools ({})", target)); - let _time = timeit(builder); - let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple); tarball.set_overlay(OverlayKind::LLVM); tarball.is_preview(true); @@ -2375,9 +2357,6 @@ impl Step for RustDev { } } - builder.info(&format!("Dist RustDev ({})", target)); - let _time = timeit(builder); - let mut tarball = Tarball::new(builder, "rust-dev", &target.triple); tarball.set_overlay(OverlayKind::LLVM); diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 294b69c85f48..f99b6f30192d 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -114,13 +114,17 @@ impl<'a> Tarball<'a> { self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644); } + let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller); + + self.builder.info(&format!("Dist {} ({})", self.component, self.target)); + let _time = crate::util::timeit(self.builder); + let mut component_name = self.component.clone(); if self.is_preview { component_name.push_str("-preview"); } let distdir = crate::dist::distdir(self.builder); - let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller); cmd.arg("generate") .arg(format!("--product-name={}", self.product_name)) .arg("--rel-manifest-dir=rustlib") @@ -137,7 +141,6 @@ impl<'a> Tarball<'a> { .arg("--legacy-manifest-dirs=rustlib,cargo") .arg(format!("--component-name={}", component_name)); self.builder.run(&mut cmd); - t!(std::fs::remove_dir_all(&self.temp_dir)); distdir.join(format!("{}-{}.tar.gz", self.pkgname, self.target)) From 79f60fbd0410d1cfcbc4ddc8cba7bb11e1dd65ba Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 26 Nov 2020 22:54:35 +0100 Subject: [PATCH 547/719] bootstrap: convert rust-std to use Tarball --- src/bootstrap/dist.rs | 38 ++++++++------------------------------ src/bootstrap/tarball.rs | 10 ++++++++++ 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 0e00649fc032..98f2b28918a1 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -559,7 +559,7 @@ pub struct Std { } impl Step for Std { - type Output = PathBuf; + type Output = Option; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -577,46 +577,24 @@ impl Step for Std { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; - let name = pkgname(builder, "rust-std"); - let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)); if skip_host_target_lib(builder, compiler) { - return archive; + return None; } builder.ensure(compile::Std { compiler, target }); - let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple)); - let _ = fs::remove_dir_all(&image); + let mut tarball = Tarball::new(builder, "rust-std", &target.triple); + tarball.include_target_in_component_name(true); let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); let stamp = compile::libstd_stamp(builder, compiler_to_use, target); - copy_target_libs(builder, target, &image, &stamp); + copy_target_libs(builder, target, &tarball.image_dir(), &stamp); - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=std-is-standing-at-the-ready.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg(format!("--component-name=rust-std-{}", target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo"); - - builder - .info(&format!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target)); - let _time = timeit(builder); - builder.run(&mut cmd); - builder.remove_dir(&image); - archive + Some(tarball.generate()) } } @@ -1699,7 +1677,7 @@ impl Step for Extended { tarballs.extend(rustfmt_installer.clone()); tarballs.extend(llvm_tools_installer); tarballs.push(analysis_installer); - tarballs.push(std_installer); + tarballs.push(std_installer.expect("missing std")); if let Some(docs_installer) = docs_installer { tarballs.push(docs_installer); } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index f99b6f30192d..bde437723bba 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -35,6 +35,7 @@ pub(crate) struct Tarball<'a> { overlay_dir: PathBuf, work_dir: PathBuf, + include_target_in_component_name: bool, is_preview: bool, } @@ -63,6 +64,7 @@ impl<'a> Tarball<'a> { overlay_dir, work_dir, + include_target_in_component_name: false, is_preview: false, } } @@ -75,6 +77,10 @@ impl<'a> Tarball<'a> { self.product_name = name.into(); } + pub(crate) fn include_target_in_component_name(&mut self, include: bool) { + self.include_target_in_component_name = include; + } + pub(crate) fn is_preview(&mut self, is: bool) { self.is_preview = is; } @@ -123,6 +129,10 @@ impl<'a> Tarball<'a> { if self.is_preview { component_name.push_str("-preview"); } + if self.include_target_in_component_name { + component_name.push('-'); + component_name.push_str(&self.target); + } let distdir = crate::dist::distdir(self.builder); cmd.arg("generate") From c0cadc9eb72e6147647bd1b7995851e371167f24 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 27 Nov 2020 12:46:02 +0100 Subject: [PATCH 548/719] bootstrap: convert rustc-dev to use Tarball --- src/bootstrap/dist.rs | 56 +++++++++++++------------------------------ 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 98f2b28918a1..1e0f3b969584 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -605,7 +605,7 @@ pub struct RustcDev { } impl Step for RustcDev { - type Output = PathBuf; + type Output = Option; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -624,60 +624,36 @@ impl Step for RustcDev { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; - - let name = pkgname(builder, "rustc-dev"); - let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)); if skip_host_target_lib(builder, compiler) { - return archive; + return None; } builder.ensure(compile::Rustc { compiler, target }); - let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple)); - let _ = fs::remove_dir_all(&image); + let tarball = Tarball::new(builder, "rustc-dev", &target.triple); let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); let stamp = compile::librustc_stamp(builder, compiler_to_use, target); - copy_target_libs(builder, target, &image, &stamp); + copy_target_libs(builder, target, tarball.image_dir(), &stamp); - // Copy compiler sources. - let dst_src = image.join("lib/rustlib/rustc-src/rust"); - t!(fs::create_dir_all(&dst_src)); - - let src_files = ["Cargo.lock"]; + let src_files = &["Cargo.lock"]; // This is the reduced set of paths which will become the rustc-dev component // (essentially the compiler crates and all of their path dependencies). - copy_src_dirs(builder, &builder.src, &["compiler"], &[], &dst_src); - for file in src_files.iter() { - builder.copy(&builder.src.join(file), &dst_src.join(file)); + copy_src_dirs( + builder, + &builder.src, + &["compiler"], + &[], + &tarball.image_dir().join("lib/rustlib/rustc-src/rust"), + ); + for file in src_files { + tarball.add_file(builder.src.join(file), "lib/rustlib/rustc-src/rust", 0o644); } - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=Rust-is-ready-to-develop.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg(format!("--component-name=rustc-dev-{}", target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo"); - - builder.info(&format!( - "Dist rustc-dev stage{} ({} -> {})", - compiler.stage, &compiler.host, target - )); - let _time = timeit(builder); - builder.run(&mut cmd); - builder.remove_dir(&image); - archive + Some(tarball.generate()) } } From c4aaff65f0cac8fe4375423f36d544440e47878b Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 27 Nov 2020 12:52:44 +0100 Subject: [PATCH 549/719] bootstrap: convert rust-analysis to use Tarball --- src/bootstrap/dist.rs | 48 +++++++++++-------------------------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 1e0f3b969584..e342c0ddf639 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -664,7 +664,7 @@ pub struct Analysis { } impl Step for Analysis { - type Output = PathBuf; + type Output = Option; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -687,52 +687,26 @@ impl Step for Analysis { } /// Creates a tarball of save-analysis metadata, if available. - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); - let name = pkgname(builder, "rust-analysis"); - if compiler.host != builder.config.build { - return distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)); + return None; } builder.ensure(compile::Std { compiler, target }); - - let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple)); - let src = builder .stage_out(compiler, Mode::Std) .join(target.triple) .join(builder.cargo_dir()) - .join("deps"); + .join("deps") + .join("save-analysis"); - let image_src = src.join("save-analysis"); - let dst = image.join("lib/rustlib").join(target.triple).join("analysis"); - t!(fs::create_dir_all(&dst)); - builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst)); - builder.cp_r(&image_src, &dst); - - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=save-analysis-saved.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg(format!("--component-name=rust-analysis-{}", target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo"); - - builder.info("Dist analysis"); - let _time = timeit(builder); - builder.run(&mut cmd); - builder.remove_dir(&image); - distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)) + let mut tarball = Tarball::new(builder, "rust-analysis", &target.triple); + tarball.include_target_in_component_name(true); + tarball.add_dir(src, format!("lib/rustlib/{}/analysis", target.triple)); + Some(tarball.generate()) } } @@ -1652,7 +1626,9 @@ impl Step for Extended { tarballs.extend(miri_installer.clone()); tarballs.extend(rustfmt_installer.clone()); tarballs.extend(llvm_tools_installer); - tarballs.push(analysis_installer); + if let Some(analysis_installer) = analysis_installer { + tarballs.push(analysis_installer); + } tarballs.push(std_installer.expect("missing std")); if let Some(docs_installer) = docs_installer { tarballs.push(docs_installer); From 8a711a00a7f0cd5470255a65a711d47e46d46c14 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 27 Nov 2020 13:11:11 +0100 Subject: [PATCH 550/719] bootstrap: convert cargo to use Tarball --- src/bootstrap/dist.rs | 71 +++++++++------------------------------- src/bootstrap/tarball.rs | 30 ++++++++++++++++- 2 files changed, 44 insertions(+), 57 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e342c0ddf639..7e7c7edceff0 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1015,72 +1015,31 @@ impl Step for Cargo { let compiler = self.compiler; let target = self.target; + let cargo = builder.ensure(tool::Cargo { compiler, target }); let src = builder.src.join("src/tools/cargo"); let etc = src.join("src/etc"); - let release_num = builder.release_num("cargo"); - let name = pkgname(builder, "cargo"); - let version = builder.cargo_info.version(builder, &release_num); - - let tmp = tmpdir(builder); - let image = tmp.join("cargo-image"); - drop(fs::remove_dir_all(&image)); - builder.create_dir(&image); // Prepare the image directory - builder.create_dir(&image.join("share/zsh/site-functions")); - builder.create_dir(&image.join("etc/bash_completion.d")); - let cargo = builder.ensure(tool::Cargo { compiler, target }); - builder.install(&cargo, &image.join("bin"), 0o755); + let mut tarball = Tarball::new(builder, "cargo", &target.triple); + tarball.set_overlay(OverlayKind::Cargo); + + tarball.add_file(&cargo, "bin", 0o755); + tarball.add_file(src.join("README.md"), "share/doc/cargo", 0o644); + tarball.add_file(src.join("LICENSE-MIT"), "share/doc/cargo", 0o644); + tarball.add_file(src.join("LICENSE-APACHE"), "share/doc/cargo", 0o644); + tarball.add_file(src.join("LICENSE-THIRD-PARTY"), "share/doc/cargo", 0o644); + tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644); + tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo"); + tarball.add_dir(etc.join("man"), "share/man/man1"); + for dirent in fs::read_dir(cargo.parent().unwrap()).expect("read_dir") { let dirent = dirent.expect("read dir entry"); if dirent.file_name().to_str().expect("utf8").starts_with("cargo-credential-") { - builder.install(&dirent.path(), &image.join("libexec"), 0o755); + tarball.add_file(&dirent.path(), "libexec", 0o755); } } - for man in t!(etc.join("man").read_dir()) { - let man = t!(man); - builder.install(&man.path(), &image.join("share/man/man1"), 0o644); - } - builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644); - builder.copy(&etc.join("cargo.bashcomp.sh"), &image.join("etc/bash_completion.d/cargo")); - let doc = image.join("share/doc/cargo"); - builder.install(&src.join("README.md"), &doc, 0o644); - builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644); - // Prepare the overlay - let overlay = tmp.join("cargo-overlay"); - drop(fs::remove_dir_all(&overlay)); - builder.create_dir(&overlay); - builder.install(&src.join("README.md"), &overlay, 0o644); - builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644); - builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644); - builder.create(&overlay.join("version"), &version); - - // Generate the installer tarball - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=Rust-is-ready-to-roll.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg("--component-name=cargo") - .arg("--legacy-manifest-dirs=rustlib,cargo"); - - builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target)); - let _time = timeit(builder); - builder.run(&mut cmd); - distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)) + tarball.generate() } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index bde437723bba..5340995ce96f 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -8,6 +8,7 @@ use crate::builder::Builder; pub(crate) enum OverlayKind { Rust, LLVM, + Cargo, } impl OverlayKind { @@ -17,6 +18,22 @@ impl OverlayKind { OverlayKind::LLVM => { &["src/llvm-project/llvm/LICENSE.TXT", "src/llvm-project/llvm/README.txt"] } + OverlayKind::Cargo => &[ + "src/tools/cargo/README.md", + "src/tools/cargo/LICENSE-MIT", + "src/tools/cargo/LICENSE-APACHE", + "src/tools/cargo/LICENSE-THIRD-PARTY", + ], + } + } + + fn version(&self, builder: &Builder<'_>) -> String { + match self { + OverlayKind::Rust => builder.rust_version(), + OverlayKind::LLVM => builder.rust_version(), + OverlayKind::Cargo => { + builder.cargo_info.version(builder, &builder.release_num("cargo")) + } } } } @@ -103,6 +120,17 @@ impl<'a> Tarball<'a> { self.builder.install(src.as_ref(), &destdir, perms); } + pub(crate) fn add_renamed_file( + &self, + src: impl AsRef, + destdir: impl AsRef, + new_name: &str, + ) { + let destdir = self.image_dir.join(destdir.as_ref()); + t!(std::fs::create_dir_all(&destdir)); + self.builder.copy(src.as_ref(), &destdir.join(new_name)); + } + pub(crate) fn add_dir(&self, src: impl AsRef, dest: impl AsRef) { let dest = self.image_dir.join(dest.as_ref()); @@ -112,7 +140,7 @@ impl<'a> Tarball<'a> { pub(crate) fn generate(self) -> PathBuf { t!(std::fs::create_dir_all(&self.overlay_dir)); - self.builder.create(&self.overlay_dir.join("version"), &self.builder.rust_version()); + self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder)); if let Some(sha) = self.builder.rust_sha() { self.builder.create(&self.overlay_dir.join("git-commit-hash"), &sha); } From 521b884913b603ddbdcc1af97b772e40d4ea5f84 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 27 Nov 2020 17:43:03 +0100 Subject: [PATCH 551/719] bootstrap: convert clippy to use Tarball --- src/bootstrap/dist.rs | 58 +++++++--------------------------------- src/bootstrap/tarball.rs | 9 +++++++ 2 files changed, 19 insertions(+), 48 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 7e7c7edceff0..47ad8fae26b1 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1256,16 +1256,6 @@ impl Step for Clippy { let target = self.target; assert!(builder.config.extended); - let src = builder.src.join("src/tools/clippy"); - let release_num = builder.release_num("clippy"); - let name = pkgname(builder, "clippy"); - let version = builder.clippy_info.version(builder, &release_num); - - let tmp = tmpdir(builder); - let image = tmp.join("clippy-image"); - drop(fs::remove_dir_all(&image)); - builder.create_dir(&image); - // Prepare the image directory // We expect clippy to build, because we've exited this step above if tool // state for clippy isn't testing. @@ -1275,45 +1265,17 @@ impl Step for Clippy { let cargoclippy = builder .ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() }) .expect("clippy expected to build - essential tool"); + let src = builder.src.join("src/tools/clippy"); - builder.install(&clippy, &image.join("bin"), 0o755); - builder.install(&cargoclippy, &image.join("bin"), 0o755); - let doc = image.join("share/doc/clippy"); - builder.install(&src.join("README.md"), &doc, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); - - // Prepare the overlay - let overlay = tmp.join("clippy-overlay"); - drop(fs::remove_dir_all(&overlay)); - t!(fs::create_dir_all(&overlay)); - builder.install(&src.join("README.md"), &overlay, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); - builder.create(&overlay.join("version"), &version); - - // Generate the installer tarball - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=clippy-ready-to-serve.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--component-name=clippy-preview"); - - builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target)); - let _time = timeit(builder); - builder.run(&mut cmd); - distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)) + let mut tarball = Tarball::new(builder, "clippy", &target.triple); + tarball.set_overlay(OverlayKind::Clippy); + tarball.is_preview(true); + tarball.add_file(clippy, "bin", 0o755); + tarball.add_file(cargoclippy, "bin", 0o755); + tarball.add_file(src.join("README.md"), "share/doc/clippy", 0o644); + tarball.add_file(src.join("LICENSE-APACHE"), "share/doc/clippy", 0o644); + tarball.add_file(src.join("LICENSE-MIT"), "share/doc/clippy", 0o644); + tarball.generate() } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 5340995ce96f..c0c84222e7dd 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -9,6 +9,7 @@ pub(crate) enum OverlayKind { Rust, LLVM, Cargo, + Clippy, } impl OverlayKind { @@ -24,6 +25,11 @@ impl OverlayKind { "src/tools/cargo/LICENSE-APACHE", "src/tools/cargo/LICENSE-THIRD-PARTY", ], + OverlayKind::Clippy => &[ + "src/tools/clippy/README.md", + "src/tools/clippy/LICENSE-APACHE", + "src/tools/clippy/LICENSE-MIT", + ], } } @@ -34,6 +40,9 @@ impl OverlayKind { OverlayKind::Cargo => { builder.cargo_info.version(builder, &builder.release_num("cargo")) } + OverlayKind::Clippy => { + builder.clippy_info.version(builder, &builder.release_num("clippy")) + } } } } From 32afb3c436eb3909a636fd4fce20a1ba03cc88ec Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 27 Nov 2020 17:56:22 +0100 Subject: [PATCH 552/719] bootstrap: simplify including licenses and readmes to tarballs --- src/bootstrap/dist.rs | 10 ++-------- src/bootstrap/tarball.rs | 10 ++++++++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 47ad8fae26b1..aa4d518d0143 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1024,13 +1024,10 @@ impl Step for Cargo { tarball.set_overlay(OverlayKind::Cargo); tarball.add_file(&cargo, "bin", 0o755); - tarball.add_file(src.join("README.md"), "share/doc/cargo", 0o644); - tarball.add_file(src.join("LICENSE-MIT"), "share/doc/cargo", 0o644); - tarball.add_file(src.join("LICENSE-APACHE"), "share/doc/cargo", 0o644); - tarball.add_file(src.join("LICENSE-THIRD-PARTY"), "share/doc/cargo", 0o644); tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644); tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo"); tarball.add_dir(etc.join("man"), "share/man/man1"); + tarball.add_legal_and_readme_to("share/doc/cargo"); for dirent in fs::read_dir(cargo.parent().unwrap()).expect("read_dir") { let dirent = dirent.expect("read dir entry"); @@ -1265,16 +1262,13 @@ impl Step for Clippy { let cargoclippy = builder .ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() }) .expect("clippy expected to build - essential tool"); - let src = builder.src.join("src/tools/clippy"); let mut tarball = Tarball::new(builder, "clippy", &target.triple); tarball.set_overlay(OverlayKind::Clippy); tarball.is_preview(true); tarball.add_file(clippy, "bin", 0o755); tarball.add_file(cargoclippy, "bin", 0o755); - tarball.add_file(src.join("README.md"), "share/doc/clippy", 0o644); - tarball.add_file(src.join("LICENSE-APACHE"), "share/doc/clippy", 0o644); - tarball.add_file(src.join("LICENSE-MIT"), "share/doc/clippy", 0o644); + tarball.add_legal_and_readme_to("share/doc/clippy"); tarball.generate() } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index c0c84222e7dd..2c8f69e94b3f 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -13,7 +13,7 @@ pub(crate) enum OverlayKind { } impl OverlayKind { - fn included_files(&self) -> &[&str] { + fn legal_and_readme(&self) -> &[&str] { match self { OverlayKind::Rust => &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"], OverlayKind::LLVM => { @@ -140,6 +140,12 @@ impl<'a> Tarball<'a> { self.builder.copy(src.as_ref(), &destdir.join(new_name)); } + pub(crate) fn add_legal_and_readme_to(&self, destdir: impl AsRef) { + for file in self.overlay.legal_and_readme() { + self.add_file(self.builder.src.join(file), destdir.as_ref(), 0o644); + } + } + pub(crate) fn add_dir(&self, src: impl AsRef, dest: impl AsRef) { let dest = self.image_dir.join(dest.as_ref()); @@ -153,7 +159,7 @@ impl<'a> Tarball<'a> { if let Some(sha) = self.builder.rust_sha() { self.builder.create(&self.overlay_dir.join("git-commit-hash"), &sha); } - for file in self.overlay.included_files() { + for file in self.overlay.legal_and_readme() { self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644); } From 2073ea5c07ea5a83d17fb7d08f67cc55e1010aaf Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 27 Nov 2020 18:03:41 +0100 Subject: [PATCH 553/719] bootstrap: convert miri to use Tarball --- src/bootstrap/dist.rs | 58 +++++----------------------------------- src/bootstrap/tarball.rs | 7 +++++ 2 files changed, 14 insertions(+), 51 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index aa4d518d0143..a884e7ee2cc4 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1303,19 +1303,6 @@ impl Step for Miri { let target = self.target; assert!(builder.config.extended); - let src = builder.src.join("src/tools/miri"); - let release_num = builder.release_num("miri"); - let name = pkgname(builder, "miri"); - let version = builder.miri_info.version(builder, &release_num); - - let tmp = tmpdir(builder); - let image = tmp.join("miri-image"); - drop(fs::remove_dir_all(&image)); - builder.create_dir(&image); - - // Prepare the image directory - // We expect miri to build, because we've exited this step above if tool - // state for miri isn't testing. let miri = builder .ensure(tool::Miri { compiler, target, extra_features: Vec::new() }) .or_else(|| { @@ -1329,44 +1316,13 @@ impl Step for Miri { None })?; - builder.install(&miri, &image.join("bin"), 0o755); - builder.install(&cargomiri, &image.join("bin"), 0o755); - let doc = image.join("share/doc/miri"); - builder.install(&src.join("README.md"), &doc, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); - - // Prepare the overlay - let overlay = tmp.join("miri-overlay"); - drop(fs::remove_dir_all(&overlay)); - t!(fs::create_dir_all(&overlay)); - builder.install(&src.join("README.md"), &overlay, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); - builder.create(&overlay.join("version"), &version); - - // Generate the installer tarball - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=miri-ready-to-serve.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--component-name=miri-preview"); - - builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target)); - let _time = timeit(builder); - builder.run(&mut cmd); - Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) + let mut tarball = Tarball::new(builder, "miri", &target.triple); + tarball.set_overlay(OverlayKind::Miri); + tarball.is_preview(true); + tarball.add_file(miri, "bin", 0o755); + tarball.add_file(cargomiri, "bin", 0o755); + tarball.add_legal_and_readme_to("share/doc/miri"); + Some(tarball.generate()) } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 2c8f69e94b3f..0e705a93902e 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -10,6 +10,7 @@ pub(crate) enum OverlayKind { LLVM, Cargo, Clippy, + Miri, } impl OverlayKind { @@ -30,6 +31,11 @@ impl OverlayKind { "src/tools/clippy/LICENSE-APACHE", "src/tools/clippy/LICENSE-MIT", ], + OverlayKind::Miri => &[ + "src/tools/miri/README.md", + "src/tools/miri/LICENSE-APACHE", + "src/tools/miri/LICENSE-MIT", + ], } } @@ -43,6 +49,7 @@ impl OverlayKind { OverlayKind::Clippy => { builder.clippy_info.version(builder, &builder.release_num("clippy")) } + OverlayKind::Miri => builder.miri_info.version(builder, &builder.release_num("miri")), } } } From 2b54f0de3794e5fc38f0d4eb1364cb67a041aa4f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 27 Nov 2020 18:07:58 +0100 Subject: [PATCH 554/719] bootstrap: convert rustfmt to use Tarball --- src/bootstrap/dist.rs | 56 +++++----------------------------------- src/bootstrap/tarball.rs | 9 +++++++ 2 files changed, 16 insertions(+), 49 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index a884e7ee2cc4..35e0aeba1465 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1355,17 +1355,6 @@ impl Step for Rustfmt { let compiler = self.compiler; let target = self.target; - let src = builder.src.join("src/tools/rustfmt"); - let release_num = builder.release_num("rustfmt"); - let name = pkgname(builder, "rustfmt"); - let version = builder.rustfmt_info.version(builder, &release_num); - - let tmp = tmpdir(builder); - let image = tmp.join("rustfmt-image"); - drop(fs::remove_dir_all(&image)); - builder.create_dir(&image); - - // Prepare the image directory let rustfmt = builder .ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() }) .or_else(|| { @@ -1379,44 +1368,13 @@ impl Step for Rustfmt { None })?; - builder.install(&rustfmt, &image.join("bin"), 0o755); - builder.install(&cargofmt, &image.join("bin"), 0o755); - let doc = image.join("share/doc/rustfmt"); - builder.install(&src.join("README.md"), &doc, 0o644); - builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - - // Prepare the overlay - let overlay = tmp.join("rustfmt-overlay"); - drop(fs::remove_dir_all(&overlay)); - builder.create_dir(&overlay); - builder.install(&src.join("README.md"), &overlay, 0o644); - builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644); - builder.create(&overlay.join("version"), &version); - - // Generate the installer tarball - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=rustfmt-ready-to-fmt.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--component-name=rustfmt-preview"); - - builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target)); - let _time = timeit(builder); - builder.run(&mut cmd); - Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) + let mut tarball = Tarball::new(builder, "rustfmt", &target.triple); + tarball.set_overlay(OverlayKind::Rustfmt); + tarball.is_preview(true); + tarball.add_file(rustfmt, "bin", 0o755); + tarball.add_file(cargofmt, "bin", 0o755); + tarball.add_legal_and_readme_to("share/doc/rustfmt"); + Some(tarball.generate()) } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 0e705a93902e..8543f9d4a386 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -11,6 +11,7 @@ pub(crate) enum OverlayKind { Cargo, Clippy, Miri, + Rustfmt, } impl OverlayKind { @@ -36,6 +37,11 @@ impl OverlayKind { "src/tools/miri/LICENSE-APACHE", "src/tools/miri/LICENSE-MIT", ], + OverlayKind::Rustfmt => &[ + "src/tools/rustfmt/README.md", + "src/tools/rustfmt/LICENSE-APACHE", + "src/tools/rustfmt/LICENSE-MIT", + ], } } @@ -50,6 +56,9 @@ impl OverlayKind { builder.clippy_info.version(builder, &builder.release_num("clippy")) } OverlayKind::Miri => builder.miri_info.version(builder, &builder.release_num("miri")), + OverlayKind::Rustfmt => { + builder.rustfmt_info.version(builder, &builder.release_num("rustfmt")) + } } } } From cfb23e845e56718fa33b7b76d30e2edec992d659 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 27 Nov 2020 18:12:17 +0100 Subject: [PATCH 555/719] bootstrap: convert rls to use Tarball --- src/bootstrap/dist.rs | 56 +++++----------------------------------- src/bootstrap/tarball.rs | 7 +++++ 2 files changed, 13 insertions(+), 50 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 35e0aeba1465..c31a938c746f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1070,19 +1070,6 @@ impl Step for Rls { let target = self.target; assert!(builder.config.extended); - let src = builder.src.join("src/tools/rls"); - let release_num = builder.release_num("rls"); - let name = pkgname(builder, "rls"); - let version = builder.rls_info.version(builder, &release_num); - - let tmp = tmpdir(builder); - let image = tmp.join("rls-image"); - drop(fs::remove_dir_all(&image)); - t!(fs::create_dir_all(&image)); - - // Prepare the image directory - // We expect RLS to build, because we've exited this step above if tool - // state for RLS isn't testing. let rls = builder .ensure(tool::Rls { compiler, target, extra_features: Vec::new() }) .or_else(|| { @@ -1090,43 +1077,12 @@ impl Step for Rls { None })?; - builder.install(&rls, &image.join("bin"), 0o755); - let doc = image.join("share/doc/rls"); - builder.install(&src.join("README.md"), &doc, 0o644); - builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - - // Prepare the overlay - let overlay = tmp.join("rls-overlay"); - drop(fs::remove_dir_all(&overlay)); - t!(fs::create_dir_all(&overlay)); - builder.install(&src.join("README.md"), &overlay, 0o644); - builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644); - builder.create(&overlay.join("version"), &version); - - // Generate the installer tarball - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=RLS-ready-to-serve.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--component-name=rls-preview"); - - builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target.triple)); - let _time = timeit(builder); - builder.run(&mut cmd); - Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) + let mut tarball = Tarball::new(builder, "rls", &target.triple); + tarball.set_overlay(OverlayKind::RLS); + tarball.is_preview(true); + tarball.add_file(rls, "bin", 0o755); + tarball.add_legal_and_readme_to("share/doc/rls"); + Some(tarball.generate()) } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 8543f9d4a386..efc85a1445aa 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -12,6 +12,7 @@ pub(crate) enum OverlayKind { Clippy, Miri, Rustfmt, + RLS, } impl OverlayKind { @@ -42,6 +43,11 @@ impl OverlayKind { "src/tools/rustfmt/LICENSE-APACHE", "src/tools/rustfmt/LICENSE-MIT", ], + OverlayKind::RLS => &[ + "src/tools/rls/README.md", + "src/tools/rls/LICENSE-APACHE", + "src/tools/rls/LICENSE-MIT", + ], } } @@ -59,6 +65,7 @@ impl OverlayKind { OverlayKind::Rustfmt => { builder.rustfmt_info.version(builder, &builder.release_num("rustfmt")) } + OverlayKind::RLS => builder.rls_info.version(builder, &builder.release_num("rls")), } } } From 2e0a16cf0d67f61d85ff7631846e9c3c6e20c85a Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 27 Nov 2020 18:20:23 +0100 Subject: [PATCH 556/719] bootstrap: convert rust-analyzer to use Tarball --- src/bootstrap/dist.rs | 56 +++++----------------------------------- src/bootstrap/tarball.rs | 9 +++++++ 2 files changed, 15 insertions(+), 50 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c31a938c746f..b1a61500a70d 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1122,60 +1122,16 @@ impl Step for RustAnalyzer { return None; } - let src = builder.src.join("src/tools/rust-analyzer"); - let release_num = builder.release_num("rust-analyzer/crates/rust-analyzer"); - let name = pkgname(builder, "rust-analyzer"); - let version = builder.rust_analyzer_info.version(builder, &release_num); - - let tmp = tmpdir(builder); - let image = tmp.join("rust-analyzer-image"); - drop(fs::remove_dir_all(&image)); - builder.create_dir(&image); - - // Prepare the image directory - // We expect rust-analyer to always build, as it doesn't depend on rustc internals - // and doesn't have associated toolstate. let rust_analyzer = builder .ensure(tool::RustAnalyzer { compiler, target, extra_features: Vec::new() }) .expect("rust-analyzer always builds"); - builder.install(&rust_analyzer, &image.join("bin"), 0o755); - let doc = image.join("share/doc/rust-analyzer"); - builder.install(&src.join("README.md"), &doc, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); - - // Prepare the overlay - let overlay = tmp.join("rust-analyzer-overlay"); - drop(fs::remove_dir_all(&overlay)); - t!(fs::create_dir_all(&overlay)); - builder.install(&src.join("README.md"), &overlay, 0o644); - builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); - builder.create(&overlay.join("version"), &version); - - // Generate the installer tarball - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=rust-analyzer-ready-to-serve.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--component-name=rust-analyzer-preview"); - - builder.info(&format!("Dist rust-analyzer stage{} ({})", compiler.stage, target)); - let _time = timeit(builder); - builder.run(&mut cmd); - Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) + let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); + tarball.set_overlay(OverlayKind::RustAnalyzer); + tarball.is_preview(true); + tarball.add_file(rust_analyzer, "bin", 0o755); + tarball.add_legal_and_readme_to("share/doc/rust-analyzer"); + Some(tarball.generate()) } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index efc85a1445aa..8a23d36346e3 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -13,6 +13,7 @@ pub(crate) enum OverlayKind { Miri, Rustfmt, RLS, + RustAnalyzer, } impl OverlayKind { @@ -48,6 +49,11 @@ impl OverlayKind { "src/tools/rls/LICENSE-APACHE", "src/tools/rls/LICENSE-MIT", ], + OverlayKind::RustAnalyzer => &[ + "src/tools/rust-analyzer/README.md", + "src/tools/rust-analyzer/LICENSE-APACHE", + "src/tools/rust-analyzer/LICENSE-MIT", + ], } } @@ -66,6 +72,9 @@ impl OverlayKind { builder.rustfmt_info.version(builder, &builder.release_num("rustfmt")) } OverlayKind::RLS => builder.rls_info.version(builder, &builder.release_num("rls")), + OverlayKind::RustAnalyzer => builder + .rust_analyzer_info + .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")), } } } From 1906c42962b1f2bef084474e09b211e48ed2bda7 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 30 Nov 2020 13:25:34 +0100 Subject: [PATCH 557/719] bootstrap: convert rust-src to use Tarball --- src/bootstrap/dist.rs | 30 +++--------------------------- src/bootstrap/tarball.rs | 31 +++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index b1a61500a70d..c89b378f8206 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -814,9 +814,7 @@ impl Step for Src { /// Creates the `rust-src` installer component fn run(self, builder: &Builder<'_>) -> PathBuf { - let name = pkgname(builder, "rust-src"); - let image = tmpdir(builder).join(format!("{}-image", name)); - let _ = fs::remove_dir_all(&image); + let tarball = Tarball::new_targetless(builder, "rust-src"); // A lot of tools expect the rust-src component to be entirely in this directory, so if you // change that (e.g. by adding another directory `lib/rustlib/src/foo` or @@ -825,8 +823,7 @@ impl Step for Src { // // NOTE: if you update the paths here, you also should update the "virtual" path // translation code in `imported_source_files` in `src/librustc_metadata/rmeta/decoder.rs` - let dst_src = image.join("lib/rustlib/src/rust"); - t!(fs::create_dir_all(&dst_src)); + let dst_src = tarball.image_dir().join("lib/rustlib/src/rust"); let src_files = ["Cargo.lock"]; // This is the reduced set of paths which will become the rust-src component @@ -846,28 +843,7 @@ impl Step for Src { builder.copy(&builder.src.join(file), &dst_src.join(file)); } - // Create source tarball in rust-installer format - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=Awesome-Source.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg(format!("--package-name={}", name)) - .arg("--component-name=rust-src") - .arg("--legacy-manifest-dirs=rustlib,cargo"); - - builder.info("Dist src"); - let _time = timeit(builder); - builder.run(&mut cmd); - - builder.remove_dir(&image); - distdir(builder).join(&format!("{}.tar.gz", name)) + tarball.generate() } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 8a23d36346e3..27769cab5af0 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -84,7 +84,7 @@ pub(crate) struct Tarball<'a> { pkgname: String, component: String, - target: String, + target: Option, product_name: String, overlay: OverlayKind, @@ -99,6 +99,14 @@ pub(crate) struct Tarball<'a> { impl<'a> Tarball<'a> { pub(crate) fn new(builder: &'a Builder<'a>, component: &str, target: &str) -> Self { + Self::new_inner(builder, component, Some(target.into())) + } + + pub(crate) fn new_targetless(builder: &'a Builder<'a>, component: &str) -> Self { + Self::new_inner(builder, component, None) + } + + fn new_inner(builder: &'a Builder<'a>, component: &str, target: Option) -> Self { let pkgname = crate::dist::pkgname(builder, component); let temp_dir = builder.out.join("tmp").join("tarball").join(component); @@ -113,7 +121,7 @@ impl<'a> Tarball<'a> { pkgname, component: component.into(), - target: target.into(), + target, product_name: "Rust".into(), overlay: OverlayKind::Rust, @@ -197,7 +205,14 @@ impl<'a> Tarball<'a> { let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller); - self.builder.info(&format!("Dist {} ({})", self.component, self.target)); + let package_name = if let Some(target) = &self.target { + self.builder.info(&format!("Dist {} ({})", self.component, target)); + format!("{}-{}", self.pkgname, target) + } else { + self.builder.info(&format!("Dist {}", self.component)); + self.pkgname.clone() + }; + let _time = crate::util::timeit(self.builder); let mut component_name = self.component.clone(); @@ -206,7 +221,11 @@ impl<'a> Tarball<'a> { } if self.include_target_in_component_name { component_name.push('-'); - component_name.push_str(&self.target); + component_name.push_str( + &self + .target + .expect("include_target_in_component_name used in a targetless tarball"), + ); } let distdir = crate::dist::distdir(self.builder); @@ -222,12 +241,12 @@ impl<'a> Tarball<'a> { .arg(&distdir) .arg("--non-installed-overlay") .arg(self.overlay_dir) - .arg(format!("--package-name={}-{}", self.pkgname, self.target)) + .arg(format!("--package-name={}", package_name)) .arg("--legacy-manifest-dirs=rustlib,cargo") .arg(format!("--component-name={}", component_name)); self.builder.run(&mut cmd); t!(std::fs::remove_dir_all(&self.temp_dir)); - distdir.join(format!("{}-{}.tar.gz", self.pkgname, self.target)) + distdir.join(format!("{}.tar.gz", package_name)) } } From 48924ab7088802123a64af77e5201ddfc1f1a733 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 2 Dec 2020 13:29:45 +0100 Subject: [PATCH 558/719] bootstrap: convert rust to use Tarball --- src/bootstrap/dist.rs | 43 +++----------------- src/bootstrap/tarball.rs | 85 ++++++++++++++++++++++++++++------------ 2 files changed, 65 insertions(+), 63 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c89b378f8206..a68f13988174 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1314,21 +1314,7 @@ impl Step for Extended { let std_installer = builder.ensure(Std { compiler: builder.compiler(stage, target), target }); - let tmp = tmpdir(builder); - let overlay = tmp.join("extended-overlay"); let etc = builder.src.join("src/etc/installer"); - let work = tmp.join("work"); - - let _ = fs::remove_dir_all(&overlay); - builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644); - builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644); - builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644); - let version = builder.rust_version(); - builder.create(&overlay.join("version"), &version); - if let Some(sha) = builder.rust_sha() { - builder.create(&overlay.join("git-commit-hash"), &sha); - } - builder.install(&etc.join("README.md"), &overlay, 0o644); // When rust-std package split from rustc, we needed to ensure that during // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering @@ -1353,31 +1339,12 @@ impl Step for Extended { if target.contains("pc-windows-gnu") { tarballs.push(mingw_installer.unwrap()); } - let mut input_tarballs = tarballs[0].as_os_str().to_owned(); - for tarball in &tarballs[1..] { - input_tarballs.push(","); - input_tarballs.push(tarball); - } - builder.info("building combined installer"); - let mut cmd = rust_installer(builder); - cmd.arg("combine") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=Rust-is-ready-to-roll.") - .arg("--work-dir") - .arg(&work) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--input-tarballs") - .arg(input_tarballs) - .arg("--non-installed-overlay") - .arg(&overlay); - let time = timeit(&builder); - builder.run(&mut cmd); - drop(time); + let mut tarball = Tarball::new(builder, "rust", &target.triple); + let work = tarball.persist_work_dir(); + tarball.combine(&tarballs); + + let tmp = tmpdir(builder).join("combined-tarball"); let mut license = String::new(); license += &builder.read(&builder.src.join("COPYRIGHT")); diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 27769cab5af0..b4146450596d 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -1,4 +1,7 @@ -use std::path::{Path, PathBuf}; +use std::{ + path::{Path, PathBuf}, + process::Command, +}; use build_helper::t; @@ -95,6 +98,7 @@ pub(crate) struct Tarball<'a> { include_target_in_component_name: bool, is_preview: bool, + delete_temp_dir: bool, } impl<'a> Tarball<'a> { @@ -132,6 +136,7 @@ impl<'a> Tarball<'a> { include_target_in_component_name: false, is_preview: false, + delete_temp_dir: true, } } @@ -193,7 +198,53 @@ impl<'a> Tarball<'a> { self.builder.cp_r(src.as_ref(), &dest); } + pub(crate) fn persist_work_dir(&mut self) -> PathBuf { + self.delete_temp_dir = false; + self.work_dir.clone() + } + pub(crate) fn generate(self) -> PathBuf { + let mut component_name = self.component.clone(); + if self.is_preview { + component_name.push_str("-preview"); + } + if self.include_target_in_component_name { + component_name.push('-'); + component_name.push_str( + &self + .target + .as_ref() + .expect("include_target_in_component_name used in a targetless tarball"), + ); + } + + self.run(|this, cmd| { + cmd.arg("generate") + .arg("--image-dir") + .arg(&this.image_dir) + .arg("--non-installed-overlay") + .arg(&this.overlay_dir) + .arg(format!("--component-name={}", &component_name)); + }) + } + + pub(crate) fn combine(self, tarballs: &[PathBuf]) { + let mut input_tarballs = tarballs[0].as_os_str().to_os_string(); + for tarball in &tarballs[1..] { + input_tarballs.push(","); + input_tarballs.push(tarball); + } + + self.run(|this, cmd| { + cmd.arg("combine") + .arg("--input-tarballs") + .arg(input_tarballs) + .arg("--non-installed-overlay") + .arg(&this.overlay_dir); + }); + } + + fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> PathBuf { t!(std::fs::create_dir_all(&self.overlay_dir)); self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder)); if let Some(sha) = self.builder.rust_sha() { @@ -215,37 +266,21 @@ impl<'a> Tarball<'a> { let _time = crate::util::timeit(self.builder); - let mut component_name = self.component.clone(); - if self.is_preview { - component_name.push_str("-preview"); - } - if self.include_target_in_component_name { - component_name.push('-'); - component_name.push_str( - &self - .target - .expect("include_target_in_component_name used in a targetless tarball"), - ); - } - let distdir = crate::dist::distdir(self.builder); - cmd.arg("generate") + build_cli(&self, &mut cmd); + cmd.arg("--rel-manifest-dir=rustlib") + .arg("--legacy-manifest-dirs=rustlib,cargo") .arg(format!("--product-name={}", self.product_name)) - .arg("--rel-manifest-dir=rustlib") .arg(format!("--success-message={} installed.", self.component)) - .arg("--image-dir") - .arg(self.image_dir) + .arg(format!("--package-name={}", package_name)) .arg("--work-dir") .arg(self.work_dir) .arg("--output-dir") - .arg(&distdir) - .arg("--non-installed-overlay") - .arg(self.overlay_dir) - .arg(format!("--package-name={}", package_name)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg(format!("--component-name={}", component_name)); + .arg(&distdir); self.builder.run(&mut cmd); - t!(std::fs::remove_dir_all(&self.temp_dir)); + if self.delete_temp_dir { + t!(std::fs::remove_dir_all(&self.temp_dir)); + } distdir.join(format!("{}.tar.gz", package_name)) } From f18335edb2917a310b69a522e6f3fde30af3d419 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 7 Dec 2020 11:49:22 +0100 Subject: [PATCH 559/719] bootstrap: convert rustc-src to use Tarball --- src/bootstrap/dist.rs | 34 ++----------------- src/bootstrap/tarball.rs | 73 +++++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 62 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index a68f13988174..258483bf1345 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -37,10 +37,6 @@ pub fn tmpdir(builder: &Builder<'_>) -> PathBuf { builder.out.join("tmp/dist") } -fn rust_installer(builder: &Builder<'_>) -> Command { - builder.tool_cmd(Tool::RustInstaller) -} - fn missing_tool(tool_name: &str, skip: bool) { if skip { println!("Unable to build {}, skipping dist", tool_name) @@ -867,11 +863,8 @@ impl Step for PlainSourceTarball { /// Creates the plain source tarball fn run(self, builder: &Builder<'_>) -> PathBuf { - // Make sure that the root folder of tarball has the correct name - let plain_name = format!("{}-src", pkgname(builder, "rustc")); - let plain_dst_src = tmpdir(builder).join(&plain_name); - let _ = fs::remove_dir_all(&plain_dst_src); - t!(fs::create_dir_all(&plain_dst_src)); + let tarball = Tarball::new(builder, "rustc", "src"); + let plain_dst_src = tarball.image_dir(); // This is the set of root paths which will become part of the source package let src_files = [ @@ -914,28 +907,7 @@ impl Step for PlainSourceTarball { builder.run(&mut cmd); } - // Create plain source tarball - let plain_name = format!("rustc-{}-src", builder.rust_package_vers()); - let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name)); - tarball.set_extension(""); // strip .gz - tarball.set_extension(""); // strip .tar - if let Some(dir) = tarball.parent() { - builder.create_dir(&dir); - } - builder.info("running installer"); - let mut cmd = rust_installer(builder); - cmd.arg("tarball") - .arg("--input") - .arg(&plain_name) - .arg("--output") - .arg(&tarball) - .arg("--work-dir=.") - .current_dir(tmpdir(builder)); - - builder.info("Create plain source tarball"); - let _time = timeit(builder); - builder.run(&mut cmd); - distdir(builder).join(&format!("{}.tar.gz", plain_name)) + tarball.bare() } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index b4146450596d..5d73a655427b 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -94,7 +94,6 @@ pub(crate) struct Tarball<'a> { temp_dir: PathBuf, image_dir: PathBuf, overlay_dir: PathBuf, - work_dir: PathBuf, include_target_in_component_name: bool, is_preview: bool, @@ -113,12 +112,14 @@ impl<'a> Tarball<'a> { fn new_inner(builder: &'a Builder<'a>, component: &str, target: Option) -> Self { let pkgname = crate::dist::pkgname(builder, component); - let temp_dir = builder.out.join("tmp").join("tarball").join(component); + let mut temp_dir = builder.out.join("tmp").join("tarball"); + if let Some(target) = &target { + temp_dir = temp_dir.join(target); + } let _ = std::fs::remove_dir_all(&temp_dir); let image_dir = temp_dir.join("image"); let overlay_dir = temp_dir.join("overlay"); - let work_dir = temp_dir.join("work"); Self { builder, @@ -132,7 +133,6 @@ impl<'a> Tarball<'a> { temp_dir, image_dir, overlay_dir, - work_dir, include_target_in_component_name: false, is_preview: false, @@ -200,7 +200,7 @@ impl<'a> Tarball<'a> { pub(crate) fn persist_work_dir(&mut self) -> PathBuf { self.delete_temp_dir = false; - self.work_dir.clone() + self.temp_dir.clone() } pub(crate) fn generate(self) -> PathBuf { @@ -222,9 +222,8 @@ impl<'a> Tarball<'a> { cmd.arg("generate") .arg("--image-dir") .arg(&this.image_dir) - .arg("--non-installed-overlay") - .arg(&this.overlay_dir) .arg(format!("--component-name={}", &component_name)); + this.non_bare_args(cmd); }) } @@ -236,14 +235,41 @@ impl<'a> Tarball<'a> { } self.run(|this, cmd| { - cmd.arg("combine") - .arg("--input-tarballs") - .arg(input_tarballs) - .arg("--non-installed-overlay") - .arg(&this.overlay_dir); + cmd.arg("combine").arg("--input-tarballs").arg(input_tarballs); + this.non_bare_args(cmd); }); } + pub(crate) fn bare(self) -> PathBuf { + self.run(|this, cmd| { + cmd.arg("tarball") + .arg("--input") + .arg(&this.image_dir) + .arg("--output") + .arg(crate::dist::distdir(this.builder).join(this.package_name())); + }) + } + + fn package_name(&self) -> String { + if let Some(target) = &self.target { + format!("{}-{}", self.pkgname, target) + } else { + self.pkgname.clone() + } + } + + fn non_bare_args(&self, cmd: &mut Command) { + cmd.arg("--rel-manifest-dir=rustlib") + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg(format!("--product-name={}", self.product_name)) + .arg(format!("--success-message={} installed.", self.component)) + .arg(format!("--package-name={}", self.package_name())) + .arg("--non-installed-overlay") + .arg(&self.overlay_dir) + .arg("--output-dir") + .arg(crate::dist::distdir(self.builder)); + } + fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> PathBuf { t!(std::fs::create_dir_all(&self.overlay_dir)); self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder)); @@ -256,32 +282,17 @@ impl<'a> Tarball<'a> { let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller); - let package_name = if let Some(target) = &self.target { - self.builder.info(&format!("Dist {} ({})", self.component, target)); - format!("{}-{}", self.pkgname, target) - } else { - self.builder.info(&format!("Dist {}", self.component)); - self.pkgname.clone() - }; - + let package_name = self.package_name(); + self.builder.info(&format!("Dist {}", package_name)); let _time = crate::util::timeit(self.builder); - let distdir = crate::dist::distdir(self.builder); build_cli(&self, &mut cmd); - cmd.arg("--rel-manifest-dir=rustlib") - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg(format!("--product-name={}", self.product_name)) - .arg(format!("--success-message={} installed.", self.component)) - .arg(format!("--package-name={}", package_name)) - .arg("--work-dir") - .arg(self.work_dir) - .arg("--output-dir") - .arg(&distdir); + cmd.arg("--work-dir").arg(&self.temp_dir); self.builder.run(&mut cmd); if self.delete_temp_dir { t!(std::fs::remove_dir_all(&self.temp_dir)); } - distdir.join(format!("{}.tar.gz", package_name)) + crate::dist::distdir(self.builder).join(format!("{}.tar.gz", package_name)) } } From ae12a0c200da9a97d80d074e20bf4180fe4671b5 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 7 Dec 2020 17:23:26 +0100 Subject: [PATCH 560/719] bootstrap: avoid producing the rust tarball during dry runs --- src/bootstrap/dist.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 258483bf1345..dddb9527ea1d 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1288,6 +1288,11 @@ impl Step for Extended { let etc = builder.src.join("src/etc/installer"); + // Avoid producing tarballs during a dry run. + if builder.config.dry_run { + return; + } + // When rust-std package split from rustc, we needed to ensure that during // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering // the std files during uninstall. To do this ensure that rustc comes From 2c081769b09a876ecd3e9854f8cffc022ddc6b13 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 21 Dec 2020 18:04:58 +0100 Subject: [PATCH 561/719] bootstrap: use the normal compiler to build std --- src/bootstrap/dist.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index dddb9527ea1d..6d9ee60f9527 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1283,8 +1283,7 @@ impl Step for Extended { let analysis_installer = builder.ensure(Analysis { compiler, target }); let docs_installer = builder.ensure(Docs { host: target }); - let std_installer = - builder.ensure(Std { compiler: builder.compiler(stage, target), target }); + let std_installer = builder.ensure(Std { compiler, target }); let etc = builder.src.join("src/etc/installer"); From 8736731f70be86b169a0dcc6a1900ccc05d2db85 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 23 Dec 2020 19:40:45 +0100 Subject: [PATCH 562/719] bootstrap: convert reproducible-artifacts to use Tarball --- src/bootstrap/dist.rs | 45 ++++--------------------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 6d9ee60f9527..0a79d09b27fe 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2034,47 +2034,10 @@ impl Step for ReproducibleArtifacts { } fn run(self, builder: &Builder<'_>) -> Self::Output { - let name = pkgname(builder, "reproducible-artifacts"); - let tmp = tmpdir(builder); + let path = builder.config.rust_profile_use.as_ref()?; - // Prepare the image. - let image = tmp.join("reproducible-artifacts-image"); - let _ = fs::remove_dir_all(&image); - - if let Some(path) = &builder.config.rust_profile_use { - builder.install(std::path::Path::new(path), &image, 0o644); - } else { - return None; - } - - // Prepare the overlay. - let overlay = tmp.join("reproducible-artifacts-overlay"); - let _ = fs::remove_dir_all(&overlay); - builder.create_dir(&overlay); - builder.create(&overlay.join("version"), &builder.rust_version()); - for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] { - builder.install(&builder.src.join(file), &overlay, 0o644); - } - - // Create the final tarball. - let mut cmd = rust_installer(builder); - cmd.arg("generate") - .arg("--product-name=Rust") - .arg("--rel-manifest-dir=rustlib") - .arg("--success-message=reproducible-artifacts installed.") - .arg("--image-dir") - .arg(&image) - .arg("--work-dir") - .arg(&tmpdir(builder)) - .arg("--output-dir") - .arg(&distdir(builder)) - .arg("--non-installed-overlay") - .arg(&overlay) - .arg(format!("--package-name={}-{}", name, self.target.triple)) - .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--component-name=reproducible-artifacts"); - - builder.run(&mut cmd); - Some(distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple))) + let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple); + tarball.add_file(path, ".", 0o644); + Some(tarball.generate()) } } From f459b0fea5723010bf1654d8073389fd0a0263d1 Mon Sep 17 00:00:00 2001 From: Yenlin Chen <3822365+hencrice@users.noreply.github.com> Date: Wed, 23 Dec 2020 18:55:37 +0000 Subject: [PATCH 563/719] Addressed feedbacks Also updated the mir-opt test output files. --- compiler/rustc_mir/src/util/pretty.rs | 20 +++---------------- .../checked_add.main.ConstProp.diff | 3 --- .../const_prop/indirect.main.ConstProp.diff | 3 --- .../issue_67019.main.ConstProp.diff | 3 --- ...ble_variable_aggregate.main.ConstProp.diff | 3 --- ...es_into_variable.main.ConstProp.32bit.diff | 3 --- ...es_into_variable.main.ConstProp.64bit.diff | 3 --- .../return_place.add.ConstProp.diff | 3 --- ...le_literal_propagation.main.ConstProp.diff | 3 --- ...ves_unused_consts.main.SimplifyLocals.diff | 3 --- 10 files changed, 3 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 9b81629400a6..394eb8334223 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -17,7 +17,6 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; use rustc_target::abi::Size; use std::ops::ControlFlow; @@ -414,22 +413,9 @@ fn use_verbose(ty: &&TyS<'tcx>) -> bool { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, // Unit type ty::Tuple(g_args) if g_args.is_empty() => false, - ty::Tuple(g_args) => { - // could have used `try_fold` here but it seems a bit silly that - // the accumulator is useless - let mut should_be_verbose = false; - for g_arg in g_args.iter() { - if match g_arg.unpack() { - GenericArgKind::Type(ty) => use_verbose(&ty), - GenericArgKind::Const(ty::Const { ty, val: _ }) => use_verbose(ty), - _ => false, - } { - should_be_verbose = true; - break; - } - } - should_be_verbose - } + ty::Tuple(g_args) => g_args.iter().any(|g_arg| { + use_verbose(&g_arg.expect_ty()) + }), ty::Array(ty, _) => use_verbose(ty), ty::FnDef(..) => false, _ => true, diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff index f01676b6da86..3397ef95856a 100644 --- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff @@ -14,9 +14,6 @@ - _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 + _2 = const (2_u32, false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 -+ // ty::Const -+ // + ty: (u32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/checked_add.rs:5:18: 5:23 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff index 8c7b35887c91..9ddb34e58e5a 100644 --- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff @@ -18,9 +18,6 @@ - assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 + _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25 + _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:5:13: 5:29 -+ // ty::Const -+ // + ty: (u8, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/indirect.rs:5:13: 5:29 + // + literal: Const { ty: (u8, bool), val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff index 492938fc206b..da35bf18c711 100644 --- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff @@ -15,9 +15,6 @@ (_3.1: u8) = const 2_u8; // scope 0 at $DIR/issue-67019.rs:11:11: 11:17 - (_2.0: (u8, u8)) = move _3; // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 + (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 -+ // ty::Const -+ // + ty: (u8, u8) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/issue-67019.rs:11:10: 11:19 + // + literal: Const { ty: (u8, u8), val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff index 204c1acecf54..12b02e90345d 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff @@ -20,9 +20,6 @@ StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10 - _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 + _2 = const (42_i32, 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 -+ // ty::Const -+ // + ty: (i32, i32) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14 + // + literal: Const { ty: (i32, i32), val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff index 53ffc01ccaf2..a10bac4f3ea3 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff @@ -27,9 +27,6 @@ - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -+ // ty::Const -+ // + ty: (i32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff index 53ffc01ccaf2..a10bac4f3ea3 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff @@ -27,9 +27,6 @@ - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -+ // ty::Const -+ // + ty: (i32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff index fc8a5437232c..f0e9916e6300 100644 --- a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff +++ b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff @@ -9,9 +9,6 @@ - _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10 - assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 + _1 = const (4_u32, false); // scope 0 at $DIR/return_place.rs:6:5: 6:10 -+ // ty::Const -+ // + ty: (u32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/return_place.rs:6:5: 6:10 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff index 2de1ab19b7c3..da4b135d4c6d 100644 --- a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff @@ -18,9 +18,6 @@ StorageLive(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 - _3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 + _3 = const (1_u32, 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 -+ // ty::Const -+ // + ty: (u32, u32) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14 + // + literal: Const { ty: (u32, u32), val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff index 3064e92f9000..34f8ca870cd2 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff @@ -42,9 +42,6 @@ // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12 // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(Scalar()) } - // ty::Const - // + ty: ((), ()) - // + val: Value(Scalar()) // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 // + literal: Const { ty: ((), ()), val: Value(Scalar()) } From ecba49c1bd6e16235e13a076e03e31fcd8d7ffc8 Mon Sep 17 00:00:00 2001 From: Yenlin Chen <3822365+hencrice@users.noreply.github.com> Date: Wed, 23 Dec 2020 19:10:59 +0000 Subject: [PATCH 564/719] Fixed formatting --- compiler/rustc_mir/src/util/pretty.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 394eb8334223..34ec16d9f291 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -413,9 +413,7 @@ fn use_verbose(ty: &&TyS<'tcx>) -> bool { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, // Unit type ty::Tuple(g_args) if g_args.is_empty() => false, - ty::Tuple(g_args) => g_args.iter().any(|g_arg| { - use_verbose(&g_arg.expect_ty()) - }), + ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty())), ty::Array(ty, _) => use_verbose(ty), ty::FnDef(..) => false, _ => true, From 152d4e74bec46c08e388b47f3c5693929caf377f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 23 Dec 2020 20:27:12 +0100 Subject: [PATCH 565/719] Update HTML DOM attribute "edition" to "data-edition" --- src/librustdoc/html/highlight.rs | 2 +- src/librustdoc/html/static/rustdoc.css | 2 +- src/test/rustdoc/codeblock-title.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 47d2707e40df..077481c89895 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -30,7 +30,7 @@ crate fn render_with_highlighting( "
", class, if let Some(edition_info) = edition_info { - format!(" edition=\"{}\"", edition_info) + format!(" data-edition=\"{}\"", edition_info) } else { String::new() }, diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index afc4308b68f9..0b40480f738d 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1098,7 +1098,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { content: "This example panics"; } .tooltip.edition::after { - content: "This code runs with edition " attr(edition); + content: "This code runs with edition " attr(data-edition); } .tooltip::before { diff --git a/src/test/rustdoc/codeblock-title.rs b/src/test/rustdoc/codeblock-title.rs index 1327fd67d316..140c5b3a6720 100644 --- a/src/test/rustdoc/codeblock-title.rs +++ b/src/test/rustdoc/codeblock-title.rs @@ -3,7 +3,7 @@ // @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]' "ⓘ" // @has foo/fn.bar.html '//*[@class="tooltip ignore"]' "ⓘ" // @has foo/fn.bar.html '//*[@class="tooltip should_panic"]' "ⓘ" -// @has foo/fn.bar.html '//*[@edition="2018"]' "ⓘ" +// @has foo/fn.bar.html '//*[@data-edition="2018"]' "ⓘ" /// foo /// From 481f6dbebfdb85739e821eddc3781612dfd0830a Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Wed, 23 Dec 2020 19:56:17 +0000 Subject: [PATCH 566/719] Update RELEASES.md --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 0cfbb62c85e4..8f04980e3903 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -78,6 +78,7 @@ Compatibility Notes Previously such invalid or unused attributes could be ignored. - Leading whitespace is stripped more uniformly in documentation comments, which may change behavior. You read [this post about the changes][rustdoc-ws-post] for more details. +- [Trait bounds are no longer inferred for associated types.][79904] Internal Only ------------- @@ -112,6 +113,7 @@ related tools. [74989]: https://github.com/rust-lang/rust/pull/74989 [79004]: https://github.com/rust-lang/rust/pull/79004 [78676]: https://github.com/rust-lang/rust/pull/78676 +[79904]: https://github.com/rust-lang/rust/issues/79904 [cargo/8864]: https://github.com/rust-lang/cargo/pull/8864 [cargo/8765]: https://github.com/rust-lang/cargo/pull/8765 [cargo/8758]: https://github.com/rust-lang/cargo/pull/8758 From 0bfc45aa859b94cedeffcbd949f9aaad9f3ac8d8 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 23 Dec 2020 12:18:15 -0800 Subject: [PATCH 567/719] Add libz-sys to rustc-workspace-hack. https://github.com/alexcrichton/curl-rust/pull/351 changed curl-rust to no longer enable the default features of libz-sys. Because rustfmt includes rustc-workspace-hack with the rustc-workspace-hack/all-static feature (sometimes), it ends up building libz-sys without the default features. This causes a duplicate with other packages (like rls) which enable the default features. --- Cargo.lock | 1 + src/tools/rustc-workspace-hack/Cargo.toml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8fbfa8d64282..3603dbe1d0c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3435,6 +3435,7 @@ dependencies = [ "byteorder", "crossbeam-utils 0.7.2", "libc", + "libz-sys", "proc-macro2", "quote", "serde", diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 11b175f9e80e..1cde0e25cedc 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -65,6 +65,8 @@ byteorder = { version = "1", features = ['default', 'std'] } curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true } crossbeam-utils = { version = "0.7.2", features = ["nightly"] } libc = { version = "0.2.79", features = ["align"] } +# Ensure default features of libz-sys, which are disabled in some scenarios. +libz-sys = { version = "1.1.2" } proc-macro2 = { version = "1", features = ["default"] } quote = { version = "1", features = ["default"] } serde = { version = "1.0.82", features = ['derive'] } From 6dc4f7a9d430e1b7d9a2a4032905fd96677e7846 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 23 Dec 2020 15:05:06 -0500 Subject: [PATCH 568/719] Don't unnecessarily override attrs for Module They were never changed from the default, which you can get with `tcx.get_attrs()`. --- src/librustdoc/clean/mod.rs | 7 +------ src/librustdoc/doctree.rs | 4 +--- src/librustdoc/visit_ast.rs | 6 +----- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index de53ce8d95c1..6982e16da875 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -218,11 +218,6 @@ impl Clean for CrateNum { impl Clean for doctree::Module<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { - // maintain a stack of mod ids, for doc comment path resolution - // but we also need to resolve the module's own docs based on whether its docs were written - // inside or outside the module, so check for that - let attrs = self.attrs.clean(cx); - let mut items: Vec = vec![]; items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); items.extend(self.foreigns.iter().map(|x| x.clean(cx))); @@ -251,7 +246,7 @@ impl Clean for doctree::Module<'_> { ModuleItem(Module { is_crate: self.is_crate, items }), cx, ); - Item { attrs, source: span.clean(cx), ..what_rustc_thinks } + Item { source: span.clean(cx), ..what_rustc_thinks } } } diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index ee9a69818579..bc9f1cf8806a 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -9,7 +9,6 @@ use rustc_hir as hir; crate struct Module<'hir> { crate name: Option, - crate attrs: &'hir [ast::Attribute], crate where_outer: Span, crate where_inner: Span, crate imports: Vec>, @@ -23,13 +22,12 @@ crate struct Module<'hir> { } impl Module<'hir> { - crate fn new(name: Option, attrs: &'hir [ast::Attribute]) -> Module<'hir> { + crate fn new(name: Option) -> Module<'hir> { Module { name, id: hir::CRATE_HIR_ID, where_outer: rustc_span::DUMMY_SP, where_inner: rustc_span::DUMMY_SP, - attrs, imports: Vec::new(), mods: Vec::new(), items: Vec::new(), diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f9cb1d586b10..3c0aeaad43e5 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -1,7 +1,6 @@ //! The Rust AST Visitor. Extracts useful information and massages it into a form //! usable for `clean`. -use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -64,7 +63,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> { let mut module = self.visit_mod_contents( krate.item.span, - krate.item.attrs, &Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public }, hir::CRATE_HIR_ID, &krate.item.module, @@ -82,13 +80,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn visit_mod_contents( &mut self, span: Span, - attrs: &'tcx [ast::Attribute], vis: &'tcx hir::Visibility<'_>, id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Option, ) -> Module<'tcx> { - let mut om = Module::new(name, attrs); + let mut om = Module::new(name); om.where_outer = span; om.where_inner = m.inner; om.id = id; @@ -292,7 +289,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemKind::Mod(ref m) => { om.mods.push(self.visit_mod_contents( item.span, - &item.attrs, &item.vis, item.hir_id, m, From df94bfceb1e457f613d01d03f1f3f1c696d1c77f Mon Sep 17 00:00:00 2001 From: pierwill <19642016+pierwill@users.noreply.github.com> Date: Wed, 23 Dec 2020 13:08:15 -0800 Subject: [PATCH 569/719] Fix typo --- compiler/rustc_middle/src/ty/list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 83a2bdf90f9a..e657088a5e46 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -24,7 +24,7 @@ extern "C" { /// This means we can use pointer for both /// equality comparisons and hashing. /// -/// Unlike slices, The types contained in `List` are expected to be `Copy` +/// Unlike slices, the types contained in `List` are expected to be `Copy` /// and iterating over a `List` returns `T` instead of a reference. /// /// Note: `Slice` was already taken by the `Ty`. From 8824efd61c050d8ee138593b6128950ec25c752d Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 23 Nov 2020 14:41:53 +0100 Subject: [PATCH 570/719] BTreeMap: avoid implicit use of node length in flight --- library/alloc/src/collections/btree/node.rs | 178 +++++++++----------- 1 file changed, 81 insertions(+), 97 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index a3ff83561f1b..769383515b7f 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -35,6 +35,7 @@ use core::cmp::Ordering; use core::marker::PhantomData; use core::mem::{self, MaybeUninit}; use core::ptr::{self, NonNull}; +use core::slice::SliceIndex; use crate::alloc::{Allocator, Global, Layout}; use crate::boxed::Box; @@ -507,30 +508,45 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// Borrows exclusive access to an element of the key storage area. /// /// # Safety - /// The node has more than `idx` initialized elements. - unsafe fn key_area_mut_at(&mut self, idx: usize) -> &mut MaybeUninit { - debug_assert!(idx < self.len()); - unsafe { self.as_leaf_mut().keys.get_unchecked_mut(idx) } + /// `index` is in bounds of 0..CAPACITY + unsafe fn key_area_mut_at(&mut self, index: I) -> &mut Output + where + I: SliceIndex<[MaybeUninit], Output = Output>, + { + // SAFETY: the caller will not be able to call further methods on self + // until the key slice reference is dropped, as we have unique access + // for the lifetime of the borrow. + unsafe { self.as_leaf_mut().keys.as_mut_slice().get_unchecked_mut(index) } } - /// Borrows exclusive access to an element of the value storage area. + /// Borrows exclusive access to an element or slice of the node's value storage area. /// /// # Safety - /// The node has more than `idx` initialized elements. - unsafe fn val_area_mut_at(&mut self, idx: usize) -> &mut MaybeUninit { - debug_assert!(idx < self.len()); - unsafe { self.as_leaf_mut().vals.get_unchecked_mut(idx) } + /// `index` is in bounds of 0..CAPACITY + unsafe fn val_area_mut_at(&mut self, index: I) -> &mut Output + where + I: SliceIndex<[MaybeUninit], Output = Output>, + { + // SAFETY: the caller will not be able to call further methods on self + // until the value slice reference is dropped, as we have unique access + // for the lifetime of the borrow. + unsafe { self.as_leaf_mut().vals.as_mut_slice().get_unchecked_mut(index) } } } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { - /// Borrows exclusive access to an element of the storage area for edge contents. + /// Borrows exclusive access to an element or slice of the node's storage area for edge contents. /// /// # Safety - /// The node has at least `idx` initialized elements. - unsafe fn edge_area_mut_at(&mut self, idx: usize) -> &mut MaybeUninit> { - debug_assert!(idx <= self.len()); - unsafe { self.as_internal_mut().edges.get_unchecked_mut(idx) } + /// `index` is in bounds of 0..CAPACITY + 1 + unsafe fn edge_area_mut_at(&mut self, index: I) -> &mut Output + where + I: SliceIndex<[MaybeUninit>], Output = Output>, + { + // SAFETY: the caller will not be able to call further methods on self + // until the edge slice reference is dropped, as we have unique access + // for the lifetime of the borrow. + unsafe { self.as_internal_mut().edges.as_mut_slice().get_unchecked_mut(index) } } } @@ -559,37 +575,6 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { } } -impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - /// Borrows exclusive access to a sized slice of key storage area in the node. - unsafe fn key_area_slice(&mut self) -> &mut [MaybeUninit] { - let len = self.len(); - // SAFETY: the caller will not be able to call further methods on self - // until the key slice reference is dropped, as we have unique access - // for the lifetime of the borrow. - unsafe { self.as_leaf_mut().keys.get_unchecked_mut(..len) } - } - - /// Borrows exclusive access to a sized slice of value storage area in the node. - unsafe fn val_area_slice(&mut self) -> &mut [MaybeUninit] { - let len = self.len(); - // SAFETY: the caller will not be able to call further methods on self - // until the value slice reference is dropped, as we have unique access - // for the lifetime of the borrow. - unsafe { self.as_leaf_mut().vals.get_unchecked_mut(..len) } - } -} - -impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { - /// Borrows exclusive access to a sized slice of storage area for edge contents in the node. - unsafe fn edge_area_slice(&mut self) -> &mut [MaybeUninit>] { - let len = self.len(); - // SAFETY: the caller will not be able to call further methods on self - // until the edge slice reference is dropped, as we have unique access - // for the lifetime of the borrow. - unsafe { self.as_internal_mut().edges.get_unchecked_mut(..len + 1) } - } -} - impl<'a, K, V, Type> NodeRef, K, V, Type> { /// # Safety /// - The node has more than `idx` initialized elements. @@ -650,12 +635,12 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key-value pair to the beginning of the node. fn push_front(&mut self, key: K, val: V) { - assert!(self.len() < CAPACITY); - + let new_len = self.len() + 1; + assert!(new_len <= CAPACITY); unsafe { - *self.len_mut() += 1; - slice_insert(self.key_area_slice(), 0, key); - slice_insert(self.val_area_slice(), 0, val); + slice_insert(self.key_area_mut_at(..new_len), 0, key); + slice_insert(self.val_area_mut_at(..new_len), 0, val); + *self.len_mut() = new_len as u16; } } } @@ -697,14 +682,15 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { /// Adds a key-value pair, and an edge to go to the left of that pair, /// to the beginning of the node. fn push_front(&mut self, key: K, val: V, edge: Root) { + let new_len = self.len() + 1; assert!(edge.height == self.height - 1); - assert!(self.len() < CAPACITY); + assert!(new_len <= CAPACITY); unsafe { - *self.len_mut() += 1; - slice_insert(self.key_area_slice(), 0, key); - slice_insert(self.val_area_slice(), 0, val); - slice_insert(self.edge_area_slice(), 0, edge.node); + slice_insert(self.key_area_mut_at(..new_len), 0, key); + slice_insert(self.val_area_mut_at(..new_len), 0, val); + slice_insert(self.edge_area_mut_at(..new_len + 1), 0, edge.node); + *self.len_mut() = new_len as u16; } self.correct_all_childrens_parent_links(); @@ -749,12 +735,12 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let old_len = self.len(); unsafe { - let key = slice_remove(self.key_area_slice(), 0); - let val = slice_remove(self.val_area_slice(), 0); + let key = slice_remove(self.key_area_mut_at(..old_len), 0); + let val = slice_remove(self.val_area_mut_at(..old_len), 0); let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(mut internal) => { - let node = slice_remove(internal.edge_area_slice(), 0); + let node = slice_remove(internal.edge_area_mut_at(..old_len + 1), 0); let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; // Currently, clearing the parent link is superfluous, because we will // insert the node elsewhere and set its parent link again. @@ -975,11 +961,12 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// The returned pointer points to the inserted value. fn insert_fit(&mut self, key: K, val: V) -> *mut V { debug_assert!(self.node.len() < CAPACITY); + let new_len = self.node.len() + 1; unsafe { - *self.node.len_mut() += 1; - slice_insert(self.node.key_area_slice(), self.idx, key); - slice_insert(self.node.val_area_slice(), self.idx, val); + slice_insert(self.node.key_area_mut_at(..new_len), self.idx, key); + slice_insert(self.node.val_area_mut_at(..new_len), self.idx, val); + *self.node.len_mut() = new_len as u16; self.node.val_area_mut_at(self.idx).assume_init_mut() } @@ -1033,14 +1020,15 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, fn insert_fit(&mut self, key: K, val: V, edge: Root) { debug_assert!(self.node.len() < CAPACITY); debug_assert!(edge.height == self.node.height - 1); + let new_len = self.node.len() + 1; unsafe { - *self.node.len_mut() += 1; - slice_insert(self.node.key_area_slice(), self.idx, key); - slice_insert(self.node.val_area_slice(), self.idx, val); - slice_insert(self.node.edge_area_slice(), self.idx + 1, edge.node); + slice_insert(self.node.key_area_mut_at(..new_len), self.idx, key); + slice_insert(self.node.val_area_mut_at(..new_len), self.idx, val); + slice_insert(self.node.edge_area_mut_at(..new_len + 1), self.idx + 1, edge.node); + *self.node.len_mut() = new_len as u16; - self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len()); + self.node.correct_childrens_parent_links(self.idx + 1..new_len + 1); } } @@ -1177,17 +1165,11 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { - /// Helps implementations of `split` for a particular `NodeType`, - /// by calculating the length of the new node. - fn split_new_node_len(&self) -> usize { - debug_assert!(self.idx < self.node.len()); - self.node.len() - self.idx - 1 - } - /// Helps implementations of `split` for a particular `NodeType`, /// by taking care of leaf data. fn split_leaf_data(&mut self, new_node: &mut LeafNode) -> (K, V) { - let new_len = self.split_new_node_len(); + debug_assert!(self.idx < self.node.len()); + let new_len = self.node.len() - self.idx - 1; new_node.len = new_len as u16; unsafe { let k = ptr::read(self.node.reborrow().key_at(self.idx)); @@ -1234,10 +1216,11 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark pub fn remove( mut self, ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { + let old_len = self.node.len(); unsafe { - let k = slice_remove(self.node.key_area_slice(), self.idx); - let v = slice_remove(self.node.val_area_slice(), self.idx); - *self.node.len_mut() -= 1; + let k = slice_remove(self.node.key_area_mut_at(..old_len), self.idx); + let v = slice_remove(self.node.val_area_mut_at(..old_len), self.idx); + *self.node.len_mut() = (old_len - 1) as u16; ((k, v), self.left_edge()) } } @@ -1254,14 +1237,13 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, pub fn split(mut self) -> SplitResult<'a, K, V, marker::Internal> { unsafe { let mut new_node = Box::new(InternalNode::new()); - let new_len = self.split_new_node_len(); - // Move edges out before reducing length: + let kv = self.split_leaf_data(&mut new_node.data); + let new_len = usize::from(new_node.data.len); ptr::copy_nonoverlapping( self.node.reborrow().edge_area().as_ptr().add(self.idx + 1), new_node.edges.as_mut_ptr(), new_len + 1, ); - let kv = self.split_leaf_data(&mut new_node.data); let height = self.node.height; let mut right = NodeRef::from_new_internal(new_node, height); @@ -1384,23 +1366,25 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { unsafe { *left_node.len_mut() = new_left_len as u16; - let parent_key = slice_remove(parent_node.key_area_slice(), parent_idx); + let parent_key = + slice_remove(parent_node.key_area_mut_at(..old_parent_len), parent_idx); left_node.key_area_mut_at(old_left_len).write(parent_key); ptr::copy_nonoverlapping( right_node.reborrow().key_area().as_ptr(), - left_node.key_area_slice().as_mut_ptr().add(old_left_len + 1), + left_node.key_area_mut_at(old_left_len + 1..).as_mut_ptr(), right_len, ); - let parent_val = slice_remove(parent_node.val_area_slice(), parent_idx); + let parent_val = + slice_remove(parent_node.val_area_mut_at(..old_parent_len), parent_idx); left_node.val_area_mut_at(old_left_len).write(parent_val); ptr::copy_nonoverlapping( right_node.reborrow().val_area().as_ptr(), - left_node.val_area_slice().as_mut_ptr().add(old_left_len + 1), + left_node.val_area_mut_at(old_left_len + 1..).as_mut_ptr(), right_len, ); - slice_remove(&mut parent_node.edge_area_slice(), parent_idx + 1); + slice_remove(&mut parent_node.edge_area_mut_at(..old_parent_len + 1), parent_idx + 1); parent_node.correct_childrens_parent_links(parent_idx + 1..old_parent_len); *parent_node.len_mut() -= 1; @@ -1411,7 +1395,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { let right_node = right_node.cast_to_internal_unchecked(); ptr::copy_nonoverlapping( right_node.reborrow().edge_area().as_ptr(), - left_node.edge_area_slice().as_mut_ptr().add(old_left_len + 1), + left_node.edge_area_mut_at(old_left_len + 1..).as_mut_ptr(), right_len + 1, ); @@ -1489,6 +1473,9 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { assert!(old_left_len >= count); let new_left_len = old_left_len - count; + let new_right_len = old_right_len + count; + *left_node.len_mut() = new_left_len as u16; + *right_node.len_mut() = new_right_len as u16; // Move leaf data. { @@ -1513,16 +1500,13 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { move_kv(left_kv, new_left_len, parent_kv, 0, 1); } - *left_node.len_mut() -= count as u16; - *right_node.len_mut() += count as u16; - match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { // Make room for stolen edges. let left = left.reborrow(); - let right_edges = right.edge_area_slice().as_mut_ptr(); + let right_edges = right.edge_area_mut_at(..).as_mut_ptr(); ptr::copy(right_edges, right_edges.add(count), old_right_len + 1); - right.correct_childrens_parent_links(count..count + old_right_len + 1); + right.correct_childrens_parent_links(count..new_right_len + 1); // Steal edges. move_edges(left, new_left_len + 1, right, 0, count); @@ -1546,7 +1530,10 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { assert!(old_left_len + count <= CAPACITY); assert!(old_right_len >= count); + let new_left_len = old_left_len + count; let new_right_len = old_right_len - count; + *left_node.len_mut() = new_left_len as u16; + *right_node.len_mut() = new_right_len as u16; // Move leaf data. { @@ -1571,16 +1558,13 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { ptr::copy(right_kv.1.add(count), right_kv.1, new_right_len); } - *left_node.len_mut() += count as u16; - *right_node.len_mut() -= count as u16; - match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { // Steal edges. move_edges(right.reborrow(), 0, left, old_left_len + 1, count); // Fill gap where stolen edges used to be. - let right_edges = right.edge_area_slice().as_mut_ptr(); + let right_edges = right.edge_area_mut_at(..).as_mut_ptr(); ptr::copy(right_edges.add(count), right_edges, new_right_len + 1); right.correct_childrens_parent_links(0..=new_right_len); } @@ -1614,8 +1598,8 @@ unsafe fn move_edges<'a, K: 'a, V: 'a>( ) { unsafe { let source_ptr = source.edge_area().as_ptr(); - let dest_ptr = dest.edge_area_slice().as_mut_ptr(); - ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); + let dest_ptr = dest.edge_area_mut_at(dest_offset..).as_mut_ptr(); + ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr, count); dest.correct_childrens_parent_links(dest_offset..dest_offset + count); } } From 6e852cc4ce3b99048d164c58456371c25669c672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 24 Dec 2020 10:16:06 +0100 Subject: [PATCH 571/719] remove redundant clones (clippy::redundant_clone) --- compiler/rustc_infer/src/infer/mod.rs | 2 +- compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 069f708856ea..56d9634213ae 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1317,7 +1317,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { T: TypeFoldable<'tcx>, { if !value.needs_infer() { - return value.clone(); // Avoid duplicated subst-folding. + return value; // Avoid duplicated subst-folding. } let mut r = resolve::OpportunisticVarResolver::new(self); value.fold_with(&mut r) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index d79dd97a69a7..db2fa5730a33 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -328,8 +328,8 @@ struct SplitIntRange { } impl SplitIntRange { - fn new(r: IntRange) -> Self { - SplitIntRange { range: r.clone(), borders: Vec::new() } + fn new(range: IntRange) -> Self { + SplitIntRange { range, borders: Vec::new() } } /// Internal use From d12a358673b17ed74fe1a584b4cab66fe62e18d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 24 Dec 2020 02:55:21 +0100 Subject: [PATCH 572/719] use matches!() macro in more places --- compiler/rustc_ast/src/ast.rs | 45 ++++------------ compiler/rustc_ast/src/attr/mod.rs | 5 +- compiler/rustc_ast/src/token.rs | 53 +++++++------------ compiler/rustc_ast/src/util/classify.rs | 18 +++---- compiler/rustc_ast/src/util/comments.rs | 6 +-- .../src/deriving/clone.rs | 7 ++- .../src/deriving/generic/mod.rs | 12 ++--- compiler/rustc_builtin_macros/src/format.rs | 5 +- .../src/format_foreign.rs | 5 +- compiler/rustc_builtin_macros/src/llvm_asm.rs | 8 +-- .../src/proc_macro_harness.rs | 5 +- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 8 +-- .../trait_impl_difference.rs | 5 +- .../rustc_infer/src/infer/free_regions.rs | 5 +- .../src/infer/lexical_region_resolve/mod.rs | 11 +--- compiler/rustc_middle/src/hir/map/blocks.rs | 20 ++----- compiler/rustc_middle/src/mir/coverage.rs | 10 +--- compiler/rustc_middle/src/ty/error.rs | 7 +-- compiler/rustc_middle/src/ty/sty.rs | 5 +- .../rustc_mir_build/src/build/expr/into.rs | 6 +-- compiler/rustc_parse/src/parser/path.rs | 7 ++- compiler/rustc_passes/src/dead.rs | 38 ++++++------- compiler/rustc_passes/src/liveness.rs | 5 +- .../rustc_resolve/src/late/diagnostics.rs | 19 +++---- .../src/traits/auto_trait.rs | 10 +--- .../src/traits/coherence.rs | 6 +-- .../src/traits/error_reporting/mod.rs | 12 ++--- .../rustc_trait_selection/src/traits/mod.rs | 5 +- compiler/rustc_typeck/src/astconv/generics.rs | 22 ++++---- compiler/rustc_typeck/src/check/check.rs | 12 ++--- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 5 +- compiler/rustc_typeck/src/check/regionck.rs | 5 +- compiler/rustc_typeck/src/collect.rs | 8 +-- compiler/rustc_typeck/src/expr_use_visitor.rs | 8 +-- 34 files changed, 138 insertions(+), 270 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 220bbed7e78b..478e61dd1211 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -167,10 +167,7 @@ pub enum GenericArgs { impl GenericArgs { pub fn is_angle_bracketed(&self) -> bool { - match *self { - AngleBracketed(..) => true, - _ => false, - } + matches!(self, AngleBracketed(..)) } pub fn span(&self) -> Span { @@ -629,10 +626,7 @@ impl Pat { /// Is this a `..` pattern? pub fn is_rest(&self) -> bool { - match self.kind { - PatKind::Rest => true, - _ => false, - } + matches!(self.kind, PatKind::Rest) } } @@ -852,10 +846,7 @@ impl BinOpKind { } } pub fn lazy(&self) -> bool { - match *self { - BinOpKind::And | BinOpKind::Or => true, - _ => false, - } + matches!(self, BinOpKind::And | BinOpKind::Or) } pub fn is_comparison(&self) -> bool { @@ -963,17 +954,11 @@ impl Stmt { } pub fn is_item(&self) -> bool { - match self.kind { - StmtKind::Item(_) => true, - _ => false, - } + matches!(self.kind, StmtKind::Item(_)) } pub fn is_expr(&self) -> bool { - match self.kind { - StmtKind::Expr(_) => true, - _ => false, - } + matches!(self.kind, StmtKind::Expr(_)) } } @@ -1652,26 +1637,17 @@ pub enum LitKind { impl LitKind { /// Returns `true` if this literal is a string. pub fn is_str(&self) -> bool { - match *self { - LitKind::Str(..) => true, - _ => false, - } + matches!(self, LitKind::Str(..)) } /// Returns `true` if this literal is byte literal string. pub fn is_bytestr(&self) -> bool { - match self { - LitKind::ByteStr(_) => true, - _ => false, - } + matches!(self, LitKind::ByteStr(_)) } /// Returns `true` if this is a numeric literal. pub fn is_numeric(&self) -> bool { - match *self { - LitKind::Int(..) | LitKind::Float(..) => true, - _ => false, - } + matches!(self, LitKind::Int(..) | LitKind::Float(..)) } /// Returns `true` if this literal has no suffix. @@ -2237,10 +2213,7 @@ impl FnDecl { self.inputs.get(0).map_or(false, Param::is_self) } pub fn c_variadic(&self) -> bool { - self.inputs.last().map_or(false, |arg| match arg.ty.kind { - TyKind::CVarArgs => true, - _ => false, - }) + self.inputs.last().map_or(false, |arg| matches!(arg.ty.kind, TyKind::CVarArgs)) } } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 19c7c479f042..726ae5e51f7a 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -234,10 +234,7 @@ impl MetaItem { } pub fn is_word(&self) -> bool { - match self.kind { - MetaItemKind::Word => true, - _ => false, - } + matches!(self.kind, MetaItemKind::Word) } pub fn has_name(&self, name: Symbol) -> bool { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index a74464937c8b..cd1e444bcf72 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -130,10 +130,7 @@ impl LitKind { } crate fn may_have_suffix(self) -> bool { - match self { - Integer | Float | Err => true, - _ => false, - } + matches!(self, Integer | Float | Err) } } @@ -305,10 +302,7 @@ impl TokenKind { } pub fn should_end_const_arg(&self) -> bool { - match self { - Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true, - _ => false, - } + matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr)) } } @@ -346,18 +340,21 @@ impl Token { } pub fn is_op(&self) -> bool { - match self.kind { - OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | Eof => false, - _ => true, - } + !matches!( + self.kind, + OpenDelim(..) + | CloseDelim(..) + | Literal(..) + | DocComment(..) + | Ident(..) + | Lifetime(..) + | Interpolated(..) + | Eof + ) } pub fn is_like_plus(&self) -> bool { - match self.kind { - BinOp(Plus) | BinOpEq(Plus) => true, - _ => false, - } + matches!(self.kind, BinOp(Plus) | BinOpEq(Plus)) } /// Returns `true` if the token can appear at the start of an expression. @@ -379,13 +376,10 @@ impl Token { ModSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => match **nt { - NtLiteral(..) | + Interpolated(ref nt) => matches!(**nt, NtLiteral(..) | NtExpr(..) | NtBlock(..) | - NtPath(..) => true, - _ => false, - }, + NtPath(..)), _ => false, } } @@ -405,10 +399,7 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path ModSep => true, // global path - Interpolated(ref nt) => match **nt { - NtTy(..) | NtPath(..) => true, - _ => false, - }, + Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)), _ => false, } } @@ -417,10 +408,7 @@ impl Token { pub fn can_begin_const_arg(&self) -> bool { match self.kind { OpenDelim(Brace) => true, - Interpolated(ref nt) => match **nt { - NtExpr(..) | NtBlock(..) | NtLiteral(..) => true, - _ => false, - }, + Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), _ => self.can_begin_literal_maybe_minus(), } } @@ -436,10 +424,7 @@ impl Token { /// Returns `true` if the token is any literal. pub fn is_lit(&self) -> bool { - match self.kind { - Literal(..) => true, - _ => false, - } + matches!(self.kind, Literal(..)) } /// Returns `true` if the token is any literal, a minus (which can prefix a literal, diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 60422a2e5739..90786520fe80 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -12,14 +12,14 @@ use crate::ast; /// |x| 5 /// isn't parsed as (if true {...} else {...} | x) | 5 pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { - match e.kind { + !matches!( + e.kind, ast::ExprKind::If(..) - | ast::ExprKind::Match(..) - | ast::ExprKind::Block(..) - | ast::ExprKind::While(..) - | ast::ExprKind::Loop(..) - | ast::ExprKind::ForLoop(..) - | ast::ExprKind::TryBlock(..) => false, - _ => true, - } + | ast::ExprKind::Match(..) + | ast::ExprKind::Block(..) + | ast::ExprKind::While(..) + | ast::ExprKind::Loop(..) + | ast::ExprKind::ForLoop(..) + | ast::ExprKind::TryBlock(..) + ) } diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index e97c8cc4562f..e0052b760408 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -178,10 +178,8 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec { if doc_style.is_none() { - let code_to_the_right = match text[pos + token.len..].chars().next() { - Some('\r' | '\n') => false, - _ => true, - }; + let code_to_the_right = + !matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n')); let style = match (code_to_the_left, code_to_the_right) { (_, true) => CommentStyle::Mixed, (false, false) => CommentStyle::Isolated, diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 957c8035399a..ca1226b445d9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -38,10 +38,9 @@ pub fn expand_deriving_clone( | ItemKind::Enum(_, Generics { ref params, .. }) => { let container_id = cx.current_expansion.id.expn_data().parent; if cx.resolver.has_derive_copy(container_id) - && !params.iter().any(|param| match param.kind { - ast::GenericParamKind::Type { .. } => true, - _ => false, - }) + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) { bounds = vec![]; is_shallow = true; diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6531e68be9cd..e78d1368b357 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -404,12 +404,10 @@ impl<'a> TraitDef<'a> { let has_no_type_params = match item.kind { ast::ItemKind::Struct(_, ref generics) | ast::ItemKind::Enum(_, ref generics) - | ast::ItemKind::Union(_, ref generics) => { - !generics.params.iter().any(|param| match param.kind { - ast::GenericParamKind::Type { .. } => true, - _ => false, - }) - } + | ast::ItemKind::Union(_, ref generics) => !generics + .params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), _ => unreachable!(), }; let container_id = cx.current_expansion.id.expn_data().parent; @@ -868,7 +866,7 @@ impl<'a> MethodDef<'a> { Self_ if nonstatic => { self_args.push(arg_expr); } - Ptr(ref ty, _) if (if let Self_ = **ty { true } else { false }) && nonstatic => { + Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => { self_args.push(cx.expr_deref(trait_.span, arg_expr)) } _ => { diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 550524e652af..85ca1da6f1da 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1044,10 +1044,7 @@ pub fn expand_preparsed_format_args( let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg { parse::String(_) => false, - parse::NextArgument(arg) => match arg.position { - parse::Position::ArgumentIs(_) => true, - _ => false, - }, + parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)), }); cx.build_index_map(); diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index f00dfd1241fb..0496c72cb005 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -580,10 +580,7 @@ pub mod printf { } fn is_flag(c: &char) -> bool { - match c { - '0' | '-' | '+' | ' ' | '#' | '\'' => true, - _ => false, - } + matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'') } #[cfg(test)] diff --git a/compiler/rustc_builtin_macros/src/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs index db73fdbe24ff..d203b5bc5429 100644 --- a/compiler/rustc_builtin_macros/src/llvm_asm.rs +++ b/compiler/rustc_builtin_macros/src/llvm_asm.rs @@ -87,9 +87,11 @@ fn parse_inline_asm<'a>( // parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription. let first_colon = tts .trees() - .position(|tt| match tt { - tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) => true, - _ => false, + .position(|tt| { + matches!( + tt, + tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) + ) }) .unwrap_or(tts.len()); let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect()); diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 4e91436199a5..7582d9805390 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -256,10 +256,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // we're just not interested in this item. // // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. - let is_fn = match item.kind { - ast::ItemKind::Fn(..) => true, - _ => false, - }; + let is_fn = matches!(item.kind, ast::ItemKind::Fn(..)); let mut found_attr: Option<&'a ast::Attribute> = None; diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 44bb0deeae97..57e49ba8d1a5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -112,12 +112,12 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { }; // Allow uses of projections that are ZSTs or from scalar fields. - let is_consume = match context { + let is_consume = matches!( + context, PlaceContext::NonMutatingUse( NonMutatingUseContext::Copy | NonMutatingUseContext::Move, - ) => true, - _ => false, - }; + ) + ); if is_consume { let base_ty = mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx()); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 4d3217a9c0bd..0958afa03082 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -132,10 +132,7 @@ impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { [segment] if segment .res - .map(|res| match res { - Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true, - _ => false, - }) + .map(|res| matches!(res, Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _))) .unwrap_or(false) => { self.types.push(path.span); diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index 32f73237dd41..728dc2de3703 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -93,10 +93,7 @@ impl<'tcx> FreeRegionMap<'tcx> { /// True for free regions other than `'static`. pub fn is_free(&self, r: Region<'_>) -> bool { - match *r { - ty::ReEarlyBound(_) | ty::ReFree(_) => true, - _ => false, - } + matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_)) } /// True if `r` is a free region or static of the sort that this diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index d7b2ce7ee208..ab34cda8cc18 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -393,10 +393,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { if self.expand_node(a_region, b_vid, b_data) { changes.push(b_vid); } - match *b_data { - VarValue::Value(ReStatic) | VarValue::ErrorValue => false, - _ => true, - } + !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue) }); } } @@ -972,11 +969,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } VerifyBound::IsEmpty => { - if let ty::ReEmpty(_) = min { - true - } else { - false - } + matches!(min, ty::ReEmpty(_)) } VerifyBound::AnyBound(bs) => { diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs index 6f572a4875f8..9d392c7b26bf 100644 --- a/compiler/rustc_middle/src/hir/map/blocks.rs +++ b/compiler/rustc_middle/src/hir/map/blocks.rs @@ -42,37 +42,25 @@ trait MaybeFnLike { impl MaybeFnLike for hir::Item<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ItemKind::Fn(..) => true, - _ => false, - } + matches!(self.kind, hir::ItemKind::Fn(..)) } } impl MaybeFnLike for hir::ImplItem<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ImplItemKind::Fn(..) => true, - _ => false, - } + matches!(self.kind, hir::ImplItemKind::Fn(..)) } } impl MaybeFnLike for hir::TraitItem<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true, - _ => false, - } + matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_))) } } impl MaybeFnLike for hir::Expr<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ExprKind::Closure(..) => true, - _ => false, - } + matches!(self.kind, hir::ExprKind::Closure(..)) } } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 8a6bf9dff7b6..95096d0fb719 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -118,17 +118,11 @@ impl CoverageKind { } pub fn is_counter(&self) -> bool { - match self { - Self::Counter { .. } => true, - _ => false, - } + matches!(self, Self::Counter { .. }) } pub fn is_expression(&self) -> bool { - match self { - Self::Expression { .. } => true, - _ => false, - } + matches!(self, Self::Expression { .. }) } pub fn is_unreachable(&self) -> bool { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index fc02e78b2fad..fe20925b3879 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -647,14 +647,11 @@ impl Trait for X { let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); // We don't want to suggest calling an assoc fn in a scope where that isn't feasible. - let callable_scope = match body_owner { - Some( + let callable_scope = matches!(body_owner, Some( hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), - ) => true, - _ => false, - }; + )); let impl_comparison = matches!( cause_code, ObligationCauseCode::CompareImplMethodObligation { .. } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9fa399a01697..4ce76409c6f1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -215,10 +215,7 @@ pub enum TyKind<'tcx> { impl TyKind<'tcx> { #[inline] pub fn is_primitive(&self) -> bool { - match self { - Bool | Char | Int(_) | Uint(_) | Float(_) => true, - _ => false, - } + matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_)) } /// Get the article ("a" or "an") to use with this type. diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 1f70fdb5ae30..09281799041e 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -40,11 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr_span = expr.span; let source_info = this.source_info(expr_span); - let expr_is_block_or_scope = match expr.kind { - ExprKind::Block { .. } => true, - ExprKind::Scope { .. } => true, - _ => false, - }; + let expr_is_block_or_scope = matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. }); let schedule_drop = move |this: &mut Self| { if let Some(drop_scope) = scope { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 4510e86e0341..60a47ca12b86 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -501,10 +501,9 @@ impl<'a> Parser<'a> { pub(super) fn expr_is_valid_const_arg(&self, expr: &P) -> bool { match &expr.kind { ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true, - ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind { - ast::ExprKind::Lit(_) => true, - _ => false, - }, + ast::ExprKind::Unary(ast::UnOp::Neg, expr) => { + matches!(expr.kind, ast::ExprKind::Lit(_)) + } // We can only resolve single-segment paths at the moment, because multi-segment paths // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`. ast::ExprKind::Path(None, path) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 00152878d6d9..c4fb0cf5b28d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -23,18 +23,18 @@ use rustc_span::symbol::{sym, Symbol}; // function, then we should explore its block to check for codes that // may need to be marked as live. fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { - match tcx.hir().find(hir_id) { + matches!( + tcx.hir().find(hir_id), Some( Node::Item(..) - | Node::ImplItem(..) - | Node::ForeignItem(..) - | Node::TraitItem(..) - | Node::Variant(..) - | Node::AnonConst(..) - | Node::Pat(..), - ) => true, - _ => false, - } + | Node::ImplItem(..) + | Node::ForeignItem(..) + | Node::TraitItem(..) + | Node::Variant(..) + | Node::AnonConst(..) + | Node::Pat(..), + ) + ) } struct MarkSymbolVisitor<'tcx> { @@ -500,16 +500,16 @@ struct DeadVisitor<'tcx> { impl DeadVisitor<'tcx> { fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool { - let should_warn = match item.kind { + let should_warn = matches!( + item.kind, hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) => true, - _ => false, - }; + | hir::ItemKind::Const(..) + | hir::ItemKind::Fn(..) + | hir::ItemKind::TyAlias(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..) + ); should_warn && !self.symbol_is_live(item.hir_id) } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 86ce35c6d990..54e3cc69aea9 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -367,10 +367,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - let is_shorthand = match param.pat.kind { - rustc_hir::PatKind::Struct(..) => true, - _ => false, - }; + let is_shorthand = matches!(param.pat.kind, rustc_hir::PatKind::Struct(..)); param.pat.each_binding(|_bm, hir_id, _x, ident| { let var = if is_shorthand { Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true }) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 68f59baffce1..b7c703f0e8f7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1653,17 +1653,14 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { for missing in &self.missing_named_lifetime_spots { match missing { MissingLifetimeSpot::Generics(generics) => { - let (span, sugg) = if let Some(param) = - generics.params.iter().find(|p| match p.kind { - hir::GenericParamKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => false, - hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Elided, - } => false, - _ => true, - }) { + let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| { + !matches!(p.kind, hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } | hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Elided, + }) + }) { (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) } else { suggests_in_band = true; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6ab16886ed23..fc6a9a7f2097 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -35,10 +35,7 @@ pub enum AutoTraitResult { #[allow(dead_code)] impl AutoTraitResult { fn is_auto(&self) -> bool { - match *self { - AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, - _ => false, - } + matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl) } } @@ -601,10 +598,7 @@ impl AutoTraitFinder<'tcx> { } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - match *p.ty().skip_binder().kind() { - ty::Projection(proj) if proj == p.skip_binder().projection_ty => true, - _ => false, - } + matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty) } fn evaluate_nested_obligations( diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 9324d55ac1b2..99b96f609647 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -193,10 +193,8 @@ fn overlap_within_probe( let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); - let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) { - Some(true) => true, - _ => false, - }; + let involves_placeholder = + matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true)); Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9feba7bfc492..1d82e732907b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -861,10 +861,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { let arg_length = arguments.len(); - let distinct = match &other[..] { - &[ArgKind::Tuple(..)] => true, - _ => false, - }; + let distinct = matches!(other, &[ArgKind::Tuple(..)]); match (arg_length, arguments.get(0)) { (1, Some(&ArgKind::Tuple(_, ref fields))) => { format!("a single {}-tuple as argument", fields.len()) @@ -1201,12 +1198,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { normalized_ty, data.ty ); - let is_normalized_ty_expected = match &obligation.cause.code { - ObligationCauseCode::ItemObligation(_) + let is_normalized_ty_expected = !matches!(obligation.cause.code, ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ObjectCastObligation(_) => false, - _ => true, - }; + | ObligationCauseCode::ObjectCastObligation(_)); if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( is_normalized_ty_expected, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2fb9b3cd5d30..9c894e99a389 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -323,9 +323,8 @@ pub fn normalize_param_env_or_error<'tcx>( // This works fairly well because trait matching does not actually care about param-env // TypeOutlives predicates - these are normally used by regionck. let outlives_predicates: Vec<_> = predicates - .drain_filter(|predicate| match predicate.skip_binders() { - ty::PredicateAtom::TypeOutlives(..) => true, - _ => false, + .drain_filter(|predicate| { + matches!(predicate.skip_binders(), ty::PredicateAtom::TypeOutlives(..)) }) .collect(); diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index b7e77f389f85..0feac036f002 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -526,18 +526,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generics: &ty::Generics, ) -> bool { let explicit = !seg.infer_args; - let impl_trait = - generics.params.iter().any(|param| match param.kind { - ty::GenericParamDefKind::Type { - synthetic: - Some( - hir::SyntheticTyParamKind::ImplTrait - | hir::SyntheticTyParamKind::FromAttr, - ), - .. - } => true, - _ => false, - }); + let impl_trait = generics.params.iter().any(|param| { + matches!(param.kind, ty::GenericParamDefKind::Type { + synthetic: + Some( + hir::SyntheticTyParamKind::ImplTrait + | hir::SyntheticTyParamKind::FromAttr, + ), + .. + }) + }); if explicit && impl_trait { let spans = seg diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index ec7369fd3e8e..9c60e8933d4d 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -543,10 +543,9 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if let Some(ty) = prohibit_opaque.break_value() { let is_async = match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { - hir::OpaqueTyOrigin::AsyncFn => true, - _ => false, - }, + ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { + matches!(origin, hir::OpaqueTyOrigin::AsyncFn) + } _ => unreachable!(), }; @@ -1321,10 +1320,7 @@ pub fn check_enum<'tcx>( } if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant { - let is_unit = |var: &hir::Variant<'_>| match var.data { - hir::VariantData::Unit(..) => true, - _ => false, - }; + let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..)); let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); let has_non_units = vs.iter().any(|var| !is_unit(var)); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 333bda00dbe8..3e60924d6fcf 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -325,10 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); } - let is_closure = match arg.kind { - ExprKind::Closure(..) => true, - _ => false, - }; + let is_closure = matches!(arg.kind, ExprKind::Closure(..)); if is_closure != check_closures { continue; diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index b8b98cef7637..eca6ce1ecdb6 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -354,10 +354,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { hir_id: hir::HirId, ) { assert!( - match fk { - intravisit::FnKind::Closure(..) => true, - _ => false, - }, + matches!(fk, intravisit::FnKind::Closure(..)), "visit_fn invoked for something other than a closure" ); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index bc6b2037c184..603643d094d9 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -156,10 +156,10 @@ crate fn placeholder_type_error( if let Some(span) = span { sugg.push((span, format!("<{}>", type_name))); } - } else if let Some(arg) = generics.iter().find(|arg| match arg.name { - hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true, - _ => false, - }) { + } else if let Some(arg) = generics + .iter() + .find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. }))) + { // Account for `_` already present in cases like `struct S<_>(_);` and suggest // `struct S(T);` instead of `struct S<_, T>(T);`. sugg.push((arg.span, (*type_name).to_string())); diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index ce9fd5575cf9..3ce244e11bf4 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -595,10 +595,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let upvars = self.tcx().upvars_mentioned(self.body_owner); // For purposes of this function, generator and closures are equivalent. - let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() { - ty::Closure(..) | ty::Generator(..) => true, - _ => false, - }; + let body_owner_is_closure = matches!( + self.tcx().type_of(self.body_owner.to_def_id()).kind(), + ty::Closure(..) | ty::Generator(..) + ); if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id) { From 9e618bacf2c060d19d7dfbdb04c332b81cf56839 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Wed, 18 Nov 2020 18:19:38 +0100 Subject: [PATCH 573/719] BTreeMap: make test cases more explicit on failure --- library/alloc/src/collections/btree/map/tests.rs | 2 +- library/alloc/src/collections/btree/node/tests.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 97df8ea07d23..c857d4317e49 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -115,7 +115,7 @@ impl BTreeMap { impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { fn assert_min_len(self, min_len: usize) { - assert!(self.len() >= min_len, "{} < {}", self.len(), min_len); + assert!(self.len() >= min_len, "node len {} < {}", self.len(), min_len); if let node::ForceResult::Internal(node) = self.force() { for idx in 0..=node.len() { let edge = unsafe { Handle::new_edge(node, idx) }; diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index 6886962106b0..7fe8ff743c04 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -30,11 +30,15 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> let depth = self.height(); let indent = " ".repeat(depth); result += &format!("\n{}", indent); - for idx in 0..leaf.len() { - if idx > 0 { - result += ", "; + if leaf.len() == 0 { + result += "(empty node)"; + } else { + for idx in 0..leaf.len() { + if idx > 0 { + result += ", "; + } + result += &format!("{:?}", unsafe { leaf.key_at(idx) }); } - result += &format!("{:?}", unsafe { leaf.key_at(idx) }); } } navigate::Position::Internal(_) => {} From d473cbe75b50dd583b582d0e99ba0c17228c1f86 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Wed, 18 Nov 2020 18:19:38 +0100 Subject: [PATCH 574/719] BTreeMap: test split_off (and append) more thoroughly --- library/alloc/src/collections/btree/append.rs | 9 ++++++--- .../alloc/src/collections/btree/map/tests.rs | 20 ++++++++++++++++++- library/alloc/src/collections/btree/mod.rs | 7 +++++-- .../alloc/src/collections/btree/set/tests.rs | 4 +++- library/alloc/src/collections/btree/split.rs | 5 +++++ 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index bd99c4ed2f14..9c0ffee84fd2 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -81,15 +81,18 @@ impl Root { // the appended elements even if advancing the iterator panicks. *length += 1; } - self.fix_right_edge(); + self.fix_right_border_of_plentiful(); } - fn fix_right_edge(&mut self) { - // Handle underfull nodes, start from the top. + /// Stock up any underfull nodes on the right border of the tree. + /// The other nodes, those that are not the root nor a rightmost edge, + /// must have MIN_LEN elements to spare. + fn fix_right_border_of_plentiful(&mut self) { let mut cur_node = self.borrow_mut(); while let Internal(internal) = cur_node.force() { // Check if right-most child is underfull. let mut last_kv = internal.last_kv().consider_for_balancing(); + debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2); let right_child_len = last_kv.right_child_len(); if right_child_len < MIN_LEN { // We need to steal. diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 97df8ea07d23..924ab3782910 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1797,7 +1797,6 @@ fn test_append_ord_chaos() { } fn rand_data(len: usize) -> Vec<(u32, u32)> { - assert!(len * 2 <= 70029); // from that point on numbers repeat let mut rng = DeterministicRng::new(); Vec::from_iter((0..len).map(|_| (rng.next(), rng.next()))) } @@ -1862,6 +1861,25 @@ fn test_split_off_tiny_right_height_2() { assert_eq!(*right.last_key_value().unwrap().0, last); } +#[test] +fn test_split_off_halfway() { + let mut rng = DeterministicRng::new(); + for &len in &[NODE_CAPACITY, 25, 50, 75, 100] { + let mut data = Vec::from_iter((0..len).map(|_| (rng.next(), ()))); + // Insertion in non-ascending order creates some variation in node length. + let mut map = BTreeMap::from_iter(data.iter().copied()); + data.sort(); + let small_keys = data.iter().take(len / 2).map(|kv| kv.0); + let large_keys = data.iter().skip(len / 2).map(|kv| kv.0); + let split_key = large_keys.clone().next().unwrap(); + let right = map.split_off(&split_key); + map.check(); + right.check(); + assert!(map.keys().copied().eq(small_keys)); + assert!(right.keys().copied().eq(large_keys)); + } +} + #[test] fn test_split_off_large_random_sorted() { // Miri is too slow diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index ebcbb0e467c4..cdb39104047f 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -38,6 +38,7 @@ pub unsafe fn unwrap_unchecked(val: Option) -> T { #[cfg(test)] /// XorShiftRng struct DeterministicRng { + count: usize, x: u32, y: u32, z: u32, @@ -47,11 +48,13 @@ struct DeterministicRng { #[cfg(test)] impl DeterministicRng { fn new() -> Self { - DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } + DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } } - /// Guarantees that the first 70029 results are unique. + /// Guarantees that each returned number is unique. fn next(&mut self) -> u32 { + self.count += 1; + assert!(self.count <= 70029); let x = self.x; let t = x ^ (x << 11); self.x = self.y; diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 4d05bc4ebfa1..fd19c0078a74 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -696,8 +696,10 @@ fn test_first_last() { assert_eq!(a.pop_last(), None); } +// Unlike the function with the same name in map/tests, returns no values. +// Which also means it returns different predetermined pseudo-random keys, +// and the test cases using this function explore slightly different trees. fn rand_data(len: usize) -> Vec { - assert!(len <= 70029); // from that point on numbers repeat let mut rng = DeterministicRng::new(); Vec::from_iter((0..len).map(|_| rng.next())) } diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs index 6108c139bb3a..4561c8eaf47f 100644 --- a/library/alloc/src/collections/btree/split.rs +++ b/library/alloc/src/collections/btree/split.rs @@ -53,6 +53,9 @@ impl Root { } } + /// Stock up or merge away any underfull nodes on the right border of the + /// tree. The other nodes, those that are not the root nor a rightmost edge, + /// must already have at least MIN_LEN elements. fn fix_right_border(&mut self) { self.fix_top(); @@ -72,6 +75,7 @@ impl Root { } cur_node = last_kv.into_right_child(); } + debug_assert!(cur_node.len() > MIN_LEN); } } @@ -98,6 +102,7 @@ impl Root { } cur_node = first_kv.into_left_child(); } + debug_assert!(cur_node.len() > MIN_LEN); } } From f327a352b89a571dde76e176471d12fbd8fce0dd Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Wed, 18 Nov 2020 18:19:38 +0100 Subject: [PATCH 575/719] BTreeMap: test full nodes a little more --- library/alloc/src/collections/btree/append.rs | 2 +- .../alloc/src/collections/btree/map/tests.rs | 40 +++++++++++++++---- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index bd99c4ed2f14..9c53c84f5b2f 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -30,7 +30,7 @@ impl Root { /// Pushes all key-value pairs to the end of the tree, incrementing a /// `length` variable along the way. The latter makes it easier for the /// caller to avoid a leak when the iterator panicks. - fn bulk_push(&mut self, iter: I, length: &mut usize) + pub fn bulk_push(&mut self, iter: I, length: &mut usize) where I: Iterator, { diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 97df8ea07d23..565dc175393a 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -111,6 +111,18 @@ impl BTreeMap { } } } + + // Transform the tree to minimize wasted space, obtaining fewer nodes that + // are mostly filled up to their capacity. The same compact tree could have + // been obtained by inserting keys in a shrewd order. + fn compact(&mut self) + where + K: Ord, + { + let iter = mem::take(self).into_iter(); + let root = BTreeMap::ensure_is_owned(&mut self.root); + root.bulk_push(iter, &mut self.length); + } } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { @@ -1679,17 +1691,29 @@ fn test_first_last_entry() { } #[test] -fn test_insert_into_full_left() { - let mut map: BTreeMap<_, _> = (0..NODE_CAPACITY).map(|i| (i * 2, ())).collect(); - assert!(map.insert(NODE_CAPACITY, ()).is_none()); - map.check(); +fn test_insert_into_full_height_0() { + let size = NODE_CAPACITY; + for pos in 0..=size { + let mut map: BTreeMap<_, _> = (0..size).map(|i| (i * 2 + 1, ())).collect(); + assert!(map.insert(pos * 2, ()).is_none()); + map.check(); + } } #[test] -fn test_insert_into_full_right() { - let mut map: BTreeMap<_, _> = (0..NODE_CAPACITY).map(|i| (i * 2, ())).collect(); - assert!(map.insert(NODE_CAPACITY + 2, ()).is_none()); - map.check(); +fn test_insert_into_full_height_1() { + let size = NODE_CAPACITY + 1 + NODE_CAPACITY; + for pos in 0..=size { + let mut map: BTreeMap<_, _> = (0..size).map(|i| (i * 2 + 1, ())).collect(); + map.compact(); + let root_node = map.root.as_ref().unwrap().reborrow(); + assert_eq!(root_node.len(), 1); + assert_eq!(root_node.first_leaf_edge().into_node().len(), NODE_CAPACITY); + assert_eq!(root_node.last_leaf_edge().into_node().len(), NODE_CAPACITY); + + assert!(map.insert(pos * 2, ()).is_none()); + map.check(); + } } macro_rules! create_append_test { From db1451c7ad08e77a17c59f6755f234ea507ead92 Mon Sep 17 00:00:00 2001 From: ThePuzzlemaker Date: Sun, 20 Dec 2020 01:34:33 -0600 Subject: [PATCH 576/719] rustdoc: Highlight edition-specific keywords correctly in code blocks, accounting for code block edition modifiers This is a squash of these commits: - Highlight edition-specific keywords correctly in code blocks, accounting for code block edition modifiers - Fix unit tests - Revert changes to rustc_span::symbol to prepare for merge of #80272 - Use new Symbol::is_reserved API from #80272 - Remove unused import added by accident when merging --- src/librustdoc/html/highlight.rs | 22 +++++++++++++++------- src/librustdoc/html/highlight/tests.rs | 5 +++-- src/librustdoc/html/markdown.rs | 1 + src/librustdoc/html/render/mod.rs | 1 + src/librustdoc/html/sources.rs | 7 ++++--- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 077481c89895..d21998bb8cfe 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -12,7 +12,7 @@ use std::iter::Peekable; use rustc_lexer::{LiteralKind, TokenKind}; use rustc_span::edition::Edition; -use rustc_span::symbol::Ident; +use rustc_span::symbol::Symbol; use rustc_span::with_default_session_globals; /// Highlights `src`, returning the HTML output. @@ -21,6 +21,7 @@ crate fn render_with_highlighting( class: Option<&str>, playground_button: Option<&str>, tooltip: Option<(Option, &str)>, + edition: Edition, ) -> String { debug!("highlighting: ================\n{}\n==============", src); let mut out = String::with_capacity(src.len()); @@ -39,7 +40,7 @@ crate fn render_with_highlighting( } write_header(&mut out, class); - write_code(&mut out, &src); + write_code(&mut out, &src, edition); write_footer(&mut out, playground_button); out @@ -50,10 +51,10 @@ fn write_header(out: &mut String, class: Option<&str>) { .unwrap() } -fn write_code(out: &mut String, src: &str) { +fn write_code(out: &mut String, src: &str, edition: Edition) { // This replace allows to fix how the code source with DOS backline characters is displayed. let src = src.replace("\r\n", "\n"); - Classifier::new(&src).highlight(&mut |highlight| { + Classifier::new(&src, edition).highlight(&mut |highlight| { match highlight { Highlight::Token { text, class } => string(out, Escape(text), class), Highlight::EnterSpan { class } => enter_span(out, class), @@ -144,12 +145,19 @@ struct Classifier<'a> { in_attribute: bool, in_macro: bool, in_macro_nonterminal: bool, + edition: Edition, } impl<'a> Classifier<'a> { - fn new(src: &str) -> Classifier<'_> { + fn new(src: &str, edition: Edition) -> Classifier<'_> { let tokens = TokenIter { src }.peekable(); - Classifier { tokens, in_attribute: false, in_macro: false, in_macro_nonterminal: false } + Classifier { + tokens, + in_attribute: false, + in_macro: false, + in_macro_nonterminal: false, + edition, + } } /// Exhausts the `Classifier` writing the output into `sink`. @@ -301,7 +309,7 @@ impl<'a> Classifier<'a> { "Option" | "Result" => Class::PreludeTy, "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, // Keywords are also included in the identifier set. - _ if Ident::from_str(text).is_reserved() => Class::KeyWord, + _ if Symbol::intern(text).is_reserved(|| self.edition) => Class::KeyWord, _ if self.in_macro_nonterminal => { self.in_macro_nonterminal = false; Class::MacroNonTerminal diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index f57f52d6f087..f97c8a7ab714 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,5 +1,6 @@ use super::write_code; use expect_test::expect_file; +use rustc_span::edition::Edition; const STYLE: &str = r#"