diff options
102 files changed, 1623 insertions, 606 deletions
diff --git a/Cargo.lock b/Cargo.lock index d4f4ec7f6f0..75d644c1ed9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,12 +139,6 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - -[[package]] -name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" @@ -766,7 +760,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0", + "autocfg", "cfg-if", "lazy_static", ] @@ -1245,11 +1239,11 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.6.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd9867f119b19fecb08cd5c326ad4488d7a1da4bf75b4d95d71db742525aaab" +checksum = "34f595585f103464d8d2f6e9864682d74c1601fed5e07d62b1c9058dba8246fb" dependencies = [ - "autocfg 0.1.7", + "autocfg", "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -2079,7 +2073,7 @@ version = "0.9.54" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" dependencies = [ - "autocfg 1.0.0", + "autocfg", "cc", "libc", "openssl-src", diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 1db629c3bdf..1d5fa73d228 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1294,7 +1294,7 @@ impl<K: Ord, V> BTreeMap<K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap<K, V> { +impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1363,7 +1363,7 @@ impl<K, V> Clone for Iter<'_, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap<K, V> { +impl<'a, K, V> IntoIterator for &'a mut BTreeMap<K, V> { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index 0dcb5930964..33b1ee003ed 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -1,3 +1,5 @@ +use core::intrinsics; +use core::mem; use core::ptr; use super::node::{marker, ForceResult::*, Handle, NodeRef}; @@ -79,16 +81,24 @@ def_next_kv_uncheched_dealloc! {unsafe fn next_kv_unchecked_dealloc: right_kv} def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv} /// This replaces the value behind the `v` unique reference by calling the -/// relevant function. +/// relevant function, and returns a result obtained along the way. /// -/// Safety: The change closure must not panic. +/// If a panic occurs in the `change` closure, the entire process will be aborted. #[inline] -unsafe fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { +fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { + struct PanicGuard; + impl Drop for PanicGuard { + fn drop(&mut self) { + intrinsics::abort() + } + } + let guard = PanicGuard; let value = unsafe { ptr::read(v) }; let (new_value, ret) = change(value); unsafe { ptr::write(v, new_value); } + mem::forget(guard); ret } @@ -97,26 +107,22 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed /// key and value in between. /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree. pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { - unsafe { - replace(self, |leaf_edge| { - let kv = leaf_edge.next_kv(); - let kv = unwrap_unchecked(kv.ok()); - (kv.next_leaf_edge(), kv.into_kv()) - }) - } + replace(self, |leaf_edge| { + let kv = leaf_edge.next_kv(); + let kv = unsafe { unwrap_unchecked(kv.ok()) }; + (kv.next_leaf_edge(), kv.into_kv()) + }) } /// Moves the leaf edge handle to the previous leaf edge and returns references to the /// key and value in between. /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree. pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { - unsafe { - replace(self, |leaf_edge| { - let kv = leaf_edge.next_back_kv(); - let kv = unwrap_unchecked(kv.ok()); - (kv.next_back_leaf_edge(), kv.into_kv()) - }) - } + replace(self, |leaf_edge| { + let kv = leaf_edge.next_back_kv(); + let kv = unsafe { unwrap_unchecked(kv.ok()) }; + (kv.next_back_leaf_edge(), kv.into_kv()) + }) } } @@ -127,16 +133,14 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge /// - The caller must ensure that the leaf edge is not the last one in the tree. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - unsafe { - let kv = replace(self, |leaf_edge| { - let kv = leaf_edge.next_kv(); - let kv = unwrap_unchecked(kv.ok()); - (ptr::read(&kv).next_leaf_edge(), kv) - }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() - } + let kv = replace(self, |leaf_edge| { + let kv = leaf_edge.next_kv(); + let kv = unsafe { unwrap_unchecked(kv.ok()) }; + (unsafe { ptr::read(&kv) }.next_leaf_edge(), kv) + }); + // Doing the descend (and perhaps another move) invalidates the references + // returned by `into_kv_mut`, so we have to do this last. + kv.into_kv_mut() } /// Moves the leaf edge handle to the previous leaf and returns references to the @@ -145,16 +149,14 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge /// - The caller must ensure that the leaf edge is not the first one in the tree. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - unsafe { - let kv = replace(self, |leaf_edge| { - let kv = leaf_edge.next_back_kv(); - let kv = unwrap_unchecked(kv.ok()); - (ptr::read(&kv).next_back_leaf_edge(), kv) - }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() - } + let kv = replace(self, |leaf_edge| { + let kv = leaf_edge.next_back_kv(); + let kv = unsafe { unwrap_unchecked(kv.ok()) }; + (unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv) + }); + // Doing the descend (and perhaps another move) invalidates the references + // returned by `into_kv_mut`, so we have to do this last. + kv.into_kv_mut() } } @@ -172,14 +174,12 @@ impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> { /// call this method again subject to both preconditions listed in the first point, /// or call counterpart `next_back_unchecked` subject to its preconditions. pub unsafe fn next_unchecked(&mut self) -> (K, V) { - unsafe { - replace(self, |leaf_edge| { - let kv = next_kv_unchecked_dealloc(leaf_edge); - let k = ptr::read(kv.reborrow().into_kv().0); - let v = ptr::read(kv.reborrow().into_kv().1); - (kv.next_leaf_edge(), (k, v)) - }) - } + replace(self, |leaf_edge| { + let kv = unsafe { next_kv_unchecked_dealloc(leaf_edge) }; + let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; + let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; + (kv.next_leaf_edge(), (k, v)) + }) } /// Moves the leaf edge handle to the previous leaf edge and returns the key @@ -195,14 +195,12 @@ impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> { /// call this method again subject to both preconditions listed in the first point, /// or call counterpart `next_unchecked` subject to its preconditions. pub unsafe fn next_back_unchecked(&mut self) -> (K, V) { - unsafe { - replace(self, |leaf_edge| { - let kv = next_back_kv_unchecked_dealloc(leaf_edge); - let k = ptr::read(kv.reborrow().into_kv().0); - let v = ptr::read(kv.reborrow().into_kv().1); - (kv.next_back_leaf_edge(), (k, v)) - }) - } + replace(self, |leaf_edge| { + let kv = unsafe { next_back_kv_unchecked_dealloc(leaf_edge) }; + let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; + let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; + (kv.next_back_leaf_edge(), (k, v)) + }) } } diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index eb50dc28b9f..95eae7e2a73 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -4383,8 +4383,8 @@ assert_eq!( } doc_comment! { - concat!("Create an integer value from its representation as a byte array in -big endian. + concat!("Create a native endian integer value from its representation +as a byte array in big endian. ", $from_xe_bytes_doc, " @@ -4416,8 +4416,8 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), doc_comment! { concat!(" -Create an integer value from its representation as a byte array in -little endian. +Create a native endian integer value from its representation +as a byte array in little endian. ", $from_xe_bytes_doc, " @@ -4448,8 +4448,8 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } doc_comment! { - concat!("Create an integer value from its memory representation as a byte -array in native endianness. + concat!("Create a native endian integer value from its memory representation +as a byte array in native endianness. As the target platform's native endianness is used, portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index a2acc239bd3..a16970e9fd1 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -656,6 +656,38 @@ impl<T: ?Sized> *const T { self.wrapping_offset((count as isize).wrapping_neg()) } + /// Sets the pointer value to `ptr`. + /// + /// In case `self` is a (fat) pointer to an unsized type, this operation + /// will only affect the pointer part, whereas for (thin) pointers to + /// sized types, this has the same effect as a simple assignment. + /// + /// # Examples + /// + /// This function is primarily useful for allowing byte-wise pointer + /// arithmetic on potentially fat pointers: + /// + /// ``` + /// #![feature(set_ptr_value)] + /// # use core::fmt::Debug; + /// let arr: [i32; 3] = [1, 2, 3]; + /// let mut ptr = &arr[0] as *const dyn Debug; + /// let thin = ptr as *const u8; + /// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() }); + /// assert_eq!(unsafe { *(ptr as *const i32) }, 3); + /// ``` + #[unstable(feature = "set_ptr_value", issue = "75091")] + #[inline] + pub fn set_ptr_value(mut self, val: *const ()) -> Self { + let thin = &mut self as *mut *const T as *mut *const (); + // SAFETY: In case of a thin pointer, this operations is identical + // to a simple assignment. In case of a fat pointer, with the current + // fat pointer layout implementation, the first field of such a + // pointer is always the data pointer, which is likewise assigned. + unsafe { *thin = val }; + self + } + /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 17fa90ecc08..b47f90c5996 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -712,6 +712,38 @@ impl<T: ?Sized> *mut T { self.wrapping_offset((count as isize).wrapping_neg()) } + /// Sets the pointer value to `ptr`. + /// + /// In case `self` is a (fat) pointer to an unsized type, this operation + /// will only affect the pointer part, whereas for (thin) pointers to + /// sized types, this has the same effect as a simple assignment. + /// + /// # Examples + /// + /// This function is primarily useful for allowing byte-wise pointer + /// arithmetic on potentially fat pointers: + /// + /// ``` + /// #![feature(set_ptr_value)] + /// # use core::fmt::Debug; + /// let mut arr: [i32; 3] = [1, 2, 3]; + /// let mut ptr = &mut arr[0] as *mut dyn Debug; + /// let thin = ptr as *mut u8; + /// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() }); + /// assert_eq!(unsafe { *(ptr as *mut i32) }, 3); + /// ``` + #[unstable(feature = "set_ptr_value", issue = "75091")] + #[inline] + pub fn set_ptr_value(mut self, val: *mut ()) -> Self { + let thin = &mut self as *mut *mut T as *mut *mut (); + // SAFETY: In case of a thin pointer, this operations is identical + // to a simple assignment. In case of a fat pointer, with the current + // fat pointer layout implementation, the first field of such a + // pointer is always the data pointer, which is likewise assigned. + unsafe { *thin = val }; + self + } + /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 9d7e38d0e18..eac4741cd26 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1923,7 +1923,10 @@ mod traits { #[inline] fn index(self, slice: &str) -> &Self::Output { let (start, end) = (self.start, self.end); - self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, start, end), + } } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { @@ -1995,7 +1998,10 @@ mod traits { #[inline] fn index(self, slice: &str) -> &Self::Output { let end = self.end; - self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, 0, end), + } } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { @@ -2068,7 +2074,10 @@ mod traits { #[inline] fn index(self, slice: &str) -> &Self::Output { let (start, end) = (self.start, slice.len()); - self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, start, end), + } } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 474765d8638..fc07fa77b85 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -20,7 +20,7 @@ libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of compiler_builtins = { version = "0.1.32" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] } +hashbrown = { version = "0.8.1", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate addr2line = { version = "0.13.0", optional = true, default-features = false } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 7b48deee1ab..c40d6119fdf 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -580,7 +580,7 @@ where #[inline] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.base.try_reserve(additional).map_err(map_collection_alloc_err) + self.base.try_reserve(additional).map_err(map_try_reserve_error) } /// Shrinks the capacity of the map as much as possible. It will drop @@ -2569,10 +2569,10 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, } #[inline] -fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> TryReserveError { +fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { match err { - hashbrown::CollectionAllocErr::CapacityOverflow => TryReserveError::CapacityOverflow, - hashbrown::CollectionAllocErr::AllocErr { layout } => { + hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow, + hashbrown::TryReserveError::AllocError { layout } => { TryReserveError::AllocError { layout, non_exhaustive: () } } } diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index a0c0981ebf9..159ab981b23 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -961,11 +961,6 @@ impl AsInner<c::in_addr> for Ipv4Addr { &self.inner } } -impl FromInner<c::in_addr> for Ipv4Addr { - fn from_inner(addr: c::in_addr) -> Ipv4Addr { - Ipv4Addr { inner: addr } - } -} #[stable(feature = "ip_u32", since = "1.1.0")] impl From<Ipv4Addr> for u32 { @@ -976,8 +971,8 @@ impl From<Ipv4Addr> for u32 { /// ``` /// use std::net::Ipv4Addr; /// - /// let addr = Ipv4Addr::new(13, 12, 11, 10); - /// assert_eq!(0x0d0c0b0au32, u32::from(addr)); + /// let addr = Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe); + /// assert_eq!(0xcafebabe, u32::from(addr)); /// ``` fn from(ip: Ipv4Addr) -> u32 { let ip = ip.octets(); @@ -994,8 +989,8 @@ impl From<u32> for Ipv4Addr { /// ``` /// use std::net::Ipv4Addr; /// - /// let addr = Ipv4Addr::from(0x0d0c0b0au32); - /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// let addr = Ipv4Addr::from(0xcafebabe); + /// assert_eq!(Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe), addr); /// ``` fn from(ip: u32) -> Ipv4Addr { Ipv4Addr::from(ip.to_be_bytes()) diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index ab2a6010306..21ab0faed3e 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -434,7 +434,9 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { let loc = info.location().unwrap(); // The current implementation always returns Some let msg = info.message().unwrap(); // The current implementation always returns Some - rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc); + crate::sys_common::backtrace::__rust_end_short_backtrace(move || { + rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc); + }) } /// This is the entry point of panicking for the non-format-string variants of @@ -453,7 +455,10 @@ pub fn begin_panic<M: Any + Send>(msg: M) -> ! { intrinsics::abort() } - rust_panic_with_hook(&mut PanicPayload::new(msg), None, Location::caller()); + let loc = Location::caller(); + return crate::sys_common::backtrace::__rust_end_short_backtrace(move || { + rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc) + }); struct PanicPayload<A> { inner: Option<A>, diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index fb825ab16eb..45af9f68a0f 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -48,9 +48,7 @@ fn lang_start_internal( sys::args::init(argc, argv); // Let's run some code! - let exit_code = panic::catch_unwind(|| { - sys_common::backtrace::__rust_begin_short_backtrace(move || main()) - }); + let exit_code = panic::catch_unwind(main); sys_common::cleanup(); exit_code.unwrap_or(101) as isize @@ -64,5 +62,9 @@ fn lang_start<T: crate::process::Termination + 'static>( argc: isize, argv: *const *const u8, ) -> isize { - lang_start_internal(&move || main().report(), argc, argv) + lang_start_internal( + &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(), + argc, + argv, + ) } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index e36a53084ba..ba169b251b0 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -283,12 +283,12 @@ impl Drop for FileDesc { #[cfg(test)] mod tests { use super::{FileDesc, IoSlice}; + use core::mem::ManuallyDrop; #[test] fn limit_vector_count() { - let stdout = FileDesc { fd: 1 }; + let stdout = ManuallyDrop::new(FileDesc { fd: 1 }); let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>(); - assert!(stdout.write_vectored(&bufs).is_ok()); } } diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index d386a656e4f..1c5fbf7d701 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -74,6 +74,8 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: bt_fmt.add_context()?; let mut idx = 0; let mut res = Ok(()); + // Start immediately if we're not using a short backtrace. + let mut start = print_fmt != PrintFmt::Short; backtrace_rs::trace_unsynchronized(|frame| { if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { return false; @@ -89,16 +91,24 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: stop = true; return; } + if sym.contains("__rust_end_short_backtrace") { + start = true; + return; + } } } - res = bt_fmt.frame().symbol(frame, symbol); + if start { + res = bt_fmt.frame().symbol(frame, symbol); + } }); if stop { return false; } if !hit { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); + if start { + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); + } } idx += 1; @@ -123,10 +133,29 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T where F: FnOnce() -> T, - F: Send, - T: Send, { - f() + let result = f(); + + // prevent this frame from being tail-call optimised away + crate::hint::black_box(()); + + result +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that +/// this is only inline(never) when backtraces in libstd are enabled, otherwise +/// it's fine to optimize away. +#[cfg_attr(feature = "backtrace", inline(never))] +pub fn __rust_end_short_backtrace<F, T>(f: F) -> T +where + F: FnOnce() -> T, +{ + let result = f(); + + // prevent this frame from being tail-call optimised away + crate::hint::black_box(()); + + result } pub enum RustBacktrace { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 933b647071f..6bd708ef487 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -514,7 +514,10 @@ pub fn run_test( /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. #[inline(never)] fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) { - f() + f(); + + // prevent this frame from being tail-call optimised away + black_box(()); } fn run_test_in_process( diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index cec9c56a235..67f99ec4e40 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -352,8 +352,13 @@ class StdHashMapProvider: ctrl = table["ctrl"]["pointer"] self.size = int(table["items"]) - self.data_ptr = table["data"]["pointer"] - self.pair_type = self.data_ptr.dereference().type + self.pair_type = table.type.template_argument(0) + + self.new_layout = not table.type.has_key("data") + if self.new_layout: + self.data_ptr = ctrl.cast(self.pair_type.pointer()) + else: + self.data_ptr = table["data"]["pointer"] self.valid_indices = [] for idx in range(capacity): @@ -374,6 +379,8 @@ class StdHashMapProvider: for index in range(self.size): idx = self.valid_indices[index] + if self.new_layout: + idx = -(idx + 1) element = (pairs_start + idx).dereference() if self.show_values: yield "key{}".format(index), element[ZERO_FIELD] diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 3c7817b3a61..19da75c35b4 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -514,6 +514,8 @@ class StdHashMapSyntheticProvider: # type: (int) -> SBValue pairs_start = self.data_ptr.GetValueAsUnsigned() idx = self.valid_indices[index] + if self.new_layout: + idx = -(idx + 1) address = pairs_start + idx * self.pair_type_size element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type) if self.show_values: @@ -529,10 +531,15 @@ class StdHashMapSyntheticProvider: ctrl = table.GetChildMemberWithName("ctrl").GetChildAtIndex(0) self.size = table.GetChildMemberWithName("items").GetValueAsUnsigned() - self.data_ptr = table.GetChildMemberWithName("data").GetChildAtIndex(0) - self.pair_type = self.data_ptr.Dereference().GetType() + self.pair_type = table.type.template_args[0] self.pair_type_size = self.pair_type.GetByteSize() + self.new_layout = not table.GetChildMemberWithName("data").IsValid() + if self.new_layout: + self.data_ptr = ctrl.Cast(self.pair_type.GetPointerType()) + else: + self.data_ptr = table.GetChildMemberWithName("data").GetChildAtIndex(0) + u8_type = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar) u8_type_size = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar).GetByteSize() diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index b3fc3d17af7..4e81173d3d0 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -30,6 +30,7 @@ <Expand> <Item Name="[size]">base.table.items</Item> <Item Name="[capacity]">base.table.items + base.table.growth_left</Item> + <Item Name="[state]">base.hash_builder</Item> <CustomListItems> <Variable Name="i" InitialValue="0" /> @@ -40,7 +41,7 @@ <If Condition="(base.table.ctrl.pointer[i] & 0x80) == 0"> <!-- Bucket is populated --> <Exec>n--</Exec> - <Item Name="{base.table.data.pointer[i].__0}">base.table.data.pointer[i].__1</Item> + <Item Name="{static_cast<tuple<$T1, $T2>*>(base.table.ctrl.pointer)[-(i + 1)].__0}">static_cast<tuple<$T1, $T2>*>(base.table.ctrl.pointer)[-(i + 1)].__1</Item> </If> <Exec>i++</Exec> </Loop> @@ -53,6 +54,7 @@ <Expand> <Item Name="[size]">map.base.table.items</Item> <Item Name="[capacity]">map.base.table.items + map.base.table.growth_left</Item> + <Item Name="[state]">map.base.hash_builder</Item> <CustomListItems> <Variable Name="i" InitialValue="0" /> @@ -63,36 +65,7 @@ <If Condition="(map.base.table.ctrl.pointer[i] & 0x80) == 0"> <!-- Bucket is populated --> <Exec>n--</Exec> - <Item>map.base.table.data.pointer[i].__0</Item> - </If> - <Exec>i++</Exec> - </Loop> - </CustomListItems> - </Expand> - </Type> - - <Type Name="hashbrown::raw::RawTable<*>"> - <!-- RawTable has a nice and simple layout. - items Number of *populated* values in the RawTable (less than the size of ctrl.pointer / data.pointer) - growth_left Remaining capacity before growth - ctrl.pointer[i] & 0x80 Indicates the bucket is empty / should be skipped / doesn't count towards items. - data.pointer[i] The (K,V) tuple, if not empty. - --> - <DisplayString>{{ size={items} }}</DisplayString> - <Expand> - <Item Name="[size]">items</Item> - <Item Name="[capacity]">items + growth_left</Item> - - <CustomListItems> - <Variable Name="i" InitialValue="0" /> - <Variable Name="n" InitialValue="items" /> - <Size>items</Size> - <Loop> - <Break Condition="n == 0" /> - <If Condition="(ctrl.pointer[i] & 0x80) == 0"> - <!-- Bucket is populated --> - <Exec>n--</Exec> - <Item>data.pointer[i]</Item> + <Item>static_cast<$T1*>(map.base.table.ctrl.pointer)[-(i + 1)]</Item> </If> <Exec>i++</Exec> </Loop> diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 6543117774a..9337b27e5e9 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -23,7 +23,7 @@ pub use GenericArgs::*; pub use UnsafeSource::*; use crate::ptr::P; -use crate::token::{self, DelimToken}; +use crate::token::{self, CommentKind, DelimToken}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -2365,7 +2365,7 @@ pub enum AttrKind { /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` /// variant (which is much less compact and thus more expensive). - DocComment(Symbol), + DocComment(CommentKind, Symbol), } /// `TraitRef`s appear in impls. diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs index 809fda86542..847d126b3ef 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -7,7 +7,7 @@ use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Path, PathSegment}; use crate::mut_visit::visit_clobber; use crate::ptr::P; -use crate::token::{self, Token}; +use crate::token::{self, CommentKind, Token}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use rustc_data_structures::sync::Lock; @@ -169,7 +169,7 @@ impl Attribute { pub fn has_name(&self, name: Symbol) -> bool { match self.kind { AttrKind::Normal(ref item) => item.path == name, - AttrKind::DocComment(_) => false, + AttrKind::DocComment(..) => false, } } @@ -198,7 +198,7 @@ impl Attribute { None } } - AttrKind::DocComment(_) => None, + AttrKind::DocComment(..) => None, } } pub fn name_or_empty(&self) -> Symbol { @@ -218,7 +218,7 @@ impl Attribute { Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), _ => None, }, - AttrKind::DocComment(_) => None, + AttrKind::DocComment(..) => None, } } @@ -314,13 +314,13 @@ impl Attribute { pub fn is_doc_comment(&self) -> bool { match self.kind { AttrKind::Normal(_) => false, - AttrKind::DocComment(_) => true, + AttrKind::DocComment(..) => true, } } pub fn doc_str(&self) -> Option<Symbol> { match self.kind { - AttrKind::DocComment(symbol) => Some(symbol), + AttrKind::DocComment(.., data) => Some(data), AttrKind::Normal(ref item) if item.path == sym::doc => { item.meta(self.span).and_then(|meta| meta.value_str()) } @@ -331,14 +331,14 @@ impl Attribute { pub fn get_normal_item(&self) -> &AttrItem { match self.kind { AttrKind::Normal(ref item) => item, - AttrKind::DocComment(_) => panic!("unexpected doc comment"), + AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } pub fn unwrap_normal_item(self) -> AttrItem { match self.kind { AttrKind::Normal(item) => item, - AttrKind::DocComment(_) => panic!("unexpected doc comment"), + AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } @@ -405,8 +405,13 @@ pub fn mk_attr_outer(item: MetaItem) -> Attribute { mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) } -pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute { - Attribute { kind: AttrKind::DocComment(comment), id: mk_attr_id(), style, span } +pub fn mk_doc_comment( + comment_kind: CommentKind, + style: AttrStyle, + data: Symbol, + span: Span, +) -> Attribute { + Attribute { kind: AttrKind::DocComment(comment_kind, data), id: mk_attr_id(), style, span } } pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs index 54f81ef106f..df6e8218f6c 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -582,7 +582,7 @@ pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { vis.visit_path(path); visit_mac_args(args, vis); } - AttrKind::DocComment(_) => {} + AttrKind::DocComment(..) => {} } vis.visit_span(span); } diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index e1c94ddf782..bcce881ed48 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -17,6 +17,12 @@ use rustc_span::{self, Span, DUMMY_SP}; use std::borrow::Cow; use std::{fmt, mem}; +#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +pub enum CommentKind { + Line, + Block, +} + #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] #[derive(HashStable_Generic)] pub enum BinOpToken { @@ -238,9 +244,10 @@ pub enum TokenKind { Interpolated(Lrc<Nonterminal>), - // Can be expanded into several tokens. - /// A doc comment. - DocComment(Symbol), + /// A doc comment token. + /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc) + /// similarly to symbols in string literal tokens. + DocComment(CommentKind, ast::AttrStyle, Symbol), // Junk. These carry no data because we don't really care about the data // they *would* carry, and don't really want to allocate a new ident for diff --git a/src/librustc_ast/util/comments.rs b/src/librustc_ast/util/comments.rs index 39921b20226..a73891db160 100644 --- a/src/librustc_ast/util/comments.rs +++ b/src/librustc_ast/util/comments.rs @@ -1,11 +1,7 @@ -pub use CommentStyle::*; - -use crate::ast; +use crate::ast::AttrStyle; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol}; -use log::debug; - #[cfg(test)] mod tests; @@ -28,43 +24,48 @@ pub struct Comment { pub pos: BytePos, } -pub fn is_line_doc_comment(s: &str) -> bool { - let res = (s.starts_with("///") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'/') - || s.starts_with("//!"); - debug!("is {:?} a doc comment? {}", s, res); - res -} - -pub fn is_block_doc_comment(s: &str) -> bool { - // Prevent `/**/` from being parsed as a doc comment - let res = ((s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*') - || s.starts_with("/*!")) - && s.len() >= 5; - debug!("is {:?} a doc comment? {}", s, res); - res -} - -// FIXME(#64197): Try to privatize this again. -pub fn is_doc_comment(s: &str) -> bool { - (s.starts_with("///") && is_line_doc_comment(s)) - || s.starts_with("//!") - || (s.starts_with("/**") && is_block_doc_comment(s)) - || s.starts_with("/*!") +/// For a full line comment string returns its doc comment style if it's a doc comment +/// and returns `None` if it's a regular comment. +pub fn line_doc_comment_style(line_comment: &str) -> Option<AttrStyle> { + let line_comment = line_comment.as_bytes(); + assert!(line_comment.starts_with(b"//")); + match line_comment.get(2) { + // `//!` is an inner line doc comment. + Some(b'!') => Some(AttrStyle::Inner), + Some(b'/') => match line_comment.get(3) { + // `////` (more than 3 slashes) is not considered a doc comment. + Some(b'/') => None, + // Otherwise `///` is an outer line doc comment. + _ => Some(AttrStyle::Outer), + }, + _ => None, + } } -pub fn doc_comment_style(comment: Symbol) -> ast::AttrStyle { - let comment = &comment.as_str(); - assert!(is_doc_comment(comment)); - if comment.starts_with("//!") || comment.starts_with("/*!") { - ast::AttrStyle::Inner - } else { - ast::AttrStyle::Outer +/// For a full block comment string returns its doc comment style if it's a doc comment +/// and returns `None` if it's a regular comment. +pub fn block_doc_comment_style(block_comment: &str, terminated: bool) -> Option<AttrStyle> { + let block_comment = block_comment.as_bytes(); + assert!(block_comment.starts_with(b"/*")); + assert!(!terminated || block_comment.ends_with(b"*/")); + match block_comment.get(2) { + // `/*!` is an inner block doc comment. + Some(b'!') => Some(AttrStyle::Inner), + Some(b'*') => match block_comment.get(3) { + // `/***` (more than 2 stars) is not considered a doc comment. + Some(b'*') => None, + // `/**/` is not considered a doc comment. + Some(b'/') if block_comment.len() == 4 => None, + // Otherwise `/**` is an outer block doc comment. + _ => Some(AttrStyle::Outer), + }, + _ => None, } } -pub fn strip_doc_comment_decoration(comment: Symbol) -> String { - let comment = &comment.as_str(); - +/// 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<String>) -> Vec<String> { let mut i = 0; @@ -126,26 +127,15 @@ pub fn strip_doc_comment_decoration(comment: Symbol) -> String { } } - // one-line comments lose their prefix - const ONELINERS: &[&str] = &["///!", "///", "//!", "//"]; - - for prefix in ONELINERS { - if comment.starts_with(*prefix) { - return (&comment[prefix.len()..]).to_string(); - } - } - - if comment.starts_with("/*") { - let lines = - comment[3..comment.len() - 2].lines().map(|s| s.to_string()).collect::<Vec<String>>(); - + let data = data.as_str(); + if data.contains('\n') { + let lines = data.lines().map(|s| s.to_string()).collect::<Vec<String>>(); let lines = vertical_trim(lines); let lines = horizontal_trim(lines); - - return lines.join("\n"); + lines.join("\n") + } else { + data.to_string() } - - panic!("not a doc-comment: {}", comment); } /// Returns `None` if the first `col` chars of `s` contain a non-whitespace char. @@ -203,7 +193,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { comments.push(Comment { - style: Isolated, + style: CommentStyle::Isolated, lines: vec![text[..shebang_len].to_string()], pos: start_bpos, }); @@ -219,23 +209,23 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme while let Some(next_newline) = &token_text[idx + 1..].find('\n') { idx = idx + 1 + next_newline; comments.push(Comment { - style: BlankLine, + style: CommentStyle::BlankLine, lines: vec![], pos: start_bpos + BytePos((pos + idx) as u32), }); } } } - rustc_lexer::TokenKind::BlockComment { terminated: _ } => { - if !is_block_doc_comment(token_text) { + rustc_lexer::TokenKind::BlockComment { terminated } => { + if block_doc_comment_style(token_text, terminated).is_none() { let code_to_the_right = match text[pos + token.len..].chars().next() { Some('\r' | '\n') => false, _ => true, }; let style = match (code_to_the_left, code_to_the_right) { - (_, true) => Mixed, - (false, false) => Isolated, - (true, false) => Trailing, + (_, true) => CommentStyle::Mixed, + (false, false) => CommentStyle::Isolated, + (true, false) => CommentStyle::Trailing, }; // Count the number of chars since the start of the line by rescanning. @@ -249,9 +239,13 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme } } rustc_lexer::TokenKind::LineComment => { - if !is_doc_comment(token_text) { + if line_doc_comment_style(token_text).is_none() { comments.push(Comment { - style: if code_to_the_left { Trailing } else { Isolated }, + style: if code_to_the_left { + CommentStyle::Trailing + } else { + CommentStyle::Isolated + }, lines: vec![token_text.to_string()], pos: start_bpos + BytePos(pos as u32), }) diff --git a/src/librustc_ast/util/comments/tests.rs b/src/librustc_ast/util/comments/tests.rs index f08011fe4f8..e95365d8337 100644 --- a/src/librustc_ast/util/comments/tests.rs +++ b/src/librustc_ast/util/comments/tests.rs @@ -2,10 +2,17 @@ use super::*; use crate::with_default_session_globals; #[test] +fn line_doc_comments() { + assert!(line_doc_comment_style("///").is_some()); + assert!(line_doc_comment_style("/// blah").is_some()); + assert!(line_doc_comment_style("////").is_none()); +} + +#[test] fn test_block_doc_comment_1() { with_default_session_globals(|| { - let comment = "/**\n * Test \n ** Test\n * Test\n*/"; - let stripped = strip_doc_comment_decoration(Symbol::intern(comment)); + 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"); }) } @@ -13,8 +20,8 @@ fn test_block_doc_comment_1() { #[test] fn test_block_doc_comment_2() { with_default_session_globals(|| { - let comment = "/**\n * Test\n * Test\n*/"; - let stripped = strip_doc_comment_decoration(Symbol::intern(comment)); + let comment = "\n * Test\n * Test\n"; + let stripped = beautify_doc_string(Symbol::intern(comment)); assert_eq!(stripped, " Test\n Test"); }) } @@ -22,37 +29,22 @@ fn test_block_doc_comment_2() { #[test] fn test_block_doc_comment_3() { with_default_session_globals(|| { - let comment = "/**\n let a: *i32;\n *a = 5;\n*/"; - let stripped = strip_doc_comment_decoration(Symbol::intern(comment)); + 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;"); }) } #[test] -fn test_block_doc_comment_4() { - with_default_session_globals(|| { - let comment = "/*******************\n test\n *********************/"; - let stripped = strip_doc_comment_decoration(Symbol::intern(comment)); - assert_eq!(stripped, " test"); - }) -} - -#[test] fn test_line_doc_comment() { with_default_session_globals(|| { - let stripped = strip_doc_comment_decoration(Symbol::intern("/// test")); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration(Symbol::intern("///! test")); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration(Symbol::intern("// test")); + let stripped = beautify_doc_string(Symbol::intern(" test")); assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration(Symbol::intern("// test")); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration(Symbol::intern("///test")); - assert_eq!(stripped, "test"); - let stripped = strip_doc_comment_decoration(Symbol::intern("///!test")); - assert_eq!(stripped, "test"); - let stripped = strip_doc_comment_decoration(Symbol::intern("//test")); + let stripped = beautify_doc_string(Symbol::intern("! test")); + assert_eq!(stripped, "! test"); + let stripped = beautify_doc_string(Symbol::intern("test")); assert_eq!(stripped, "test"); + let stripped = beautify_doc_string(Symbol::intern("!test")); + assert_eq!(stripped, "!test"); }) } diff --git a/src/librustc_ast/visit.rs b/src/librustc_ast/visit.rs index ccab46703df..2c3d1e97df9 100644 --- a/src/librustc_ast/visit.rs +++ b/src/librustc_ast/visit.rs @@ -880,7 +880,7 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { match attr.kind { AttrKind::Normal(ref item) => walk_mac_args(visitor, &item.args), - AttrKind::DocComment(_) => {} + AttrKind::DocComment(..) => {} } } diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index abd5df537db..f9e54903a66 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -1067,7 +1067,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .collect(); // Stop if there were any errors when lowering the register classes - if operands.len() != asm.operands.len() { + if operands.len() != asm.operands.len() || sess.asm_arch.is_none() { return hir::ExprKind::Err; } diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 9df7ad2a9ac..077a07c1bfa 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -981,7 +981,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { path: item.path.clone(), args: self.lower_mac_args(&item.args), }), - AttrKind::DocComment(comment) => AttrKind::DocComment(comment), + AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data), }; Attribute { kind, id: attr.id, style: attr.style, span: attr.span } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 4b228629ad7..9d9ca78de55 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -8,10 +8,11 @@ use rustc_ast::ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::attr; use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::util::classify; +use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; use rustc_ast::util::parser::{self, AssocOp, Fixity}; -use rustc_ast::util::{classify, comments}; use rustc_span::edition::Edition; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol}; @@ -50,17 +51,17 @@ impl PpAnn for NoAnn {} pub struct Comments<'a> { sm: &'a SourceMap, - comments: Vec<comments::Comment>, + comments: Vec<Comment>, current: usize, } impl<'a> Comments<'a> { pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> { - let comments = comments::gather_comments(sm, filename, input); + let comments = gather_comments(sm, filename, input); Comments { sm, comments, current: 0 } } - pub fn next(&self) -> Option<comments::Comment> { + pub fn next(&self) -> Option<Comment> { self.comments.get(self.current).cloned() } @@ -68,9 +69,9 @@ impl<'a> Comments<'a> { &mut self, span: rustc_span::Span, next_pos: Option<BytePos>, - ) -> Option<comments::Comment> { + ) -> Option<Comment> { if let Some(cmnt) = self.next() { - if cmnt.style != comments::Trailing { + if cmnt.style != CommentStyle::Trailing { return None; } let span_line = self.sm.lookup_char_pos(span.hi()); @@ -152,8 +153,8 @@ pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { // and also addresses some specific regressions described in #63896 and #73345. fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { if let TokenTree::Token(token) = prev { - if let token::DocComment(s) = token.kind { - return !s.as_str().starts_with("//"); + if let token::DocComment(comment_kind, ..) = token.kind { + return comment_kind != CommentKind::Line; } } match tt { @@ -194,6 +195,19 @@ fn binop_to_string(op: BinOpToken) -> &'static str { } } +fn doc_comment_to_string( + comment_kind: CommentKind, + attr_style: ast::AttrStyle, + data: Symbol, +) -> String { + match (comment_kind, attr_style) { + (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data), + (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data), + (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data), + (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data), + } +} + pub fn literal_to_string(lit: token::Lit) -> String { let token::Lit { kind, symbol, suffix } = lit; let mut out = match kind { @@ -271,7 +285,9 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>) token::Lifetime(s) => s.to_string(), /* Other */ - token::DocComment(s) => s.to_string(), + token::DocComment(comment_kind, attr_style, data) => { + doc_comment_to_string(comment_kind, attr_style, data) + } token::Eof => "<eof>".to_string(), token::Whitespace => " ".to_string(), token::Comment => "/* */".to_string(), @@ -447,9 +463,9 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere } } - fn print_comment(&mut self, cmnt: &comments::Comment) { + fn print_comment(&mut self, cmnt: &Comment) { match cmnt.style { - comments::Mixed => { + CommentStyle::Mixed => { if !self.is_beginning_of_line() { self.zerobreak(); } @@ -468,7 +484,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere } self.zerobreak() } - comments::Isolated => { + CommentStyle::Isolated => { self.hardbreak_if_not_bol(); for line in &cmnt.lines { // Don't print empty lines because they will end up as trailing @@ -479,7 +495,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere self.hardbreak(); } } - comments::Trailing => { + CommentStyle::Trailing => { if !self.is_beginning_of_line() { self.word(" "); } @@ -497,7 +513,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere self.end(); } } - comments::BlankLine => { + CommentStyle::BlankLine => { // We need to do at least one, possibly two hardbreaks. let twice = match self.last_token() { pp::Token::String(s) => ";" == s, @@ -516,7 +532,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere } } - fn next_comment(&mut self) -> Option<comments::Comment> { + fn next_comment(&mut self) -> Option<Comment> { self.comments().as_mut().and_then(|c| c.next()) } @@ -599,8 +615,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere self.print_attr_item(&item, attr.span); self.word("]"); } - ast::AttrKind::DocComment(comment) => { - self.word(comment.to_string()); + ast::AttrKind::DocComment(comment_kind, data) => { + self.word(doc_comment_to_string(comment_kind, attr.style, data)); self.hardbreak() } } diff --git a/src/librustc_error_codes/error_codes/E0746.md b/src/librustc_error_codes/error_codes/E0746.md index 305667e58f8..90755d47f67 100644 --- a/src/librustc_error_codes/error_codes/E0746.md +++ b/src/librustc_error_codes/error_codes/E0746.md @@ -1,4 +1,4 @@ -Return types cannot be `dyn Trait`s as they must be `Sized`. +An unboxed trait object was used as a return value. Erroneous code example: @@ -13,11 +13,13 @@ impl T for S { // Having the trait `T` as return type is invalid because // unboxed trait objects do not have a statically known size: -fn foo() -> dyn T { +fn foo() -> dyn T { // error! S(42) } ``` +Return types cannot be `dyn Trait`s as they must be `Sized`. + To avoid the error there are a couple of options. If there is a single type involved, you can use [`impl Trait`]: @@ -32,7 +34,7 @@ If there is a single type involved, you can use [`impl Trait`]: # } // The compiler will select `S(usize)` as the materialized return type of this // function, but callers will only know that the return type implements `T`. -fn foo() -> impl T { +fn foo() -> impl T { // ok! S(42) } ``` @@ -57,7 +59,7 @@ impl T for O { // This now returns a "trait object" and callers are only be able to access // associated items from `T`. -fn foo(x: bool) -> Box<dyn T> { +fn foo(x: bool) -> Box<dyn T> { // ok! if x { Box::new(S(42)) } else { diff --git a/src/librustc_error_codes/error_codes/E0747.md b/src/librustc_error_codes/error_codes/E0747.md index df1afbfef46..caf7e0fba07 100644 --- a/src/librustc_error_codes/error_codes/E0747.md +++ b/src/librustc_error_codes/error_codes/E0747.md @@ -1,4 +1,4 @@ -Generic arguments must be provided in the same order as the corresponding +Generic arguments were not provided in the same order as the corresponding generic parameters are declared. Erroneous code example: @@ -11,7 +11,7 @@ type X = S<(), 'static>; // error: the type argument is provided before the ``` The argument order should be changed to match the parameter declaration -order, as in the following. +order, as in the following: ``` struct S<'a, T>(&'a T); diff --git a/src/librustc_expand/parse/lexer/tests.rs b/src/librustc_expand/parse/lexer/tests.rs index b3775c78e73..0b51abf385f 100644 --- a/src/librustc_expand/parse/lexer/tests.rs +++ b/src/librustc_expand/parse/lexer/tests.rs @@ -1,5 +1,5 @@ -use rustc_ast::token::{self, Token, TokenKind}; -use rustc_ast::util::comments::is_doc_comment; +use rustc_ast::ast::AttrStyle; +use rustc_ast::token::{self, CommentKind, Token, TokenKind}; use rustc_ast::with_default_session_globals; use rustc_data_structures::sync::Lrc; use rustc_errors::{emitter::EmitterWriter, Handler}; @@ -224,13 +224,6 @@ fn literal_suffixes() { } #[test] -fn line_doc_comments() { - assert!(is_doc_comment("///")); - assert!(is_doc_comment("/// blah")); - assert!(!is_doc_comment("////")); -} - -#[test] fn nested_block_comments() { with_default_session_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); @@ -251,6 +244,9 @@ fn crlf_comments() { assert_eq!(comment.kind, token::Comment); assert_eq!((comment.span.lo(), comment.span.hi()), (BytePos(0), BytePos(7))); assert_eq!(lexer.next_token(), token::Whitespace); - assert_eq!(lexer.next_token(), token::DocComment(Symbol::intern("/// test"))); + assert_eq!( + lexer.next_token(), + token::DocComment(CommentKind::Line, AttrStyle::Outer, Symbol::intern(" test")) + ); }) } diff --git a/src/librustc_expand/parse/tests.rs b/src/librustc_expand/parse/tests.rs index fc9b9f2dab0..d6301c8a82e 100644 --- a/src/librustc_expand/parse/tests.rs +++ b/src/librustc_expand/parse/tests.rs @@ -244,20 +244,20 @@ fn crlf_doc_comments() { let source = "/// doc comment\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_1, source, &sess).unwrap().unwrap(); let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap(); - assert_eq!(doc.as_str(), "/// doc comment"); + assert_eq!(doc.as_str(), " doc comment"); let name_2 = FileName::Custom("crlf_source_2".to_string()); let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_2, source, &sess).unwrap().unwrap(); let docs = item.attrs.iter().filter_map(|at| at.doc_str()).collect::<Vec<_>>(); - let b: &[_] = &[Symbol::intern("/// doc comment"), Symbol::intern("/// line 2")]; + let b: &[_] = &[Symbol::intern(" doc comment"), Symbol::intern(" line 2")]; assert_eq!(&docs[..], b); let name_3 = FileName::Custom("clrf_source_3".to_string()); let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap(); let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap(); - assert_eq!(doc.as_str(), "/** doc comment\n * with CRLF */"); + assert_eq!(doc.as_str(), " doc comment\n * with CRLF "); }); } diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index 881d7b84b70..005db35da7a 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -3,7 +3,6 @@ use crate::base::ExtCtxt; use rustc_ast::ast; use rustc_ast::token; use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; -use rustc_ast::util::comments; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::Diagnostic; @@ -148,11 +147,9 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)> tt!(Punct::new('\'', true)) } Literal(lit) => tt!(Literal { lit }), - DocComment(c) => { - let style = comments::doc_comment_style(c); - let stripped = comments::strip_doc_comment_decoration(c); + DocComment(_, attr_style, data) => { let mut escaped = String::new(); - for ch in stripped.chars() { + for ch in data.as_str().chars() { escaped.extend(ch.escape_debug()); } let stream = vec![ @@ -169,7 +166,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)> span: DelimSpan::from_single(span), flatten: false, })); - if style == ast::AttrStyle::Inner { + if attr_style == ast::AttrStyle::Inner { stack.push(tt!(Punct::new('!', false))); } tt!(Punct::new('#', false)) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index d7c310a8b4c..7e42f219ce2 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -576,7 +576,7 @@ declare_features! ( /// Lazily evaluate constants. This allows constants to depend on type parameters. (active, lazy_normalization_consts, "1.46.0", Some(72219), None), - /// Alloc calling `transmute` in const fn + /// Allows calling `transmute` in const fn (active, const_fn_transmute, "1.46.0", Some(53605), None), // ------------------------------------------------------------------------- diff --git a/src/librustc_hir/def.rs b/src/librustc_hir/def.rs index af1860ca6bf..618f3e99c3f 100644 --- a/src/librustc_hir/def.rs +++ b/src/librustc_hir/def.rs @@ -150,7 +150,7 @@ impl DefKind { } } - pub fn matches_ns(&self, ns: Namespace) -> bool { + pub fn ns(&self) -> Option<Namespace> { match self { DefKind::Mod | DefKind::Struct @@ -163,7 +163,7 @@ impl DefKind { | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy - | DefKind::TyParam => ns == Namespace::TypeNS, + | DefKind::TyParam => Some(Namespace::TypeNS), DefKind::Fn | DefKind::Const @@ -171,9 +171,9 @@ impl DefKind { | DefKind::Static | DefKind::Ctor(..) | DefKind::AssocFn - | DefKind::AssocConst => ns == Namespace::ValueNS, + | DefKind::AssocConst => Some(Namespace::ValueNS), - DefKind::Macro(..) => ns == Namespace::MacroNS, + DefKind::Macro(..) => Some(Namespace::MacroNS), // Not namespaced. DefKind::AnonConst @@ -185,7 +185,7 @@ impl DefKind { | DefKind::Use | DefKind::ForeignMod | DefKind::GlobalAsm - | DefKind::Impl => false, + | DefKind::Impl => None, } } } @@ -453,7 +453,7 @@ impl<Id> Res<Id> { pub fn matches_ns(&self, ns: Namespace) -> bool { match self { - Res::Def(kind, ..) => kind.matches_ns(ns), + Res::Def(kind, ..) => kind.ns() == Some(ns), Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => ns == Namespace::TypeNS, Res::SelfCtor(..) | Res::Local(..) => ns == Namespace::ValueNS, Res::NonMacroAttr(..) => ns == Namespace::MacroNS, diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index d451d9a22a4..29d615b04a3 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -39,8 +39,8 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { .collect_and_partition_mono_items(LOCAL_CRATE) .1 .iter() - .map(|cgu| cgu.name()) - .collect::<BTreeSet<Symbol>>(); + .map(|cgu| cgu.name().to_string()) + .collect::<BTreeSet<String>>(); let ams = AssertModuleSource { tcx, available_cgus }; @@ -52,7 +52,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { struct AssertModuleSource<'tcx> { tcx: TyCtxt<'tcx>, - available_cgus: BTreeSet<Symbol>, + available_cgus: BTreeSet<String>, } impl AssertModuleSource<'tcx> { @@ -121,12 +121,11 @@ impl AssertModuleSource<'tcx> { debug!("mapping '{}' to cgu name '{}'", self.field(attr, sym::module), cgu_name); - if !self.available_cgus.contains(&cgu_name) { + if !self.available_cgus.contains(&*cgu_name.as_str()) { self.tcx.sess.span_err( attr.span, &format!( - "no module named `{}` (mangled: {}). \ - Available modules: {}", + "no module named `{}` (mangled: {}). Available modules: {}", user_path, cgu_name, self.available_cgus diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index e51862be9a8..2897480c32b 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -37,7 +37,7 @@ macro_rules! provide { def_id_arg: ty::query::query_keys::$name<$lt>, ) -> ty::query::query_values::$name<$lt> { let _prof_timer = - $tcx.prof.generic_activity("metadata_decode_entry"); + $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name))); #[allow(unused_variables)] let ($def_id, $other) = def_id_arg.into_args(); diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index 27f50c240db..81f7474962c 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -85,6 +85,8 @@ impl FlagComputation { } &ty::Generator(_, ref substs, _) => { + self.add_flags(TypeFlags::MAY_POLYMORPHIZE); + let substs = substs.as_generator(); let should_remove_further_specializable = !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); @@ -107,6 +109,8 @@ impl FlagComputation { } &ty::Closure(_, substs) => { + self.add_flags(TypeFlags::MAY_POLYMORPHIZE); + let substs = substs.as_closure(); let should_remove_further_specializable = !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); @@ -192,6 +196,8 @@ impl FlagComputation { } &ty::FnDef(_, substs) => { + self.add_flags(TypeFlags::MAY_POLYMORPHIZE); + self.add_substs(substs); } diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs index 492f8ce9ef1..87434f3f267 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/src/librustc_middle/ty/fold.rs @@ -150,6 +150,12 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) } + /// Does this value contain closures, generators or functions such that it may require + /// polymorphization? + fn may_polymorphize(&self) -> bool { + self.has_type_flags(TypeFlags::MAY_POLYMORPHIZE) + } + /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`. fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool { pub struct Visitor<F>(F); diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index 289a9db7327..cf876db26bc 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -474,26 +474,7 @@ impl<'tcx> Instance<'tcx> { } if let InstanceDef::Item(def) = self.def { - let unused = tcx.unused_generic_params(def.did); - - if unused.is_empty() { - // Exit early if every parameter was used. - return self; - } - - debug!("polymorphize: unused={:?}", unused); - let polymorphized_substs = - InternalSubsts::for_item(tcx, def.did, |param, _| match param.kind { - // If parameter is a const or type parameter.. - ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if - // ..and is within range and unused.. - unused.contains(param.index).unwrap_or(false) => - // ..then use the identity for this parameter. - tcx.mk_param_from_def(param), - // Otherwise, use the parameter as before. - _ => self.substs[param.index as usize], - }); - + let polymorphized_substs = polymorphize(tcx, def.did, self.substs); debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); Self { def: self.def, substs: polymorphized_substs } } else { @@ -502,6 +483,82 @@ impl<'tcx> Instance<'tcx> { } } +fn polymorphize<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, +) -> SubstsRef<'tcx> { + debug!("polymorphize({:?}, {:?})", def_id, substs); + let unused = tcx.unused_generic_params(def_id); + debug!("polymorphize: unused={:?}", unused); + + struct PolymorphizationFolder<'tcx> { + tcx: TyCtxt<'tcx>, + }; + + impl ty::TypeFolder<'tcx> for PolymorphizationFolder<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + debug!("fold_ty: ty={:?}", ty); + match ty.kind { + ty::Closure(def_id, substs) => { + let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + if substs == polymorphized_substs { + ty + } else { + self.tcx.mk_closure(def_id, polymorphized_substs) + } + } + ty::FnDef(def_id, substs) => { + let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + if substs == polymorphized_substs { + ty + } else { + self.tcx.mk_fn_def(def_id, polymorphized_substs) + } + } + ty::Generator(def_id, substs, movability) => { + let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + if substs == polymorphized_substs { + ty + } else { + self.tcx.mk_generator(def_id, polymorphized_substs, movability) + } + } + _ => ty.super_fold_with(self), + } + } + } + + InternalSubsts::for_item(tcx, def_id, |param, _| { + let is_unused = unused.contains(param.index).unwrap_or(false); + debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused); + match param.kind { + // If parameter is a const or type parameter.. + ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if + // ..and is within range and unused.. + unused.contains(param.index).unwrap_or(false) => + // ..then use the identity for this parameter. + tcx.mk_param_from_def(param), + + // If the parameter does not contain any closures or generators, then use the + // substitution directly. + _ if !substs.may_polymorphize() => substs[param.index as usize], + + // Otherwise, use the substitution after polymorphizing. + _ => { + let arg = substs[param.index as usize]; + let polymorphized_arg = arg.fold_with(&mut PolymorphizationFolder { tcx }); + debug!("polymorphize: arg={:?} polymorphized_arg={:?}", arg, polymorphized_arg); + ty::GenericArg::from(polymorphized_arg) + } + } + }) +} + fn needs_fn_once_adapter_shim( actual_closure_kind: ty::ClosureKind, trait_closure_kind: ty::ClosureKind, diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index bd45f866abc..c82fb2712c2 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -575,6 +575,10 @@ bitflags! { /// 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; + + /// Does this value contain closures, generators or functions such that it may require + /// polymorphization? + const MAY_POLYMORPHIZE = 1 << 18; } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 8e2fd709d66..db0b0415728 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -34,7 +34,9 @@ use crate::interpret::{ }; use crate::transform::{MirPass, MirSource}; -/// The maximum number of bytes that we'll allocate space for a return value. +/// The maximum number of bytes that we'll allocate space for a local or the return value. +/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just +/// Severely regress performance. const MAX_ALLOC_LIMIT: u64 = 1024; /// Macro for machine-specific `InterpError` without allocation. @@ -155,14 +157,19 @@ struct ConstPropMachine<'mir, 'tcx> { written_only_inside_own_block_locals: FxHashSet<Local>, /// Locals that need to be cleared after every block terminates. only_propagate_inside_block_locals: BitSet<Local>, + can_const_prop: IndexVec<Local, ConstPropMode>, } impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> { - fn new(only_propagate_inside_block_locals: BitSet<Local>) -> Self { + fn new( + only_propagate_inside_block_locals: BitSet<Local>, + can_const_prop: IndexVec<Local, ConstPropMode>, + ) -> Self { Self { stack: Vec::new(), written_only_inside_own_block_locals: Default::default(), only_propagate_inside_block_locals, + can_const_prop, } } } @@ -241,6 +248,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> local: Local, ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>> { + if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { + throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") + } if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) { ecx.machine.written_only_inside_own_block_locals.insert(local); } @@ -285,7 +295,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> struct ConstPropagator<'mir, 'tcx> { ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, tcx: TyCtxt<'tcx>, - can_const_prop: IndexVec<Local, ConstPropMode>, param_env: ParamEnv<'tcx>, // FIXME(eddyb) avoid cloning these two fields more than once, // by accessing them through `ecx` instead. @@ -331,7 +340,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let param_env = tcx.param_env_reveal_all_normalized(def_id); let span = tcx.def_span(def_id); - let can_const_prop = CanConstProp::check(body); + // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts + // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in + // `layout_of` query invocations. + let can_const_prop = CanConstProp::check(tcx, param_env, body); let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len()); for (l, mode) in can_const_prop.iter_enumerated() { if *mode == ConstPropMode::OnlyInsideOwnBlock { @@ -342,7 +354,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { tcx, span, param_env, - ConstPropMachine::new(only_propagate_inside_block_locals), + ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop), (), ); @@ -368,7 +380,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ecx, tcx, param_env, - can_const_prop, // FIXME(eddyb) avoid cloning these two fields more than once, // by accessing them through `ecx` instead. source_scopes: body.source_scopes.clone(), @@ -612,15 +623,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn const_prop( &mut self, rvalue: &Rvalue<'tcx>, - place_layout: TyAndLayout<'tcx>, source_info: SourceInfo, place: Place<'tcx>, ) -> Option<()> { - // #66397: Don't try to eval into large places as that can cause an OOM - if place_layout.size >= Size::from_bytes(MAX_ALLOC_LIMIT) { - return None; - } - // Perform any special handling for specific Rvalue types. // Generally, checks here fall into one of two categories: // 1. Additional checking to provide useful lints to the user @@ -893,7 +898,11 @@ struct CanConstProp { impl CanConstProp { /// Returns true if `local` can be propagated - fn check(body: &Body<'_>) -> IndexVec<Local, ConstPropMode> { + fn check( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + body: &Body<'tcx>, + ) -> IndexVec<Local, ConstPropMode> { let mut cpv = CanConstProp { can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls), found_assignment: BitSet::new_empty(body.local_decls.len()), @@ -903,6 +912,16 @@ impl CanConstProp { ), }; for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { + let ty = body.local_decls[local].ty; + match tcx.layout_of(param_env.and(ty)) { + Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} + // Either the layout fails to compute, then we can't use this local anyway + // or the local is too large, then we don't want to. + _ => { + *val = ConstPropMode::NoPropagation; + continue; + } + } // Cannot use args at all // Cannot use locals because if x < y { y - x } else { x - y } would // lint for x != y @@ -1018,61 +1037,52 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { let source_info = statement.source_info; self.source_info = Some(source_info); if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind { - let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty; - if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { - let can_const_prop = self.can_const_prop[place.local]; - if let Some(()) = self.const_prop(rval, place_layout, source_info, place) { - // This will return None if the above `const_prop` invocation only "wrote" a - // type whose creation requires no write. E.g. a generator whose initial state - // consists solely of uninitialized memory (so it doesn't capture any locals). - if let Some(value) = self.get_const(place) { - if self.should_const_prop(value) { - trace!("replacing {:?} with {:?}", rval, value); - self.replace_with_const(rval, value, source_info); - if can_const_prop == ConstPropMode::FullConstProp - || can_const_prop == ConstPropMode::OnlyInsideOwnBlock - { - trace!("propagated into {:?}", place); - } + let can_const_prop = self.ecx.machine.can_const_prop[place.local]; + if let Some(()) = self.const_prop(rval, source_info, place) { + // This will return None if the above `const_prop` invocation only "wrote" a + // type whose creation requires no write. E.g. a generator whose initial state + // consists solely of uninitialized memory (so it doesn't capture any locals). + if let Some(value) = self.get_const(place) { + if self.should_const_prop(value) { + trace!("replacing {:?} with {:?}", rval, value); + self.replace_with_const(rval, value, source_info); + if can_const_prop == ConstPropMode::FullConstProp + || can_const_prop == ConstPropMode::OnlyInsideOwnBlock + { + trace!("propagated into {:?}", place); } } - match can_const_prop { - ConstPropMode::OnlyInsideOwnBlock => { - trace!( - "found local restricted to its block. \ + } + match can_const_prop { + ConstPropMode::OnlyInsideOwnBlock => { + trace!( + "found local restricted to its block. \ Will remove it from const-prop after block is finished. Local: {:?}", - place.local - ); - } - ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => { - trace!("can't propagate into {:?}", place); - if place.local != RETURN_PLACE { - Self::remove_const(&mut self.ecx, place.local); - } + place.local + ); + } + ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => { + trace!("can't propagate into {:?}", place); + if place.local != RETURN_PLACE { + Self::remove_const(&mut self.ecx, place.local); } - ConstPropMode::FullConstProp => {} } - } else { - // Const prop failed, so erase the destination, ensuring that whatever happens - // from here on, does not know about the previous value. - // This is important in case we have - // ```rust - // let mut x = 42; - // x = SOME_MUTABLE_STATIC; - // // x must now be undefined - // ``` - // FIXME: we overzealously erase the entire local, because that's easier to - // implement. - trace!( - "propagation into {:?} failed. - Nuking the entire site from orbit, it's the only way to be sure", - place, - ); - Self::remove_const(&mut self.ecx, place.local); + ConstPropMode::FullConstProp => {} } } else { + // Const prop failed, so erase the destination, ensuring that whatever happens + // from here on, does not know about the previous value. + // This is important in case we have + // ```rust + // let mut x = 42; + // x = SOME_MUTABLE_STATIC; + // // x must now be undefined + // ``` + // FIXME: we overzealously erase the entire local, because that's easier to + // implement. trace!( - "cannot propagate into {:?}, because the type of the local is generic.", + "propagation into {:?} failed. + Nuking the entire site from orbit, it's the only way to be sure", place, ); Self::remove_const(&mut self.ecx, place.local); diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index 2b0e637c74e..c3a79660eb9 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -1,4 +1,4 @@ -use rustc_ast::token::{self, Token, TokenKind}; +use rustc_ast::token::{self, CommentKind, Token, TokenKind}; use rustc_ast::util::comments; use rustc_data_structures::sync::Lrc; use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError}; @@ -170,22 +170,20 @@ impl<'a> StringReader<'a> { match token { rustc_lexer::TokenKind::LineComment => { let string = self.str_from(start); - // comments with only more "/"s are not doc comments - if comments::is_line_doc_comment(string) { + if let Some(attr_style) = comments::line_doc_comment_style(string) { self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment"); - token::DocComment(Symbol::intern(string)) + // Opening delimiter of the length 3 is not included into the symbol. + token::DocComment(CommentKind::Line, attr_style, Symbol::intern(&string[3..])) } else { token::Comment } } rustc_lexer::TokenKind::BlockComment { terminated } => { let string = self.str_from(start); - // block comments starting with "/**" or "/*!" are doc-comments - // but comments with only "*"s between two "/"s are not - let is_doc_comment = comments::is_block_doc_comment(string); + let attr_style = comments::block_doc_comment_style(string, terminated); if !terminated { - let msg = if is_doc_comment { + let msg = if attr_style.is_some() { "unterminated block doc-comment" } else { "unterminated block comment" @@ -202,9 +200,15 @@ impl<'a> StringReader<'a> { FatalError.raise(); } - if is_doc_comment { + if let Some(attr_style) = attr_style { self.forbid_bare_cr(start, string, "bare CR not allowed in block doc-comment"); - token::DocComment(Symbol::intern(string)) + // Opening delimiter of the length 3 and closing delimiter of the length 2 + // are not included into the symbol. + token::DocComment( + CommentKind::Block, + attr_style, + Symbol::intern(&string[3..string.len() - if terminated { 2 } else { 0 }]), + ) } else { token::Comment } diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 3319ca44da4..723e4333790 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -486,7 +486,9 @@ fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool { (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b, - (&DocComment(a), &DocComment(b)) | (&Shebang(a), &Shebang(b)) => a == b, + (&DocComment(a1, a2, a3), &DocComment(b1, b2, b3)) => a1 == b1 && a2 == b2 && a3 == b3, + + (&Shebang(a), &Shebang(b)) => a == b, (&Literal(a), &Literal(b)) => a == b, @@ -524,7 +526,7 @@ fn prepend_attrs( let item = match attr.kind { ast::AttrKind::Normal(ref item) => item, - ast::AttrKind::DocComment(_) => { + ast::AttrKind::DocComment(..) => { let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); builder.push(stream); continue; diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index 8b67f4743c6..b6a8ee71beb 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -2,10 +2,9 @@ use super::{Parser, PathStyle}; use rustc_ast::ast; use rustc_ast::attr; use rustc_ast::token::{self, Nonterminal}; -use rustc_ast::util::comments; use rustc_ast_pretty::pprust; use rustc_errors::{error_code, PResult}; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; use log::debug; @@ -47,8 +46,8 @@ impl<'a> Parser<'a> { let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; attrs.push(attr); just_parsed_doc_comment = false; - } else if let token::DocComment(s) = self.token.kind { - let attr = self.mk_doc_comment(s); + } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind { + let attr = attr::mk_doc_comment(comment_kind, attr_style, data, self.token.span); if attr.style != ast::AttrStyle::Outer { self.sess .span_diagnostic @@ -73,10 +72,6 @@ impl<'a> Parser<'a> { Ok(attrs) } - fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute { - attr::mk_doc_comment(comments::doc_comment_style(s), s, self.token.span) - } - /// Matches `attribute = # ! [ meta_item ]`. /// /// If `permit_inner` is `true`, then a leading `!` indicates an inner @@ -184,9 +179,9 @@ impl<'a> Parser<'a> { let attr = self.parse_attribute(true)?; assert_eq!(attr.style, ast::AttrStyle::Inner); attrs.push(attr); - } else if let token::DocComment(s) = self.token.kind { + } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind { // We need to get the position of this token before we bump. - let attr = self.mk_doc_comment(s); + let attr = attr::mk_doc_comment(comment_kind, attr_style, data, self.token.span); if attr.style == ast::AttrStyle::Inner { attrs.push(attr); self.bump(); diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 5e9411327ca..2854356ab0f 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1419,7 +1419,7 @@ impl<'a> Parser<'a> { } pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) { - if let token::DocComment(_) = self.token.kind { + if let token::DocComment(..) = self.token.kind { self.struct_span_err( self.token.span, "documentation comments cannot be applied to a function parameter's type", diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 5923a185dcf..10d214e52ab 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -610,7 +610,7 @@ impl<'a> Parser<'a> { /// Recover on a doc comment before `}`. fn recover_doc_comment_before_brace(&mut self) -> bool { - if let token::DocComment(_) = self.token.kind { + if let token::DocComment(..) = self.token.kind { if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) { struct_span_err!( self.diagnostic(), @@ -1231,7 +1231,7 @@ impl<'a> Parser<'a> { self.bump(); } token::CloseDelim(token::Brace) => {} - token::DocComment(_) => { + token::DocComment(..) => { let previous_span = self.prev_token.span; let mut err = self.span_fatal_err(self.token.span, Error::UselessDocComment); self.bump(); // consume the doc comment diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 2509a979221..ededfc43669 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -22,7 +22,6 @@ use rustc_ast::ast::{ use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint}; -use rustc_ast::util::comments::{doc_comment_style, strip_doc_comment_decoration}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_session::parse::ParseSess; @@ -209,18 +208,18 @@ impl TokenCursor { } fn next_desugared(&mut self) -> Token { - let (name, sp) = match self.next() { - Token { kind: token::DocComment(name), span } => (name, span), + let (data, attr_style, sp) = match self.next() { + Token { kind: token::DocComment(_, attr_style, data), span } => { + (data, attr_style, span) + } tok => return tok, }; - let stripped = strip_doc_comment_decoration(name); - // Searches for the occurrences of `"#*` and returns the minimum number of `#`s // required to wrap the text. let mut num_of_hashes = 0; let mut count = 0; - for ch in stripped.chars() { + for ch in data.as_str().chars() { count = match ch { '"' => 1, '#' if count > 0 => count + 1, @@ -236,10 +235,7 @@ impl TokenCursor { [ TokenTree::token(token::Ident(sym::doc, false), sp), TokenTree::token(token::Eq, sp), - TokenTree::token( - TokenKind::lit(token::StrRaw(num_of_hashes), Symbol::intern(&stripped), None), - sp, - ), + TokenTree::token(TokenKind::lit(token::StrRaw(num_of_hashes), data, None), sp), ] .iter() .cloned() @@ -251,7 +247,7 @@ impl TokenCursor { TokenCursorFrame::new( delim_span, token::NoDelim, - &if doc_comment_style(name) == AttrStyle::Inner { + &if attr_style == AttrStyle::Inner { [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body] .iter() .cloned() diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 81e29047dc5..a6b5b0ff301 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1075,10 +1075,9 @@ impl<'a> Resolver<'a> { ) = binding.kind { let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor"); - if let Some(fields) = self.field_names.get(&def_id) { - let first_field = fields.first().expect("empty field list in the map"); - return Some(fields.iter().fold(first_field.span, |acc, field| acc.to(field.span))); - } + let fields = self.field_names.get(&def_id)?; + let first_field = fields.first()?; // Handle `struct Foo()` + return Some(fields.iter().fold(first_field.span, |acc, field| acc.to(field.span))); } None } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 8e379a35100..d854835a024 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -10,7 +10,7 @@ mod span_utils; mod sig; use rustc_ast::ast::{self}; -use rustc_ast::util::comments::strip_doc_comment_decoration; +use rustc_ast::util::comments::beautify_doc_string; use rustc_ast_pretty::pprust::attribute_to_string; use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res}; @@ -822,11 +822,8 @@ impl<'tcx> SaveContext<'tcx> { for attr in attrs { if let Some(val) = attr.doc_str() { - if attr.is_doc_comment() { - result.push_str(&strip_doc_comment_decoration(val)); - } else { - result.push_str(&val.as_str()); - } + // FIXME: Should save-analysis beautify doc strings itself or leave it to users? + result.push_str(&beautify_doc_string(val)); result.push('\n'); } else if attr.check_name(sym::doc) { if let Some(meta_list) = attr.meta_item_list() { diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index 75e11619924..dbb64e57178 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -440,7 +440,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation ); - // `previous_stack` stores a `TraitObligatiom`, while `obligation` is + // `previous_stack` stores a `TraitObligation`, while `obligation` is // a `PredicateObligation`. These are distinct types, so we can't // use any `Option` combinator method that would force them to be // the same. diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index b261df4073d..50eca75d7ca 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -10,7 +10,7 @@ use std::{slice, vec}; use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::attr; -use rustc_ast::util::comments::strip_doc_comment_decoration; +use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::Res; @@ -506,10 +506,11 @@ impl Attributes { .iter() .filter_map(|attr| { if let Some(value) = attr.doc_str() { - let (value, mk_fragment): (_, fn(_, _, _) -> _) = if attr.is_doc_comment() { - (strip_doc_comment_decoration(value), DocFragment::SugaredDoc) + let value = beautify_doc_string(value); + let mk_fragment: fn(_, _, _) -> _ = if attr.is_doc_comment() { + DocFragment::SugaredDoc } else { - (value.to_string(), DocFragment::RawDoc) + DocFragment::RawDoc }; let line = doc_line; diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index adef4c83224..c22538f21f6 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -610,6 +610,9 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef), Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum), Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait), + Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => { + (cx.tcx.parent(i).unwrap(), TypeKind::Trait) + } Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct), Res::Def(DefKind::Union, i) => (i, TypeKind::Union), Res::Def(DefKind::Mod, i) => (i, TypeKind::Module), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index bf7a43236e0..f84486347af 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -17,6 +17,7 @@ use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; +use std::cell::Cell; use std::ops::Range; use crate::clean::*; @@ -62,11 +63,15 @@ struct LinkCollector<'a, 'tcx> { cx: &'a DocContext<'tcx>, // NOTE: this may not necessarily be a module in the current crate mod_ids: Vec<DefId>, + /// This is used to store the kind of associated items, + /// 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<Option<DefKind>>, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn new(cx: &'a DocContext<'tcx>) -> Self { - LinkCollector { cx, mod_ids: Vec::new() } + LinkCollector { cx, mod_ids: Vec::new(), kind_side_channel: Cell::new(None) } } fn variant_field( @@ -174,7 +179,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn resolve( &self, path_str: &str, - disambiguator: Option<&str>, + disambiguator: Option<Disambiguator>, ns: Namespace, current_item: &Option<String>, parent_id: Option<DefId>, @@ -214,7 +219,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Res::Def(DefKind::Mod, _) => { // This resolved to a module, but if we were passed `type@`, // we want primitive types to take precedence instead. - if disambiguator == Some("type") { + if disambiguator == Some(Disambiguator::Namespace(Namespace::TypeNS)) { if let Some(prim) = is_primitive(path_str, ns) { if extra_fragment.is_some() { return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); @@ -347,6 +352,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { AnchorFailure::AssocConstant })) } else { + // HACK(jynelson): `clean` expects the type, not the associated item. + // but the disambiguator logic expects the associated item. + // Store the kind in a side channel so that only the disambiguator logic looks at it. + self.kind_side_channel.replace(Some(item.kind.as_def_kind())); Ok((ty_res, Some(format!("{}.{}", out, item_name)))) } } else { @@ -415,7 +424,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { AnchorFailure::Method })) } else { - Ok((ty_res, Some(format!("{}.{}", kind, item_name)))) + let res = Res::Def(item.kind.as_def_kind(), item.def_id); + Ok((res, Some(format!("{}.{}", kind, item_name)))) } } else { self.variant_field(path_str, current_item, module_id) @@ -574,46 +584,14 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }; let resolved_self; let mut path_str; + let disambiguator; let (res, fragment) = { - let mut kind = None; - let mut disambiguator = None; - path_str = if let Some(prefix) = - ["struct@", "enum@", "type@", "trait@", "union@", "module@", "mod@"] - .iter() - .find(|p| link.starts_with(**p)) - { - kind = Some(TypeNS); - disambiguator = Some(&prefix[..prefix.len() - 1]); - link.trim_start_matches(prefix) - } else if let Some(prefix) = - ["const@", "static@", "value@", "function@", "fn@", "method@"] - .iter() - .find(|p| link.starts_with(**p)) - { - kind = Some(ValueNS); - disambiguator = Some(&prefix[..prefix.len() - 1]); - link.trim_start_matches(prefix) - } else if link.ends_with("!()") { - kind = Some(MacroNS); - link.trim_end_matches("!()") - } else if link.ends_with("()") { - kind = Some(ValueNS); - disambiguator = Some("fn"); - link.trim_end_matches("()") - } else if link.starts_with("macro@") { - kind = Some(MacroNS); - disambiguator = Some("macro"); - link.trim_start_matches("macro@") - } else if link.starts_with("derive@") { - kind = Some(MacroNS); - disambiguator = Some("derive"); - link.trim_start_matches("derive@") - } else if link.ends_with('!') { - kind = Some(MacroNS); - disambiguator = Some("macro"); - link.trim_end_matches('!') + path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { + disambiguator = Some(d); + path } else { - &link[..] + disambiguator = None; + &link } .trim(); @@ -646,7 +624,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } - match kind { + match disambiguator.map(Disambiguator::ns) { Some(ns @ ValueNS) => { match self.resolve( path_str, @@ -789,6 +767,42 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } else { debug!("intra-doc link to {} resolved to {:?}", path_str, res); + // Disallow e.g. linking to enums with `struct@` + if let Res::Def(kind, id) = res { + debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); + match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) { + | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) + // NOTE: this allows 'method' to mean both normal functions and associated functions + // This can't cause ambiguity because both are in the same namespace. + | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn))) + // These are namespaces; allow anything in the namespace to match + | (_, Some(Disambiguator::Namespace(_))) + // If no disambiguator given, allow anything + | (_, None) + // All of these are valid, so do nothing + => {} + (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} + (_, Some(Disambiguator::Kind(expected))) => { + // The resolved item did not match the disambiguator; give a better error than 'not found' + let msg = format!("incompatible link kind for `{}`", path_str); + report_diagnostic(cx, &msg, &item, &dox, link_range, |diag, sp| { + // HACK(jynelson): by looking at the source I saw the DefId we pass + // for `expected.descr()` doesn't matter, since it's not a crate + let note = format!("this link resolved to {} {}, which is not {} {}", kind.article(), kind.descr(id), expected.article(), expected.descr(id)); + let suggestion = Disambiguator::display_for(kind, path_str); + let help_msg = format!("to link to the {}, use its disambiguator", kind.descr(id)); + diag.note(¬e); + if let Some(sp) = sp { + diag.span_suggestion(sp, &help_msg, suggestion, Applicability::MaybeIncorrect); + } else { + diag.help(&format!("{}: {}", help_msg, suggestion)); + } + }); + continue; + } + } + } + // item can be non-local e.g. when using #[doc(primitive = "pointer")] if let Some((src_id, dst_id)) = res .opt_def_id() @@ -837,6 +851,94 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum Disambiguator { + Kind(DefKind), + Namespace(Namespace), +} + +impl Disambiguator { + /// (disambiguator, path_str) + fn from_str(link: &str) -> Result<(Self, &str), ()> { + use Disambiguator::{Kind, Namespace as NS}; + + let find_suffix = || { + let suffixes = [ + ("!()", DefKind::Macro(MacroKind::Bang)), + ("()", DefKind::Fn), + ("!", DefKind::Macro(MacroKind::Bang)), + ]; + for &(suffix, kind) in &suffixes { + if link.ends_with(suffix) { + return Ok((Kind(kind), link.trim_end_matches(suffix))); + } + } + Err(()) + }; + + if let Some(idx) = link.find('@') { + let (prefix, rest) = link.split_at(idx); + let d = match prefix { + "struct" => Kind(DefKind::Struct), + "enum" => Kind(DefKind::Enum), + "trait" => Kind(DefKind::Trait), + "union" => Kind(DefKind::Union), + "module" | "mod" => Kind(DefKind::Mod), + "const" | "constant" => Kind(DefKind::Const), + "static" => Kind(DefKind::Static), + "function" | "fn" | "method" => Kind(DefKind::Fn), + "derive" => Kind(DefKind::Macro(MacroKind::Derive)), + "type" => NS(Namespace::TypeNS), + "value" => NS(Namespace::ValueNS), + "macro" => NS(Namespace::MacroNS), + _ => return find_suffix(), + }; + Ok((d, &rest[1..])) + } else { + find_suffix() + } + } + + fn display_for(kind: DefKind, path_str: &str) -> String { + if kind == DefKind::Macro(MacroKind::Bang) { + return format!("{}!", path_str); + } else if kind == DefKind::Fn || kind == DefKind::AssocFn { + return format!("{}()", path_str); + } + let prefix = match kind { + DefKind::Struct => "struct", + DefKind::Enum => "enum", + DefKind::Trait => "trait", + DefKind::Union => "union", + DefKind::Mod => "mod", + DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => { + "const" + } + DefKind::Static => "static", + DefKind::Macro(MacroKind::Derive) => "derive", + // Now handle things that don't have a specific disambiguator + _ => match kind + .ns() + .expect("tried to calculate a disambiguator for a def without a namespace?") + { + Namespace::TypeNS => "type", + Namespace::ValueNS => "value", + Namespace::MacroNS => "macro", + }, + }; + format!("{}@{}", prefix, path_str) + } + + fn ns(self) -> Namespace { + match self { + Self::Namespace(n) => n, + Self::Kind(k) => { + k.ns().expect("only DefKinds with a valid namespace can be disambiguators") + } + } + } +} + /// Reports a diagnostic for an intra-doc link. /// /// If no link range is provided, or the source span of the link cannot be determined, the span of diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index b86a105ff76..969f5a2eaf1 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -943,7 +943,12 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with // anything else, this will combine them for us. if let Some(doc) = attrs.collapsed_doc_value() { - self.collector.set_position(attrs.span.unwrap_or(DUMMY_SP)); + // Use the outermost invocation, so that doctest names come from where the docs were written. + let span = attrs + .span + .map(|span| span.ctxt().outer_expn().expansion_cause().unwrap_or(span)) + .unwrap_or(DUMMY_SP); + self.collector.set_position(span); markdown::find_testable_code( &doc, self.collector, diff --git a/src/test/codegen-units/polymorphization/pr-75255.rs b/src/test/codegen-units/polymorphization/pr-75255.rs new file mode 100644 index 00000000000..af47b440640 --- /dev/null +++ b/src/test/codegen-units/polymorphization/pr-75255.rs @@ -0,0 +1,52 @@ +// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1 +// ignore-tidy-linelength + +#![crate_type = "rlib"] + +// Test that only one copy of `Iter::map` and `iter::repeat` are generated. + +fn unused<T>() -> u64 { + 42 +} + +fn foo<T>() { + let x = [1, 2, 3, std::mem::size_of::<T>()]; + x.iter().map(|_| ()); +} + +//~ MONO_ITEM fn core::iter[0]::adapters[0]::{{impl}}[29]::new[0]<core::slice[0]::Iter[0]<usize>, pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.0[External] +//~ MONO_ITEM fn core::iter[0]::traits[0]::iterator[0]::Iterator[0]::map[0]<core::slice[0]::Iter[0]<usize>, (), pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.1[Internal] + +fn bar<T>() { + std::iter::repeat(unused::<T>); +} + +//~ MONO_ITEM fn core::iter[0]::sources[0]::repeat[0]<fn() -> u64> @@ pr_75255-cgu.1[Internal] + +pub fn dispatch() { + foo::<String>(); + foo::<Vec<String>>(); + + bar::<String>(); + bar::<Vec<String>>(); +} + +// These are all the items that aren't relevant to the test. +//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::mem[0]::size_of[0]<usize> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::add[0]<usize> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::is_null[0]<usize> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::offset[0]<usize> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_add[0]<u8> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_offset[0]<u8> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::non_null[0]::{{impl}}[3]::new_unchecked[0]<usize> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::null[0]<u8> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::as_ptr[0]<usize> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::iter[0]<usize> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::len[0]<usize> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::dispatch[0] @@ pr_75255-cgu.1[External] +//~ MONO_ITEM fn pr_75255::foo[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::foo[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::bar[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::bar[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal] diff --git a/src/test/debuginfo/function-arguments-naked.rs b/src/test/debuginfo/function-arguments-naked.rs index e88a99b322e..5f3a1eb44e4 100644 --- a/src/test/debuginfo/function-arguments-naked.rs +++ b/src/test/debuginfo/function-arguments-naked.rs @@ -3,6 +3,9 @@ // We have to ignore android because of this issue: // https://github.com/rust-lang/rust/issues/74847 // ignore-android +// +// We need to use inline assembly, so just use one platform +// only-x86_64 // compile-flags:-g @@ -24,6 +27,7 @@ // lldb-command:continue +#![feature(asm)] #![feature(naked_functions)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -33,8 +37,6 @@ fn main() { } #[naked] -fn naked(x: usize, y: usize) { - zzz(); // #break +extern "C" fn naked(x: usize, y: usize) { + unsafe { asm!("ret"); } // #break } - -fn zzz() { () } diff --git a/src/test/debuginfo/pretty-std-collections-hash.rs b/src/test/debuginfo/pretty-std-collections-hash.rs index 361b300f28c..e8f52deabd8 100644 --- a/src/test/debuginfo/pretty-std-collections-hash.rs +++ b/src/test/debuginfo/pretty-std-collections-hash.rs @@ -9,35 +9,35 @@ // cdb-check:hash_set,d [...] : { size=15 } [Type: [...]::HashSet<u64, [...]>] // cdb-check: [size] : 15 [Type: [...]] // cdb-check: [capacity] : [...] -// cdb-check: [[...]] [...] : 0 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 0 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 1 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 1 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 2 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 2 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 3 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 3 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 4 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 4 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 5 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 5 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 6 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 6 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 7 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 7 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 8 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 8 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 9 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 9 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 10 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 10 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 11 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 11 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 12 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 12 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 13 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 13 [Type: u64] // cdb-command: dx hash_set,d -// cdb-check: [[...]] [...] : 14 [Type: unsigned __int64] +// cdb-check: [[...]] [...] : 14 [Type: u64] // cdb-command: dx hash_map,d // cdb-check:hash_map,d [...] : { size=15 } [Type: [...]::HashMap<u64, u64, [...]>] diff --git a/src/test/mir-opt/const-promotion-extern-static.rs b/src/test/mir-opt/const-promotion-extern-static.rs index e63309a9bd2..9c30e040031 100644 --- a/src/test/mir-opt/const-promotion-extern-static.rs +++ b/src/test/mir-opt/const-promotion-extern-static.rs @@ -1,7 +1,7 @@ +// ignore-endian-big extern "C" { static X: i32; } - static Y: i32 = 42; // EMIT_MIR const_promotion_extern_static.BAR.PromoteTemps.diff diff --git a/src/test/mir-opt/const_allocation.rs b/src/test/mir-opt/const_allocation.rs index bb1c48e8e3c..b0fcb86fcee 100644 --- a/src/test/mir-opt/const_allocation.rs +++ b/src/test/mir-opt/const_allocation.rs @@ -1,5 +1,5 @@ +// ignore-endian-big // EMIT_MIR_FOR_EACH_BIT_WIDTH - static FOO: &[(Option<i32>, &[&str])] = &[(None, &[]), (None, &["foo", "bar"]), (Some(42), &["meh", "mop", "möp"])]; diff --git a/src/test/mir-opt/const_allocation2.rs b/src/test/mir-opt/const_allocation2.rs index 56839255c0e..30afedffb39 100644 --- a/src/test/mir-opt/const_allocation2.rs +++ b/src/test/mir-opt/const_allocation2.rs @@ -1,5 +1,5 @@ +// ignore-endian-big // EMIT_MIR_FOR_EACH_BIT_WIDTH - // EMIT_MIR const_allocation2.main.ConstProp.after.mir fn main() { FOO; diff --git a/src/test/mir-opt/const_allocation3.rs b/src/test/mir-opt/const_allocation3.rs index 2ce289aea3f..ddeb32ab9a5 100644 --- a/src/test/mir-opt/const_allocation3.rs +++ b/src/test/mir-opt/const_allocation3.rs @@ -1,5 +1,5 @@ +// ignore-endian-big // EMIT_MIR_FOR_EACH_BIT_WIDTH - // EMIT_MIR const_allocation3.main.ConstProp.after.mir fn main() { FOO; diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit new file mode 100644 index 00000000000..721766f9849 --- /dev/null +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit @@ -0,0 +1,85 @@ +- // MIR for `main` before ConstProp ++ // MIR for `main` after ConstProp + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/large_array_index.rs:4:11: 4:11 + let _1: u8; // in scope 0 at $DIR/large_array_index.rs:6:9: 6:10 + let mut _2: [u8; 5000]; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + let _3: usize; // in scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + let mut _4: usize; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + let mut _5: bool; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + scope 1 { + debug x => _1; // in scope 1 at $DIR/large_array_index.rs:6:9: 6:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/large_array_index.rs:6:9: 6:10 + StorageLive(_2); // scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + _2 = [const 0_u8; 5000]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + // ty::Const + // + ty: u8 + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/large_array_index.rs:6:18: 6:22 + // + literal: Const { ty: u8, val: Value(Scalar(0x00)) } + StorageLive(_3); // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000002)) + // mir::Constant + // + span: $DIR/large_array_index.rs:6:30: 6:31 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) } + _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00001388)) + // mir::Constant + // + span: $DIR/large_array_index.rs:6:17: 6:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x00001388)) } +- _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ // ty::Const ++ // + ty: bool ++ // + val: Value(Scalar(0x01)) ++ // mir::Constant ++ // + span: $DIR/large_array_index.rs:6:17: 6:32 ++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } ++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ // ty::Const ++ // + ty: bool ++ // + val: Value(Scalar(0x01)) ++ // mir::Constant ++ // + span: $DIR/large_array_index.rs:6:17: 6:32 ++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } ++ // ty::Const ++ // + ty: usize ++ // + val: Value(Scalar(0x00001388)) ++ // mir::Constant ++ // + span: $DIR/large_array_index.rs:6:17: 6:32 ++ // + literal: Const { ty: usize, val: Value(Scalar(0x00001388)) } ++ // ty::Const ++ // + ty: usize ++ // + val: Value(Scalar(0x00000002)) ++ // mir::Constant ++ // + span: $DIR/large_array_index.rs:6:17: 6:32 ++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) } + } + + bb1: { + _1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 + StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 + _0 = const (); // scope 0 at $DIR/large_array_index.rs:4:11: 7:2 + // ty::Const + // + ty: () + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/large_array_index.rs:4:11: 7:2 + // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } + StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:7:1: 7:2 + return; // scope 0 at $DIR/large_array_index.rs:7:2: 7:2 + } + } + diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit new file mode 100644 index 00000000000..eae2ce6671c --- /dev/null +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit @@ -0,0 +1,85 @@ +- // MIR for `main` before ConstProp ++ // MIR for `main` after ConstProp + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/large_array_index.rs:4:11: 4:11 + let _1: u8; // in scope 0 at $DIR/large_array_index.rs:6:9: 6:10 + let mut _2: [u8; 5000]; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + let _3: usize; // in scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + let mut _4: usize; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + let mut _5: bool; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + scope 1 { + debug x => _1; // in scope 1 at $DIR/large_array_index.rs:6:9: 6:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/large_array_index.rs:6:9: 6:10 + StorageLive(_2); // scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + _2 = [const 0_u8; 5000]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:29 + // ty::Const + // + ty: u8 + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/large_array_index.rs:6:18: 6:22 + // + literal: Const { ty: u8, val: Value(Scalar(0x00)) } + StorageLive(_3); // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000002)) + // mir::Constant + // + span: $DIR/large_array_index.rs:6:30: 6:31 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) } + _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000001388)) + // mir::Constant + // + span: $DIR/large_array_index.rs:6:17: 6:32 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000001388)) } +- _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ // ty::Const ++ // + ty: bool ++ // + val: Value(Scalar(0x01)) ++ // mir::Constant ++ // + span: $DIR/large_array_index.rs:6:17: 6:32 ++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } ++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ // ty::Const ++ // + ty: bool ++ // + val: Value(Scalar(0x01)) ++ // mir::Constant ++ // + span: $DIR/large_array_index.rs:6:17: 6:32 ++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } ++ // ty::Const ++ // + ty: usize ++ // + val: Value(Scalar(0x0000000000001388)) ++ // mir::Constant ++ // + span: $DIR/large_array_index.rs:6:17: 6:32 ++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000001388)) } ++ // ty::Const ++ // + ty: usize ++ // + val: Value(Scalar(0x0000000000000002)) ++ // mir::Constant ++ // + span: $DIR/large_array_index.rs:6:17: 6:32 ++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) } + } + + bb1: { + _1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 + StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33 + _0 = const (); // scope 0 at $DIR/large_array_index.rs:4:11: 7:2 + // ty::Const + // + ty: () + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/large_array_index.rs:4:11: 7:2 + // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } + StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:7:1: 7:2 + return; // scope 0 at $DIR/large_array_index.rs:7:2: 7:2 + } + } + diff --git a/src/test/mir-opt/const_prop/large_array_index.rs b/src/test/mir-opt/const_prop/large_array_index.rs new file mode 100644 index 00000000000..48d134376db --- /dev/null +++ b/src/test/mir-opt/const_prop/large_array_index.rs @@ -0,0 +1,7 @@ +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR large_array_index.main.ConstProp.diff +fn main() { + // check that we don't propagate this, because it's too large + let x: u8 = [0_u8; 5000][2]; +} diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff index e78bc31b774..6e2ee0957ab 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff @@ -23,15 +23,13 @@ // + ty: i32 // + val: Value(Scalar(0x0000002a)) // mir::Constant -- // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20 -+ // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25 + // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20 // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) } // ty::Const // + ty: i32 // + val: Value(Scalar(0x0000002b)) // mir::Constant -- // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24 -+ // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25 + // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24 // + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) } StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10 _2 = &mut _1; // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:13: 6:19 diff --git a/src/test/mir-opt/inline/inline-into-box-place.rs b/src/test/mir-opt/inline/inline-into-box-place.rs index 30c9a5d6b8f..57298605b18 100644 --- a/src/test/mir-opt/inline/inline-into-box-place.rs +++ b/src/test/mir-opt/inline/inline-into-box-place.rs @@ -1,8 +1,8 @@ +// ignore-endian-big // ignore-wasm32-bare compiled with panic=abort by default // compile-flags: -Z mir-opt-level=3 // EMIT_MIR_FOR_EACH_BIT_WIDTH #![feature(box_syntax)] - // EMIT_MIR inline_into_box_place.main.Inline.diff fn main() { let _x: Box<Vec<u32>> = box Vec::new(); diff --git a/src/test/rustdoc-ui/auxiliary/extern_macros.rs b/src/test/rustdoc-ui/auxiliary/extern_macros.rs new file mode 100644 index 00000000000..ee1fec4c5c2 --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/extern_macros.rs @@ -0,0 +1,7 @@ +#[macro_export] +macro_rules! attrs_on_struct { + ( $( #[$attr:meta] )* ) => { + $( #[$attr] )* + pub struct ExpandedStruct; + } +} diff --git a/src/test/rustdoc-ui/doctest-output.rs b/src/test/rustdoc-ui/doctest-output.rs index f812263c252..e0e1e061ac7 100644 --- a/src/test/rustdoc-ui/doctest-output.rs +++ b/src/test/rustdoc-ui/doctest-output.rs @@ -1,3 +1,5 @@ +// edition:2018 +// aux-build:extern_macros.rs // compile-flags:--test --test-args=--test-threads=1 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // check-pass @@ -6,6 +8,10 @@ //! assert_eq!(1 + 1, 2); //! ``` +extern crate extern_macros as macros; + +use macros::attrs_on_struct; + pub mod foo { /// ``` @@ -13,3 +19,9 @@ pub mod foo { /// ``` pub fn bar() {} } + +attrs_on_struct! { + /// ``` + /// assert!(true); + /// ``` +} diff --git a/src/test/rustdoc-ui/doctest-output.stdout b/src/test/rustdoc-ui/doctest-output.stdout index 9a55bf50196..c72bd91d1dd 100644 --- a/src/test/rustdoc-ui/doctest-output.stdout +++ b/src/test/rustdoc-ui/doctest-output.stdout @@ -1,7 +1,8 @@ -running 2 tests -test $DIR/doctest-output.rs - (line 5) ... ok -test $DIR/doctest-output.rs - foo::bar (line 11) ... ok +running 3 tests +test $DIR/doctest-output.rs - (line 7) ... ok +test $DIR/doctest-output.rs - ExpandedStruct (line 23) ... ok +test $DIR/doctest-output.rs - foo::bar (line 17) ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs new file mode 100644 index 00000000000..1a7a2fce7a3 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs @@ -0,0 +1,68 @@ +#![deny(broken_intra_doc_links)] +//~^ NOTE lint level is defined +pub enum S {} + +macro_rules! m { + () => {}; +} + +static s: usize = 0; +const c: usize = 0; + +trait T {} + +/// Link to [struct@S] +//~^ ERROR incompatible link kind for `S` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [mod@S] +//~^ ERROR incompatible link kind for `S` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [union@S] +//~^ ERROR incompatible link kind for `S` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [trait@S] +//~^ ERROR incompatible link kind for `S` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [struct@T] +//~^ ERROR incompatible link kind for `T` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [derive@m] +//~^ ERROR incompatible link kind for `m` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [const@s] +//~^ ERROR incompatible link kind for `s` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [static@c] +//~^ ERROR incompatible link kind for `c` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [fn@c] +//~^ ERROR incompatible link kind for `c` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [c()] +//~^ ERROR incompatible link kind for `c` +//~| NOTE this link resolved +//~| HELP use its disambiguator + +/// Link to [const@f] +//~^ ERROR incompatible link kind for `f` +//~| NOTE this link resolved +//~| HELP use its disambiguator +pub fn f() {} diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr new file mode 100644 index 00000000000..9edf838f9d8 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr @@ -0,0 +1,95 @@ +error: incompatible link kind for `S` + --> $DIR/intra-links-disambiguator-mismatch.rs:14:14 + | +LL | /// Link to [struct@S] + | ^^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | +note: the lint level is defined here + --> $DIR/intra-links-disambiguator-mismatch.rs:1:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: this link resolved to an enum, which is not a struct + +error: incompatible link kind for `S` + --> $DIR/intra-links-disambiguator-mismatch.rs:19:14 + | +LL | /// Link to [mod@S] + | ^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | + = note: this link resolved to an enum, which is not a module + +error: incompatible link kind for `S` + --> $DIR/intra-links-disambiguator-mismatch.rs:24:14 + | +LL | /// Link to [union@S] + | ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | + = note: this link resolved to an enum, which is not a union + +error: incompatible link kind for `S` + --> $DIR/intra-links-disambiguator-mismatch.rs:29:14 + | +LL | /// Link to [trait@S] + | ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | + = note: this link resolved to an enum, which is not a trait + +error: incompatible link kind for `T` + --> $DIR/intra-links-disambiguator-mismatch.rs:34:14 + | +LL | /// Link to [struct@T] + | ^^^^^^^^ help: to link to the trait, use its disambiguator: `trait@T` + | + = note: this link resolved to a trait, which is not a struct + +error: incompatible link kind for `m` + --> $DIR/intra-links-disambiguator-mismatch.rs:39:14 + | +LL | /// Link to [derive@m] + | ^^^^^^^^ help: to link to the macro, use its disambiguator: `m!` + | + = note: this link resolved to a macro, which is not a derive macro + +error: incompatible link kind for `s` + --> $DIR/intra-links-disambiguator-mismatch.rs:44:14 + | +LL | /// Link to [const@s] + | ^^^^^^^ help: to link to the static, use its disambiguator: `static@s` + | + = note: this link resolved to a static, which is not a constant + +error: incompatible link kind for `c` + --> $DIR/intra-links-disambiguator-mismatch.rs:49:14 + | +LL | /// Link to [static@c] + | ^^^^^^^^ help: to link to the constant, use its disambiguator: `const@c` + | + = note: this link resolved to a constant, which is not a static + +error: incompatible link kind for `c` + --> $DIR/intra-links-disambiguator-mismatch.rs:54:14 + | +LL | /// Link to [fn@c] + | ^^^^ help: to link to the constant, use its disambiguator: `const@c` + | + = note: this link resolved to a constant, which is not a function + +error: incompatible link kind for `c` + --> $DIR/intra-links-disambiguator-mismatch.rs:59:14 + | +LL | /// Link to [c()] + | ^^^ help: to link to the constant, use its disambiguator: `const@c` + | + = note: this link resolved to a constant, which is not a function + +error: incompatible link kind for `f` + --> $DIR/intra-links-disambiguator-mismatch.rs:64:14 + | +LL | /// Link to [const@f] + | ^^^^^^^ help: to link to the function, use its disambiguator: `f()` + | + = note: this link resolved to a function, which is not a constant + +error: aborting due to 11 previous errors + diff --git a/src/test/rustdoc/intra-link-trait-item.rs b/src/test/rustdoc/intra-link-trait-item.rs new file mode 100644 index 00000000000..54270414c9d --- /dev/null +++ b/src/test/rustdoc/intra-link-trait-item.rs @@ -0,0 +1,12 @@ +// ignore-tidy-linelength +#![deny(broken_intra_doc_links)] + +/// Link to [S::assoc_fn()] +/// Link to [Default::default()] +// @has intra_link_trait_item/struct.S.html '//*[@href="../intra_link_trait_item/struct.S.html#method.assoc_fn"]' 'S::assoc_fn()' +// @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()' +pub struct S; + +impl S { + pub fn assoc_fn() {} +} diff --git a/src/test/ui/asm/bad-arch.rs b/src/test/ui/asm/bad-arch.rs new file mode 100644 index 00000000000..eeeeb17dd4f --- /dev/null +++ b/src/test/ui/asm/bad-arch.rs @@ -0,0 +1,18 @@ +// compile-flags: --target wasm32-unknown-unknown + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[lang = "sized"] +trait Sized {} + +fn main() { + unsafe { + asm!(""); + //~^ ERROR asm! is unsupported on this target + } +} diff --git a/src/test/ui/asm/bad-arch.stderr b/src/test/ui/asm/bad-arch.stderr new file mode 100644 index 00000000000..daccc46c6e3 --- /dev/null +++ b/src/test/ui/asm/bad-arch.stderr @@ -0,0 +1,8 @@ +error[E0472]: asm! is unsupported on this target + --> $DIR/bad-arch.rs:15:9 + | +LL | asm!(""); + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/btreemap/btreemap_into_iterator_lifetime.rs b/src/test/ui/btreemap/btreemap_into_iterator_lifetime.rs new file mode 100644 index 00000000000..fda825bc65e --- /dev/null +++ b/src/test/ui/btreemap/btreemap_into_iterator_lifetime.rs @@ -0,0 +1,23 @@ +// check-pass + +use std::collections::{BTreeMap, HashMap}; + +trait Map +where + for<'a> &'a Self: IntoIterator<Item = (&'a Self::Key, &'a Self::Value)>, +{ + type Key; + type Value; +} + +impl<K, V> Map for HashMap<K, V> { + type Key = K; + type Value = V; +} + +impl<K, V> Map for BTreeMap<K, V> { + type Key = K; + type Value = V; +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-asm.rs b/src/test/ui/feature-gates/feature-gate-asm.rs index 753e924f004..59f04372fff 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.rs +++ b/src/test/ui/feature-gates/feature-gate-asm.rs @@ -1,4 +1,4 @@ -// ignore-emscripten +// only-x86_64 fn main() { unsafe { diff --git a/src/test/ui/feature-gates/feature-gate-asm2.rs b/src/test/ui/feature-gates/feature-gate-asm2.rs index e9349acb643..aa63aff1c5e 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.rs +++ b/src/test/ui/feature-gates/feature-gate-asm2.rs @@ -1,4 +1,4 @@ -// ignore-emscripten +// only-x86_64 fn main() { unsafe { diff --git a/src/test/ui/panics/issue-47429-short-backtraces.rs b/src/test/ui/panics/issue-47429-short-backtraces.rs new file mode 100644 index 00000000000..1e8c38cc342 --- /dev/null +++ b/src/test/ui/panics/issue-47429-short-backtraces.rs @@ -0,0 +1,18 @@ +// Regression test for #47429: short backtraces were not terminating correctly + +// compile-flags: -O +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=1 + +// ignore-msvc see #62897 and `backtrace-debuginfo.rs` test +// ignore-android FIXME #17520 +// ignore-cloudabi spawning processes is not supported +// ignore-openbsd no support for libbacktrace without filename +// ignore-wasm no panic or subprocess support +// ignore-emscripten no panic or subprocess support +// ignore-sgx no subprocess support + +fn main() { + panic!() +} diff --git a/src/test/ui/panics/issue-47429-short-backtraces.run.stderr b/src/test/ui/panics/issue-47429-short-backtraces.run.stderr new file mode 100644 index 00000000000..99ee26fe55e --- /dev/null +++ b/src/test/ui/panics/issue-47429-short-backtraces.run.stderr @@ -0,0 +1,5 @@ +thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:17:5 +stack backtrace: + 0: std::panicking::begin_panic + 1: issue_47429_short_backtraces::main +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/src/test/ui/polymorphization/closure_in_upvar/fn.rs b/src/test/ui/polymorphization/closure_in_upvar/fn.rs new file mode 100644 index 00000000000..b0b39dbd3df --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/fn.rs @@ -0,0 +1,29 @@ +// build-pass +// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 + +fn foo(f: impl Fn()) { + let x = |_: ()| (); + + // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to + // `x` that will differ for each instantiation despite polymorphisation of the varying + // argument. + let y = || x(()); + + // Consider `f` used in `foo`. + f(); + // Use `y` so that it is visited in monomorphisation collection. + y(); +} + +fn entry_a() { + foo(|| ()); +} + +fn entry_b() { + foo(|| ()); +} + +fn main() { + entry_a(); + entry_b(); +} diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs b/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs new file mode 100644 index 00000000000..ba75f6c5a10 --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs @@ -0,0 +1,34 @@ +// build-pass +// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 + +fn foo(f: impl Fn()) { + // Mutate an upvar from `x` so that it implements `FnMut`. + let mut outer = 3; + let mut x = |_: ()| { + outer = 4; + () + }; + + // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to + // `x` that will differ for each instantiation despite polymorphisation of the varying + // argument. + let mut y = || x(()); + + // Consider `f` used in `foo`. + f(); + // Use `y` so that it is visited in monomorphisation collection. + y(); +} + +fn entry_a() { + foo(|| ()); +} + +fn entry_b() { + foo(|| ()); +} + +fn main() { + entry_a(); + entry_b(); +} diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs b/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs new file mode 100644 index 00000000000..e9761ad0bcb --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs @@ -0,0 +1,34 @@ +// build-pass +// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 + +fn foo(f: impl Fn()) { + // Move a non-copy type into `x` so that it implements `FnOnce`. + let outer = Vec::<u32>::new(); + let x = move |_: ()| { + let inner = outer; + () + }; + + // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to + // `x` that will differ for each instantiation despite polymorphisation of the varying + // argument. + let y = || x(()); + + // Consider `f` used in `foo`. + f(); + // Use `y` so that it is visited in monomorphisation collection. + y(); +} + +fn entry_a() { + foo(|| ()); +} + +fn entry_b() { + foo(|| ()); +} + +fn main() { + entry_a(); + entry_b(); +} diff --git a/src/test/ui/polymorphization/closure_in_upvar/other.rs b/src/test/ui/polymorphization/closure_in_upvar/other.rs new file mode 100644 index 00000000000..7614aa83fcd --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/other.rs @@ -0,0 +1,38 @@ +// build-pass +// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 + +fn y_uses_f(f: impl Fn()) { + let x = |_: ()| (); + + let y = || { + f(); + x(()); + }; + + f(); + y(); +} + +fn x_uses_f(f: impl Fn()) { + let x = |_: ()| { f(); }; + + let y = || x(()); + + f(); + y(); +} + +fn entry_a() { + x_uses_f(|| ()); + y_uses_f(|| ()); +} + +fn entry_b() { + x_uses_f(|| ()); + y_uses_f(|| ()); +} + +fn main() { + entry_a(); + entry_b(); +} diff --git a/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.rs b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.rs new file mode 100644 index 00000000000..4601a3d4741 --- /dev/null +++ b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.rs @@ -0,0 +1,10 @@ +// Regression test for issue #75062 +// Tests that we don't ICE on a privacy error for a fieldless tuple struct. + +mod foo { + struct Bar(); +} + +fn main() { + foo::Bar(); //~ ERROR tuple struct +} diff --git a/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.stderr b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.stderr new file mode 100644 index 00000000000..14a12003e2d --- /dev/null +++ b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.stderr @@ -0,0 +1,15 @@ +error[E0603]: tuple struct `Bar` is private + --> $DIR/issue-75062-fieldless-tuple-struct.rs:9:10 + | +LL | foo::Bar(); + | ^^^ private tuple struct + | +note: the tuple struct `Bar` is defined here + --> $DIR/issue-75062-fieldless-tuple-struct.rs:5:5 + | +LL | struct Bar(); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/ui/proc-macro/doc-comment-preserved.rs b/src/test/ui/proc-macro/doc-comment-preserved.rs new file mode 100644 index 00000000000..c2724ae1806 --- /dev/null +++ b/src/test/ui/proc-macro/doc-comment-preserved.rs @@ -0,0 +1,24 @@ +// check-pass +// aux-build:test-macros.rs + +// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`. +// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)" +// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)" + +#[macro_use] +extern crate test_macros; + +print_bang! { + +/** +******* +* DOC * +* DOC * +* DOC * +******* +*/ +pub struct S; + +} + +fn main() {} diff --git a/src/test/ui/proc-macro/doc-comment-preserved.stdout b/src/test/ui/proc-macro/doc-comment-preserved.stdout new file mode 100644 index 00000000000..f7904536a76 --- /dev/null +++ b/src/test/ui/proc-macro/doc-comment-preserved.stdout @@ -0,0 +1,54 @@ +PRINT-BANG INPUT (DISPLAY): /** +******* +* DOC * +* DOC * +* DOC * +******* +*/ + pub struct S ; +PRINT-BANG RE-COLLECTED (DISPLAY): #[doc = "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n"] pub struct S ; +PRINT-BANG INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: #0 bytes(LO..HI), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "doc", + span: #0 bytes(LO..HI), + }, + Punct { + ch: '=', + spacing: Alone, + span: #0 bytes(LO..HI), + }, + Literal { + kind: Str, + symbol: "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n", + suffix: None, + span: #0 bytes(LO..HI), + }, + ], + span: #0 bytes(LO..HI), + }, + Ident { + ident: "pub", + span: #0 bytes(LO..HI), + }, + Ident { + ident: "struct", + span: #0 bytes(LO..HI), + }, + Ident { + ident: "S", + span: #0 bytes(LO..HI), + }, + Punct { + ch: ';', + spacing: Alone, + span: #0 bytes(LO..HI), + }, +] diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr index be55890c08c..7f197a238e5 100644 --- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr +++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr @@ -1,7 +1,7 @@ -error[E0391]: cycle detected when computing layout of `std::option::Option<S>` +error[E0391]: cycle detected when computing layout of `S` | - = note: ...which requires computing layout of `S`... - = note: ...which again requires computing layout of `std::option::Option<S>`, completing the cycle + = note: ...which requires computing layout of `std::option::Option<S>`... + = note: ...which again requires computing layout of `S`, completing the cycle note: cycle used when optimizing MIR for `main` --> $DIR/issue-26548-recursion-via-normalize.rs:15:1 | diff --git a/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs b/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs index a323bd9e82b..8c436841b44 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs @@ -2,6 +2,7 @@ #![allow(non_camel_case_types)] // ignore-emscripten +// ignore-endian-big behavior of simd_bitmask is endian-specific // Test that the simd_bitmask intrinsic produces correct results. diff --git a/src/test/ui/simd/simd-intrinsic-generic-select.rs b/src/test/ui/simd/simd-intrinsic-generic-select.rs index 22bda4fc9d9..dc9ec5d2760 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-select.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-select.rs @@ -2,10 +2,7 @@ #![allow(non_camel_case_types)] // ignore-emscripten -// ignore-mips behavior of simd_select_bitmask is endian-specific -// ignore-mips64 behavior of simd_select_bitmask is endian-specific -// ignore-powerpc behavior of simd_select_bitmask is endian-specific -// ignore-powerpc64 behavior of simd_select_bitmask is endian-specific +// ignore-endian-big behavior of simd_select_bitmask is endian-specific // Test that the simd_select intrinsics produces correct results. diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index e87c33d1b09..6ce36fd2360 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -2,6 +2,7 @@ use crate::utils::{implements_trait, is_entrypoint_fn, is_type_diagnostic_item, use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{AttrKind, Attribute}; +use rustc_ast::token::CommentKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -249,7 +250,7 @@ fn lint_for_missing_headers<'tcx>( } } -/// Cleanup documentation decoration (`///` and such). +/// Cleanup documentation decoration. /// /// We can't use `rustc_ast::attr::AttributeMethods::with_desugared_doc` or /// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we @@ -257,54 +258,45 @@ fn lint_for_missing_headers<'tcx>( /// the spans but this function is inspired from the later. #[allow(clippy::cast_possible_truncation)] #[must_use] -pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(usize, Span)>) { +pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) { // one-line comments lose their prefix - const ONELINERS: &[&str] = &["///!", "///", "//!", "//"]; - for prefix in ONELINERS { - if comment.starts_with(*prefix) { - let doc = &comment[prefix.len()..]; - let mut doc = doc.to_owned(); - doc.push('\n'); - return ( - doc.to_owned(), - vec![(doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32)))], - ); - } + if comment_kind == CommentKind::Line { + let mut doc = doc.to_owned(); + doc.push('\n'); + let len = doc.len(); + // +3 skips the opening delimiter + return (doc, vec![(len, span.with_lo(span.lo() + BytePos(3)))]); } - if comment.starts_with("/*") { - let doc = &comment[3..comment.len() - 2]; - let mut sizes = vec![]; - let mut contains_initial_stars = false; - for line in doc.lines() { - let offset = line.as_ptr() as usize - comment.as_ptr() as usize; - debug_assert_eq!(offset as u32 as usize, offset); - contains_initial_stars |= line.trim_start().starts_with('*'); - // +1 for the newline - sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(offset as u32)))); - } - if !contains_initial_stars { - return (doc.to_string(), sizes); - } - // remove the initial '*'s if any - let mut no_stars = String::with_capacity(doc.len()); - for line in doc.lines() { - let mut chars = line.chars(); - while let Some(c) = chars.next() { - if c.is_whitespace() { - no_stars.push(c); - } else { - no_stars.push(if c == '*' { ' ' } else { c }); - break; - } + let mut sizes = vec![]; + let mut contains_initial_stars = false; + for line in doc.lines() { + let offset = line.as_ptr() as usize - doc.as_ptr() as usize; + debug_assert_eq!(offset as u32 as usize, offset); + contains_initial_stars |= line.trim_start().starts_with('*'); + // +1 adds the newline, +3 skips the opening delimiter + sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(3 + offset as u32)))); + } + if !contains_initial_stars { + return (doc.to_string(), sizes); + } + // remove the initial '*'s if any + let mut no_stars = String::with_capacity(doc.len()); + for line in doc.lines() { + let mut chars = line.chars(); + while let Some(c) = chars.next() { + if c.is_whitespace() { + no_stars.push(c); + } else { + no_stars.push(if c == '*' { ' ' } else { c }); + break; } - no_stars.push_str(chars.as_str()); - no_stars.push('\n'); } - return (no_stars, sizes); + no_stars.push_str(chars.as_str()); + no_stars.push('\n'); } - panic!("not a doc-comment: {}", comment); + (no_stars, sizes) } #[derive(Copy, Clone)] @@ -318,9 +310,8 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs let mut spans = vec![]; for attr in attrs { - if let AttrKind::DocComment(ref comment) = attr.kind { - let comment = comment.to_string(); - let (comment, current_spans) = strip_doc_comment_decoration(&comment, attr.span); + if let AttrKind::DocComment(comment_kind, comment) = attr.kind { + let (comment, current_spans) = strip_doc_comment_decoration(&comment.as_str(), comment_kind, attr.span); spans.extend_from_slice(¤t_spans); doc.push_str(&comment); } else if attr.has_name(sym!(doc)) { diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs index 7b673e15b76..74ccd9235de 100644 --- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs @@ -60,13 +60,14 @@ declare_lint_pass!(TabsInDocComments => [TABS_IN_DOC_COMMENTS]); impl TabsInDocComments { fn warn_if_tabs_in_doc(cx: &EarlyContext<'_>, attr: &ast::Attribute) { - if let ast::AttrKind::DocComment(comment) = attr.kind { + if let ast::AttrKind::DocComment(_, comment) = attr.kind { let comment = comment.as_str(); for (lo, hi) in get_chunks_of_tabs(&comment) { + // +3 skips the opening delimiter let new_span = Span::new( - attr.span.lo() + BytePos(lo), - attr.span.lo() + BytePos(hi), + attr.span.lo() + BytePos(3 + lo), + attr.span.lo() + BytePos(3 + hi), attr.span.ctxt(), ); span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index 58c1103da9f..ad02bc5fd8e 100755 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -506,7 +506,7 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { use AttrKind::*; l.style == r.style && match (&l.kind, &r.kind) { - (DocComment(l), DocComment(r)) => l == r, + (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, (Normal(l), Normal(r)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args), _ => false, } diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index ac5f0d0a39e..2b3f9be2dfb 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -1,23 +1,3 @@ -error: this operation will panic at runtime - --> $DIR/indexing_slicing_index.rs:11:5 - | -LL | x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. - | ^^^^ index out of bounds: the len is 4 but the index is 4 - | - = note: `#[deny(unconditional_panic)]` on by default - -error: this operation will panic at runtime - --> $DIR/indexing_slicing_index.rs:12:5 - | -LL | x[1 << 3]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. - | ^^^^^^^^^ index out of bounds: the len is 4 but the index is 8 - -error: this operation will panic at runtime - --> $DIR/indexing_slicing_index.rs:27:5 - | -LL | x[N]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. - | ^^^^ index out of bounds: the len is 4 but the index is 15 - error: indexing may panic. --> $DIR/indexing_slicing_index.rs:10:5 | @@ -75,5 +55,5 @@ LL | v[M]; | = help: Consider using `.get(n)` or `.get_mut(n)` instead -error: aborting due to 10 previous errors +error: aborting due to 7 previous errors diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 9269a63b41a..848bd3a43e8 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -169,7 +169,7 @@ impl fmt::Display for Debugger { } /// Configuration for compiletest -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct Config { /// `true` to to overwrite stderr/stdout files instead of complaining about changes in output. pub bless: bool, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 047fbe9da14..edbb8372633 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -827,6 +827,7 @@ impl Config { name == util::get_pointer_width(&self.target) || // pointer width name == self.stage_id.split('-').next().unwrap() || // stage (self.target != self.host && name == "cross-compile") || + (name == "endian-big" && util::is_big_endian(&self.target)) || (self.remote_test_client.is_some() && name == "remote") || match self.compare_mode { Some(CompareMode::Nll) => name == "compare-mode-nll", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 940e16720f6..7f49cb913b1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1885,7 +1885,8 @@ impl<'test> TestCx<'test> { emit_metadata: EmitMetadata, allow_unused: AllowUnused, ) -> Command { - let is_rustdoc = self.is_rustdoc(); + let is_aux = input_file.components().map(|c| c.as_os_str()).any(|c| c == "auxiliary"); + let is_rustdoc = self.is_rustdoc() && !is_aux; let mut rustc = if !is_rustdoc { Command::new(&self.config.rustc_path) } else { @@ -3246,8 +3247,19 @@ impl<'test> TestCx<'test> { } fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String { - let before = self.get_mir_dump_dir().join(before); - let after = self.get_mir_dump_dir().join(after); + let to_full_path = |path: PathBuf| { + let full = self.get_mir_dump_dir().join(&path); + if !full.exists() { + panic!( + "the mir dump file for {} does not exist (requested in {})", + path.display(), + self.testpaths.file.display(), + ); + } + full + }; + let before = to_full_path(before); + let after = to_full_path(after); debug!("comparing the contents of: {} with {}", before.display(), after.display()); let before = fs::read_to_string(before).unwrap(); let after = fs::read_to_string(after).unwrap(); @@ -3573,6 +3585,7 @@ impl ProcRes { } } +#[derive(Debug)] enum TargetLocation { ThisFile(PathBuf), ThisDirectory(PathBuf), diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 0437ff8c944..ddd7941b114 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -99,6 +99,20 @@ pub const MSAN_SUPPORTED_TARGETS: &'static [&'static str] = pub const TSAN_SUPPORTED_TARGETS: &'static [&'static str] = &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"]; +const BIG_ENDIAN: &'static [&'static str] = &[ + "armebv7r", + "mips", + "mips64", + "mipsisa32r6", + "mipsisa64r6", + "powerpc", + "powerpc64", + "s390x", + "sparc", + "sparc64", + "sparcv9", +]; + pub fn matches_os(triple: &str, name: &str) -> bool { // For the wasm32 bare target we ignore anything also ignored on emscripten // and then we also recognize `wasm32-bare` as the os for the target @@ -125,6 +139,12 @@ pub fn get_arch(triple: &str) -> &'static str { panic!("Cannot determine Architecture from triple"); } +/// Determine the endianness from `triple` +pub fn is_big_endian(triple: &str) -> bool { + let triple_arch = triple.split('-').next().unwrap(); + BIG_ENDIAN.contains(&triple_arch) +} + pub fn matches_env(triple: &str, name: &str) -> bool { if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false } } diff --git a/src/tools/miri b/src/tools/miri -Subproject 55bdb3174653039f47362742f8dc941bfc086e8 +Subproject cf633d0e897c065381b7b7d14984830176caf8b diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index c0631fcedd3..55e2d7cf827 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -42,7 +42,7 @@ MAINTAINERS = { LABELS = { 'miri': ['A-miri', 'C-bug'], 'rls': ['A-rls', 'C-bug'], - 'rustfmt': ['C-bug'], + 'rustfmt': ['A-rustfmt', 'C-bug'], 'book': ['C-bug'], 'nomicon': ['C-bug'], 'reference': ['C-bug'], diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index eabbcee9d73..d2d1807b3bb 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -15,7 +15,7 @@ //! We have two separate encoding schemes: a skiplist-like approach, and a //! compressed bitset. The datasets we consider mostly use the skiplist (it's //! smaller) but the lowercase and uppercase sets are sufficiently sparse for -//! the bitset to be worthwhile -- for those sets the biset is a 2x size win. +//! the bitset to be worthwhile -- for those sets the bitset is a 2x size win. //! Since the bitset is also faster, this seems an obvious choice. (As a //! historical note, the bitset was also the prior implementation, so its //! relative complexity had already been paid). |
