From c71f5232d812fb17c87650a84c19cd12647e6907 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 26 Dec 2020 10:09:41 -0800 Subject: [PATCH 01/12] Clarify what `Cell::replace` returns --- library/core/src/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c5ab7a39ff0ca..bccc34bf44074 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -374,7 +374,7 @@ impl Cell { } } - /// Replaces the contained value, and returns it. + /// Replaces the contained value with `val`, and returns the old contained value. /// /// # Examples /// From 5c0d76dbe1669c96f1959d7b0b1d4de7e9a47c43 Mon Sep 17 00:00:00 2001 From: The8472 Date: Mon, 22 Feb 2021 21:16:30 +0100 Subject: [PATCH 02/12] add test for failing io::copy specialization --- library/std/src/sys/unix/kernel_copy/tests.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/std/src/sys/unix/kernel_copy/tests.rs b/library/std/src/sys/unix/kernel_copy/tests.rs index 77369cdd35fb6..3fe849e23e2e6 100644 --- a/library/std/src/sys/unix/kernel_copy/tests.rs +++ b/library/std/src/sys/unix/kernel_copy/tests.rs @@ -65,6 +65,24 @@ fn copy_specialization() -> Result<()> { result.and(rm1).and(rm2) } +#[test] +fn copies_append_mode_sink() -> Result<()> { + let tmp_path = tmpdir(); + let source_path = tmp_path.join("copies_append_mode.source"); + let sink_path = tmp_path.join("copies_append_mode.sink"); + let mut source = + OpenOptions::new().create(true).truncate(true).write(true).read(true).open(&source_path)?; + write!(source, "not empty")?; + source.seek(SeekFrom::Start(0))?; + let mut sink = OpenOptions::new().create(true).append(true).open(&sink_path)?; + + let copied = crate::io::copy(&mut source, &mut sink)?; + + assert_eq!(copied, 9); + + Ok(()) +} + #[bench] fn bench_file_to_file_copy(b: &mut test::Bencher) { const BYTES: usize = 128 * 1024; From 81602fb6706654b868dd74ee88f680c57d4311cb Mon Sep 17 00:00:00 2001 From: The8472 Date: Mon, 22 Feb 2021 21:18:12 +0100 Subject: [PATCH 03/12] fix io::copy specialization when writer was opened with O_APPEND --- library/std/src/sys/unix/kernel_copy.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 200dbf06ff8a6..9687576bb6aeb 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -61,6 +61,7 @@ use crate::process::{ChildStderr, ChildStdin, ChildStdout}; use crate::ptr; use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use crate::sys::cvt; +use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV}; #[cfg(test)] mod tests; @@ -535,7 +536,7 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> cvt(copy_file_range(INVALID_FD, ptr::null_mut(), INVALID_FD, ptr::null_mut(), 1, 0)) }; - if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(libc::EBADF))) { + if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(EBADF))) { HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed); } else { HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed); @@ -573,19 +574,20 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> Err(err) => { return match err.raw_os_error() { // when file offset + max_length > u64::MAX - Some(libc::EOVERFLOW) => CopyResult::Fallback(written), - Some( - libc::ENOSYS | libc::EXDEV | libc::EINVAL | libc::EPERM | libc::EOPNOTSUPP, - ) => { + Some(EOVERFLOW) => CopyResult::Fallback(written), + Some(ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF) => { // Try fallback io::copy if either: // - Kernel version is < 4.5 (ENOSYS¹) // - Files are mounted on different fs (EXDEV) // - copy_file_range is broken in various ways on RHEL/CentOS 7 (EOPNOTSUPP) // - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM) // - copy_file_range cannot be used with pipes or device nodes (EINVAL) + // - the writer fd was opened with O_APPEND (EBADF²) // // ¹ these cases should be detected by the initial probe but we handle them here // anyway in case syscall interception changes during runtime + // ² actually invalid file descriptors would cause this too, but in that case + // the fallback code path is expected to encounter the same error again assert_eq!(written, 0); CopyResult::Fallback(0) } @@ -649,7 +651,7 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) -> Ok(ret) => written += ret as u64, Err(err) => { return match err.raw_os_error() { - Some(libc::ENOSYS | libc::EPERM) => { + Some(ENOSYS | EPERM) => { // syscall not supported (ENOSYS) // syscall is disallowed, e.g. by seccomp (EPERM) match mode { @@ -659,12 +661,12 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) -> assert_eq!(written, 0); CopyResult::Fallback(0) } - Some(libc::EINVAL) => { + Some(EINVAL) => { // splice/sendfile do not support this particular file descriptor (EINVAL) assert_eq!(written, 0); CopyResult::Fallback(0) } - Some(os_err) if mode == SpliceMode::Sendfile && os_err == libc::EOVERFLOW => { + Some(os_err) if mode == SpliceMode::Sendfile && os_err == EOVERFLOW => { CopyResult::Fallback(written) } _ => CopyResult::Error(err, written), From d6b06b8a327ff32d083bc0494cc3195d9f8082d2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 5 Mar 2021 08:43:25 -0800 Subject: [PATCH 04/12] std: Fix a bug on the wasm32-wasi target opening files This commit fixes an issue pointed out in #82758 where LTO changed the behavior of a program. It turns out that LTO was not at fault here, it simply uncovered an existing bug. The bindings to `__wasilibc_find_relpath` assumed that the relative portion of the path returned was always contained within thee input `buf` we passed in. This isn't actually the case, however, and sometimes the relative portion of the path may reference a sub-portion of the input string itself. The fix here is to use the relative path pointer coming out of `__wasilibc_find_relpath` as the source of truth. The `buf` used for local storage is discarded in this function and the relative path is copied out unconditionally. We might be able to get away with some `Cow`-like business or such to avoid the extra allocation, but for now this is probably the easiest patch to fix the original issue. --- library/std/src/sys/wasi/fs.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index bcf7da46b4b07..63c22136273fb 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -650,13 +650,11 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop, PathBuf)> { ); return Err(io::Error::new(io::ErrorKind::Other, msg)); } - let len = CStr::from_ptr(buf.as_ptr().cast()).to_bytes().len(); - buf.set_len(len); - buf.shrink_to_fit(); + let relative = CStr::from_ptr(relative_path).to_bytes().to_vec(); return Ok(( ManuallyDrop::new(WasiFd::from_raw(fd as u32)), - PathBuf::from(OsString::from_vec(buf)), + PathBuf::from(OsString::from_vec(relative)), )); } } From 14e23f117ec984434f30e51ebd5e183a3f0533c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Tue, 9 Mar 2021 21:26:07 +0100 Subject: [PATCH 05/12] convert slice doc link to intra-doc links --- library/alloc/src/slice.rs | 10 ++-- library/core/src/slice/mod.rs | 107 +++++++++++++++++----------------- 2 files changed, 58 insertions(+), 59 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 0c911cea1bb1e..8cd4ef7a14e81 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -231,7 +231,7 @@ impl [T] { /// /// When applicable, unstable sorting is preferred because it is generally faster than stable /// sorting and it doesn't allocate auxiliary memory. - /// See [`sort_unstable`](#method.sort_unstable). + /// See [`sort_unstable`](slice::sort_unstable). /// /// # Current implementation /// @@ -282,7 +282,7 @@ impl [T] { /// /// When applicable, unstable sorting is preferred because it is generally faster than stable /// sorting and it doesn't allocate auxiliary memory. - /// See [`sort_unstable_by`](#method.sort_unstable_by). + /// See [`sort_unstable_by`](slice::sort_unstable_by). /// /// # Current implementation /// @@ -320,12 +320,12 @@ impl [T] { /// worst-case, where the key function is *O*(*m*). /// /// For expensive key functions (e.g. functions that are not simple property accesses or - /// basic operations), [`sort_by_cached_key`](#method.sort_by_cached_key) is likely to be + /// basic operations), [`sort_by_cached_key`](slice::sort_by_cached_key) is likely to be /// significantly faster, as it does not recompute element keys. /// /// When applicable, unstable sorting is preferred because it is generally faster than stable /// sorting and it doesn't allocate auxiliary memory. - /// See [`sort_unstable_by_key`](#method.sort_unstable_by_key). + /// See [`sort_unstable_by_key`](slice::sort_unstable_by_key). /// /// # Current implementation /// @@ -363,7 +363,7 @@ impl [T] { /// worst-case, where the key function is *O*(*m*). /// /// For simple key functions (e.g., functions that are property accesses or - /// basic operations), [`sort_by_key`](#method.sort_by_key) is likely to be + /// basic operations), [`sort_by_key`](slice::sort_by_key) is likely to be /// faster. /// /// # Current implementation diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5510bb0257e34..674780a170ecc 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -308,7 +308,7 @@ impl [T] { /// Returns a mutable reference to an element or subslice depending on the /// type of index (see [`get`]) or `None` if the index is out of bounds. /// - /// [`get`]: #method.get + /// [`get`]: slice::get /// /// # Examples /// @@ -339,7 +339,7 @@ impl [T] { /// Calling this method with an out-of-bounds index is *[undefined behavior]* /// even if the resulting reference is not used. /// - /// [`get`]: #method.get + /// [`get`]: slice::get /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples @@ -373,7 +373,7 @@ impl [T] { /// Calling this method with an out-of-bounds index is *[undefined behavior]* /// even if the resulting reference is not used. /// - /// [`get_mut`]: #method.get_mut + /// [`get_mut`]: slice::get_mut /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples @@ -424,7 +424,7 @@ impl [T] { /// } /// ``` /// - /// [`as_mut_ptr`]: #method.as_mut_ptr + /// [`as_mut_ptr`]: slice::as_mut_ptr #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] #[inline] @@ -487,7 +487,7 @@ impl [T] { /// assert!(!a.as_ptr_range().contains(&y)); /// ``` /// - /// [`as_ptr`]: #method.as_ptr + /// [`as_ptr`]: slice::as_ptr #[stable(feature = "slice_ptr_range", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] @@ -529,7 +529,7 @@ impl [T] { /// use two pointers to refer to a range of elements in memory, as is /// common in C++. /// - /// [`as_mut_ptr`]: #method.as_mut_ptr + /// [`as_mut_ptr`]: slice::as_mut_ptr #[stable(feature = "slice_ptr_range", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] @@ -780,8 +780,8 @@ impl [T] { /// assert!(iter.next().is_none()); /// ``` /// - /// [`chunks_exact`]: #method.chunks_exact - /// [`rchunks`]: #method.rchunks + /// [`chunks_exact`]: slice::chunks_exact + /// [`rchunks`]: slice::rchunks #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { @@ -818,8 +818,8 @@ impl [T] { /// assert_eq!(v, &[1, 1, 2, 2, 3]); /// ``` /// - /// [`chunks_exact_mut`]: #method.chunks_exact_mut - /// [`rchunks_mut`]: #method.rchunks_mut + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`rchunks_mut`]: slice::rchunks_mut #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { @@ -855,8 +855,8 @@ impl [T] { /// assert_eq!(iter.remainder(), &['m']); /// ``` /// - /// [`chunks`]: #method.chunks - /// [`rchunks_exact`]: #method.rchunks_exact + /// [`chunks`]: slice::chunks + /// [`rchunks_exact`]: slice::rchunks_exact #[stable(feature = "chunks_exact", since = "1.31.0")] #[inline] pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { @@ -897,8 +897,8 @@ impl [T] { /// assert_eq!(v, &[1, 1, 2, 2, 0]); /// ``` /// - /// [`chunks_mut`]: #method.chunks_mut - /// [`rchunks_exact_mut`]: #method.rchunks_exact_mut + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut #[stable(feature = "chunks_exact", since = "1.31.0")] #[inline] pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { @@ -1032,7 +1032,7 @@ impl [T] { /// assert_eq!(iter.remainder(), &['m']); /// ``` /// - /// [`chunks_exact`]: #method.chunks_exact + /// [`chunks_exact`]: slice::chunks_exact #[unstable(feature = "array_chunks", issue = "74985")] #[inline] pub fn array_chunks(&self) -> ArrayChunks<'_, T, N> { @@ -1182,7 +1182,7 @@ impl [T] { /// assert_eq!(v, &[1, 1, 2, 2, 0]); /// ``` /// - /// [`chunks_exact_mut`]: #method.chunks_exact_mut + /// [`chunks_exact_mut`]: slice::chunks_exact_mut #[unstable(feature = "array_chunks", issue = "74985")] #[inline] pub fn array_chunks_mut(&mut self) -> ArrayChunksMut<'_, T, N> { @@ -1214,7 +1214,7 @@ impl [T] { /// assert!(iter.next().is_none()); /// ``` /// - /// [`windows`]: #method.windows + /// [`windows`]: slice::windows #[unstable(feature = "array_windows", issue = "75027")] #[inline] pub fn array_windows(&self) -> ArrayWindows<'_, T, N> { @@ -1247,8 +1247,8 @@ impl [T] { /// assert!(iter.next().is_none()); /// ``` /// - /// [`rchunks_exact`]: #method.rchunks_exact - /// [`chunks`]: #method.chunks + /// [`rchunks_exact`]: slice::rchunks_exact + /// [`chunks`]: slice::chunks #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { @@ -1285,8 +1285,8 @@ impl [T] { /// assert_eq!(v, &[3, 2, 2, 1, 1]); /// ``` /// - /// [`rchunks_exact_mut`]: #method.rchunks_exact_mut - /// [`chunks_mut`]: #method.chunks_mut + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`chunks_mut`]: slice::chunks_mut #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { @@ -1323,9 +1323,9 @@ impl [T] { /// assert_eq!(iter.remainder(), &['l']); /// ``` /// - /// [`chunks`]: #method.chunks - /// [`rchunks`]: #method.rchunks - /// [`chunks_exact`]: #method.chunks_exact + /// [`chunks`]: slice::chunks + /// [`rchunks`]: slice::rchunks + /// [`chunks_exact`]: slice::chunks_exact #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { @@ -1366,9 +1366,9 @@ impl [T] { /// assert_eq!(v, &[0, 2, 2, 1, 1]); /// ``` /// - /// [`chunks_mut`]: #method.chunks_mut - /// [`rchunks_mut`]: #method.rchunks_mut - /// [`chunks_exact_mut`]: #method.chunks_exact_mut + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_mut`]: slice::rchunks_mut + /// [`chunks_exact_mut`]: slice::chunks_exact_mut #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { @@ -1552,7 +1552,7 @@ impl [T] { /// even if the resulting reference is not used. The caller has to ensure that /// `0 <= mid <= self.len()`. /// - /// [`split_at`]: #method.split_at + /// [`split_at`]: slice::split_at /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples @@ -1601,7 +1601,7 @@ impl [T] { /// even if the resulting reference is not used. The caller has to ensure that /// `0 <= mid <= self.len()`. /// - /// [`split_at_mut`]: #method.split_at_mut + /// [`split_at_mut`]: slice::split_at_mut /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples @@ -2103,9 +2103,9 @@ impl [T] { /// /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`]. /// - /// [`binary_search_by`]: #method.binary_search_by - /// [`binary_search_by_key`]: #method.binary_search_by_key - /// [`partition_point`]: #method.partition_point + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point /// /// # Examples /// @@ -2156,9 +2156,9 @@ impl [T] { /// /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`]. /// - /// [`binary_search`]: #method.binary_search - /// [`binary_search_by_key`]: #method.binary_search_by_key - /// [`partition_point`]: #method.partition_point + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point /// /// # Examples /// @@ -2215,7 +2215,7 @@ impl [T] { /// Binary searches this sorted slice with a key extraction function. /// /// Assumes that the slice is sorted by the key, for instance with - /// [`sort_by_key`] using the same key extraction function. + /// `sort_by_key` using the same key extraction function. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any @@ -2225,10 +2225,9 @@ impl [T] { /// /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. /// - /// [`sort_by_key`]: #method.sort_by_key - /// [`binary_search`]: #method.binary_search - /// [`binary_search_by`]: #method.binary_search_by - /// [`partition_point`]: #method.partition_point + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`partition_point`]: slice::partition_point /// /// # Examples /// @@ -2446,7 +2445,7 @@ impl [T] { /// The current algorithm is based on the quickselect portion of the same quicksort algorithm /// used for [`sort_unstable`]. /// - /// [`sort_unstable`]: #method.sort_unstable + /// [`sort_unstable`]: slice::sort_unstable /// /// # Panics /// @@ -2494,7 +2493,7 @@ impl [T] { /// The current algorithm is based on the quickselect portion of the same quicksort algorithm /// used for [`sort_unstable`]. /// - /// [`sort_unstable`]: #method.sort_unstable + /// [`sort_unstable`]: slice::sort_unstable /// /// # Panics /// @@ -2546,7 +2545,7 @@ impl [T] { /// The current algorithm is based on the quickselect portion of the same quicksort algorithm /// used for [`sort_unstable`]. /// - /// [`sort_unstable`]: #method.sort_unstable + /// [`sort_unstable`]: slice::sort_unstable /// /// # Panics /// @@ -2883,7 +2882,7 @@ impl [T] { /// trait to generate values, you can pass [`Default::default`] as the /// argument. /// - /// [`fill`]: #method.fill + /// [`fill`]: slice::fill /// /// # Examples /// @@ -2956,8 +2955,8 @@ impl [T] { /// assert_eq!(slice, [4, 5, 3, 4, 5]); /// ``` /// - /// [`copy_from_slice`]: #method.copy_from_slice - /// [`split_at_mut`]: #method.split_at_mut + /// [`copy_from_slice`]: slice::copy_from_slice + /// [`split_at_mut`]: slice::split_at_mut #[stable(feature = "clone_from_slice", since = "1.7.0")] pub fn clone_from_slice(&mut self, src: &[T]) where @@ -3018,8 +3017,8 @@ impl [T] { /// assert_eq!(slice, [4, 5, 3, 4, 5]); /// ``` /// - /// [`clone_from_slice`]: #method.clone_from_slice - /// [`split_at_mut`]: #method.split_at_mut + /// [`clone_from_slice`]: slice::clone_from_slice + /// [`split_at_mut`]: slice::split_at_mut #[doc(alias = "memcpy")] #[stable(feature = "copy_from_slice", since = "1.9.0")] pub fn copy_from_slice(&mut self, src: &[T]) @@ -3136,7 +3135,7 @@ impl [T] { /// assert_eq!(slice, [4, 5, 3, 1, 2]); /// ``` /// - /// [`split_at_mut`]: #method.split_at_mut + /// [`split_at_mut`]: slice::split_at_mut #[stable(feature = "swap_with_slice", since = "1.27.0")] pub fn swap_with_slice(&mut self, other: &mut [T]) { assert!(self.len() == other.len(), "destination and source slices have different lengths"); @@ -3380,7 +3379,7 @@ impl [T] { /// function to determine the ordering of two elements. Apart from that, it's equivalent to /// [`is_sorted`]; see its documentation for more information. /// - /// [`is_sorted`]: #method.is_sorted + /// [`is_sorted`]: slice::is_sorted #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] pub fn is_sorted_by(&self, mut compare: F) -> bool where @@ -3395,7 +3394,7 @@ impl [T] { /// elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see its /// documentation for more information. /// - /// [`is_sorted`]: #method.is_sorted + /// [`is_sorted`]: slice::is_sorted /// /// # Examples /// @@ -3429,9 +3428,9 @@ impl [T] { /// /// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`]. /// - /// [`binary_search`]: #method.binary_search - /// [`binary_search_by`]: #method.binary_search_by - /// [`binary_search_by_key`]: #method.binary_search_by_key + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key /// /// # Examples /// From a4d7046714731987d079da9b99769a60da246fc9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Mar 2021 16:40:27 +0100 Subject: [PATCH 06/12] Fix "run" button position in error index --- src/doc/rust.css | 1 + src/librustdoc/html/static/rustdoc.css | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rust.css b/src/doc/rust.css index ff18e1a8f51cc..06f4df9a9b6da 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -332,6 +332,7 @@ table th { /* Code snippets */ +.example-wrap { position: relative; } pre.rust { position: relative; } a.test-arrow { background-color: rgba(78, 139, 202, 0.2); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 94c231cb33a8b..7393abfdd9eb5 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -347,10 +347,10 @@ nav.sub { .rustdoc:not(.source) .example-wrap { display: inline-flex; margin-bottom: 10px; - position: relative; } .example-wrap { + position: relative; width: 100%; } From a8088220937764db329135b3e778de935a9abbb2 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 10 Mar 2021 11:04:16 -0600 Subject: [PATCH 07/12] Simplify lower ast block --- compiler/rustc_ast_lowering/src/lib.rs | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 057e4d81f80fd..3a97321ceb691 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2409,26 +2409,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_block_noalloc(&mut self, b: &Block, targeted_by_break: bool) -> hir::Block<'hir> { - let mut expr: Option<&'hir _> = None; - - let stmts = self.arena.alloc_from_iter( - b.stmts - .iter() - .enumerate() - .filter_map(|(index, stmt)| { - if index == b.stmts.len() - 1 { - if let StmtKind::Expr(ref e) = stmt.kind { - expr = Some(self.lower_expr(e)); - None - } else { - Some(self.lower_stmt(stmt)) - } - } else { - Some(self.lower_stmt(stmt)) - } - }) - .flatten(), - ); + let (stmts, expr) = match &*b.stmts { + [stmts @ .., Stmt { kind: StmtKind::Expr(e), .. }] => (stmts, Some(&*e)), + stmts => (stmts, None), + }; + let stmts = self.arena.alloc_from_iter(stmts.iter().flat_map(|stmt| self.lower_stmt(stmt))); + let expr = expr.map(|e| self.lower_expr(e)); let rules = self.lower_block_check_mode(&b.rules); let hir_id = self.lower_node_id(b.id); From 0d0715350717f7aa308fbe7473b863b95f6198f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Wed, 10 Mar 2021 18:18:28 +0100 Subject: [PATCH 08/12] add back sort_by_key link, allow linter and add comment --- library/core/src/slice/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 674780a170ecc..e35f3e52aa0be 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2215,7 +2215,7 @@ impl [T] { /// Binary searches this sorted slice with a key extraction function. /// /// Assumes that the slice is sorted by the key, for instance with - /// `sort_by_key` using the same key extraction function. + /// [`sort_by_key`] using the same key extraction function. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any @@ -2225,6 +2225,7 @@ impl [T] { /// /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. /// + /// [`sort_by_key`]: slice::sort_by_key /// [`binary_search`]: slice::binary_search /// [`binary_search_by`]: slice::binary_search_by /// [`partition_point`]: slice::partition_point @@ -2247,6 +2248,10 @@ impl [T] { /// let r = s.binary_search_by_key(&1, |&(a, b)| b); /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` + // Lint rustdoc::broken_intra_doc_links is allowed as `slice::sort_by_key` is + // in crate `alloc`, and as such doesn't exists yet when building `core` + // links to downstream crate: https://github.com/rust-lang/rust/issues/74481 + #[cfg_attr(not(bootstrap), allow(rustdoc::broken_intra_doc_links))] #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] #[inline] pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result From 06669056b53e00c53ff6d787e706c393a469eb78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Wed, 10 Mar 2021 18:18:56 +0100 Subject: [PATCH 09/12] remove slice linkcheck exceptions --- src/tools/linkchecker/main.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 01e067ea0b803..f6875e0036f67 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -33,11 +33,6 @@ use crate::Redirect::*; // are cases where that does not work // [(generated_documentation_page, &[broken_links])] const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ - // These are methods on slice, and `Self` does not work on primitive impls - // in intra-doc links (primitive impls are weird) - // https://github.com/rust-lang/rust/issues/62834 is necessary to be - // able to link to slices - ("std/io/struct.IoSlice.html", &["#method.as_mut_ptr", "#method.sort_by_key"]), // These try to link to std::collections, but are defined in alloc // https://github.com/rust-lang/rust/issues/74481 ("std/collections/btree_map/struct.BTreeMap.html", &["#insert-and-complex-keys"]), From 232b9f1641097763ef40fedccf442f2119958608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Wed, 10 Mar 2021 18:32:55 +0100 Subject: [PATCH 10/12] apply review --- library/core/src/slice/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e35f3e52aa0be..417a106b99a2e 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2249,9 +2249,11 @@ impl [T] { /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` // Lint rustdoc::broken_intra_doc_links is allowed as `slice::sort_by_key` is - // in crate `alloc`, and as such doesn't exists yet when building `core` - // links to downstream crate: https://github.com/rust-lang/rust/issues/74481 + // in crate `alloc`, and as such doesn't exists yet when building `core`. + // links to downstream crate: #74481. Since primitives are only documented in + // libstd (#73423), this never leads to broken links in practice. #[cfg_attr(not(bootstrap), allow(rustdoc::broken_intra_doc_links))] + #[cfg_attr(bootstrap, allow(broken_intra_doc_links))] #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] #[inline] pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result From 3934dd1b3e7514959202de6ca0d2636bcae21830 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 10 Mar 2021 19:31:49 -0700 Subject: [PATCH 11/12] rustdoc: tweak the search index format This essentially switches search-index.js from a "array of struct" to a "struct of array" format, like this: { "doc": "Crate documentation", "t": [ 1, 1, 2, 3, ... ], "n": [ "Something", "SomethingElse", "whatever", "do_stuff", ... ], "q": [ "a::b", "", "", "", ... ], "d": [ "A Struct That Does Something", "Another Struct", "a function", "another function", ... ], "i": [ 0, 0, 1, 1, ... ], "f": [ null, null, [], [], ... ], "p": ..., "a": ... } So `{ty: 1, name: "Something", path: "a::b", desc: "A Struct That Does Something", parent_idx: 0, search_type: null}` is the first item. This makes the uncompressed version smaller, but it really shows on the compressed version: notriddle:rust$ wc -c new-search-index1.52.0.js 2622427 new-search-index1.52.0.js notriddle:rust$ wc -c old-search-index1.52.0.js 2725046 old-search-index1.52.0.js notriddle:rust$ gzip new-search-index1.52.0.js notriddle:rust$ gzip old-search-index1.52.0.js notriddle:rust$ wc -c new-search-index1.52.0.js.gz 239385 new-search-index1.52.0.js.gz notriddle:rust$ wc -c old-search-index1.52.0.js.gz 296328 old-search-index1.52.0.js.gz notriddle:rust$ That's a 4% improvement on the uncompressed version (fewer `[]`), and 20% improvement after gzipping it, thanks to putting like-typed data next to each other. Any compression algorithm based on a sliding window will probably show this kind of improvement. --- src/librustdoc/html/render/cache.rs | 60 ++++++++++++++++++++++++++--- src/librustdoc/html/render/mod.rs | 17 -------- src/librustdoc/html/static/main.js | 39 ++++++++++--------- 3 files changed, 74 insertions(+), 42 deletions(-) diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index a21cf5266fe1f..56fee2c9fec2d 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -4,7 +4,7 @@ use std::path::Path; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{sym, Symbol}; -use serde::Serialize; +use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean::types::{ FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, TypeKind, WherePredicate, @@ -133,21 +133,69 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< .map(|module| module.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s))) .unwrap_or_default(); - #[derive(Serialize)] struct CrateData<'a> { doc: String, - #[serde(rename = "i")] items: Vec<&'a IndexItem>, - #[serde(rename = "p")] paths: Vec<(ItemType, String)>, // The String is alias name and the vec is the list of the elements with this alias. // // To be noted: the `usize` elements are indexes to `items`. - #[serde(rename = "a")] - #[serde(skip_serializing_if = "BTreeMap::is_empty")] aliases: &'a BTreeMap>, } + impl<'a> Serialize for CrateData<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let has_aliases = !self.aliases.is_empty(); + let mut crate_data = + serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?; + crate_data.serialize_field("doc", &self.doc)?; + crate_data.serialize_field( + "t", + &self.items.iter().map(|item| &item.ty).collect::>(), + )?; + crate_data.serialize_field( + "n", + &self.items.iter().map(|item| &item.name).collect::>(), + )?; + crate_data.serialize_field( + "q", + &self.items.iter().map(|item| &item.path).collect::>(), + )?; + crate_data.serialize_field( + "d", + &self.items.iter().map(|item| &item.desc).collect::>(), + )?; + crate_data.serialize_field( + "i", + &self + .items + .iter() + .map(|item| { + assert_eq!( + item.parent.is_some(), + item.parent_idx.is_some(), + "`{}` is missing idx", + item.name + ); + item.parent_idx.map(|x| x + 1).unwrap_or(0) + }) + .collect::>(), + )?; + crate_data.serialize_field( + "f", + &self.items.iter().map(|item| &item.search_type).collect::>(), + )?; + crate_data.serialize_field("p", &self.paths)?; + if has_aliases { + crate_data.serialize_field("a", &self.aliases)?; + } + crate_data.end() + } + } + // Collect the index into a string format!( r#""{}":{}"#, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index a4621fb8ed555..66c47f14655ba 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -166,23 +166,6 @@ crate struct IndexItem { crate search_type: Option, } -impl Serialize for IndexItem { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - assert_eq!( - self.parent.is_some(), - self.parent_idx.is_some(), - "`{}` is missing idx", - self.name - ); - - (self.ty, &self.name, &self.path, &self.desc, self.parent_idx, &self.search_type) - .serialize(serializer) - } -} - /// A type used for the search index. #[derive(Debug)] crate struct RenderType { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 42519d596225b..ac2da5f779bd1 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1847,13 +1847,18 @@ function defocusSearchBar() { }); currentIndex += 1; - // an array of [(Number) item type, - // (String) name, - // (String) full path or empty string for previous path, - // (String) description, - // (Number | null) the parent path index to `paths`] - // (Object | null) the type of the function (if any) - var items = rawSearchIndex[crate].i; + // an array of (Number) item types + var itemTypes = rawSearchIndex[crate].t; + // an array of (String) item names + var itemNames = rawSearchIndex[crate].n; + // an array of (String) full paths (or empty string for previous path) + var itemPaths = rawSearchIndex[crate].q; + // an array of (String) descriptions + var itemDescs = rawSearchIndex[crate].d; + // an array of (Number) the parent path index + 1 to `paths`, or 0 if none + var itemParentIdxs = rawSearchIndex[crate].i; + // an array of (Object | null) the type of the function, if any + var itemFunctionSearchTypes = rawSearchIndex[crate].f; // an array of [(Number) item type, // (String) name] var paths = rawSearchIndex[crate].p; @@ -1867,28 +1872,24 @@ function defocusSearchBar() { paths[i] = {ty: paths[i][0], name: paths[i][1]}; } - // convert `items` into an object form, and construct word indices. + // convert `item*` into an object form, and construct word indices. // // before any analysis is performed lets gather the search terms to // search against apart from the rest of the data. This is a quick // operation that is cached for the life of the page state so that // all other search operations have access to this cached data for // faster analysis operations - len = items.length; + len = itemTypes.length; var lastPath = ""; for (i = 0; i < len; ++i) { - var rawRow = items[i]; - if (!rawRow[2]) { - rawRow[2] = lastPath; - } var row = { crate: crate, - ty: rawRow[0], - name: rawRow[1], - path: rawRow[2], - desc: rawRow[3], - parent: paths[rawRow[4]], - type: rawRow[5], + ty: itemTypes[i], + name: itemNames[i], + path: itemPaths[i] ? itemPaths[i] : lastPath, + desc: itemDescs[i], + parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined, + type: itemFunctionSearchTypes[i], }; searchIndex.push(row); if (typeof row.name === "string") { From b4cc00381bf4782b79fd4acc3bc534a160bdd535 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 13 Feb 2021 20:41:02 +0100 Subject: [PATCH 12/12] Make def_key and HIR parenting consistent. --- compiler/rustc_ast_lowering/src/lib.rs | 49 +++++----- .../rustc_middle/src/hir/map/collector.rs | 12 +++ compiler/rustc_resolve/src/def_collector.rs | 89 +++++++++++++++---- compiler/rustc_resolve/src/lib.rs | 13 ++- compiler/rustc_resolve/src/macros.rs | 2 +- src/test/ui/consts/miri_unleashed/tls.stderr | 4 +- .../print/generator-print-verbose-1.stderr | 10 +-- src/test/ui/impl-trait/impl-trait-in-macro.rs | 20 +++++ .../ui/impl-trait/impl-trait-in-macro.stderr | 20 +++++ .../impl-trait/universal-two-impl-traits.rs | 9 +- 10 files changed, 177 insertions(+), 51 deletions(-) create mode 100644 src/test/ui/impl-trait/impl-trait-in-macro.rs create mode 100644 src/test/ui/impl-trait/impl-trait-in-macro.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 057e4d81f80fd..161c6c7732df4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -223,7 +223,7 @@ enum ImplTraitContext<'b, 'a> { /// equivalent to a fresh universal parameter like `fn foo(x: T)`. /// /// Newly generated parameters should be inserted into the given `Vec`. - Universal(&'b mut Vec>), + Universal(&'b mut Vec>, LocalDefId), /// Treat `impl Trait` as shorthand for a new opaque type. /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually @@ -278,7 +278,7 @@ impl<'a> ImplTraitContext<'_, 'a> { fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> { use self::ImplTraitContext::*; match self { - Universal(params) => Universal(params), + Universal(params, parent) => Universal(params, *parent), ReturnPositionOpaqueTy { fn_def_id, origin } => { ReturnPositionOpaqueTy { fn_def_id: *fn_def_id, origin: *origin } } @@ -475,25 +475,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } impl MiscCollector<'_, '_, '_> { - fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: LocalDefId) { + fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree) { match tree.kind { UseTreeKind::Simple(_, id1, id2) => { for &id in &[id1, id2] { - self.lctx.resolver.create_def( - owner, - id, - DefPathData::Misc, - ExpnId::root(), - tree.prefix.span, - ); self.lctx.allocate_hir_id_counter(id); } } UseTreeKind::Glob => (), UseTreeKind::Nested(ref trees) => { for &(ref use_tree, id) in trees { - let hir_id = self.lctx.allocate_hir_id_counter(id); - self.allocate_use_tree_hir_id_counters(use_tree, hir_id.owner); + self.lctx.allocate_hir_id_counter(id); + self.allocate_use_tree_hir_id_counters(use_tree); } } } @@ -502,7 +495,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> { fn visit_item(&mut self, item: &'tcx Item) { - let hir_id = self.lctx.allocate_hir_id_counter(item.id); + self.lctx.allocate_hir_id_counter(item.id); match item.kind { ItemKind::Struct(_, ref generics) @@ -521,7 +514,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lctx.type_def_lifetime_params.insert(def_id.to_def_id(), count); } ItemKind::Use(ref use_tree) => { - self.allocate_use_tree_hir_id_counters(use_tree, hir_id.owner); + self.allocate_use_tree_hir_id_counters(use_tree); } _ => {} } @@ -939,8 +932,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `lifetimes_to_define`. If we swapped the order of these two, // in-band-lifetimes introduced by generics or where-clauses // wouldn't have been added yet. - let generics = - this.lower_generics_mut(generics, ImplTraitContext::Universal(&mut params)); + let generics = this.lower_generics_mut( + generics, + ImplTraitContext::Universal( + &mut params, + this.current_hir_id_owner.last().unwrap().0, + ), + ); let res = f(this, &mut params); (params, (generics, res)) }) @@ -1145,6 +1143,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } AssocTyConstraintKind::Bound { ref bounds } => { let mut capturable_lifetimes; + let mut parent_def_id = self.current_hir_id_owner.last().unwrap().0; // Piggy-back on the `impl Trait` context to figure out the correct behavior. let (desugar_to_impl_trait, itctx) = match itctx { // We are in the return position: @@ -1164,7 +1163,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo(x: dyn Iterator) - ImplTraitContext::Universal(..) if self.is_in_dyn_type => (true, itctx), + ImplTraitContext::Universal(_, parent) if self.is_in_dyn_type => { + parent_def_id = parent; + (true, itctx) + } // In `type Foo = dyn Iterator` we desugar to // `type Foo = dyn Iterator` but we have to override the @@ -1198,7 +1200,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // constructing the HIR for `impl bounds...` and then lowering that. let impl_trait_node_id = self.resolver.next_node_id(); - let parent_def_id = self.current_hir_id_owner.last().unwrap().0; self.resolver.create_def( parent_def_id, impl_trait_node_id, @@ -1451,7 +1452,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { |this| this.lower_param_bounds(bounds, nested_itctx), ) } - ImplTraitContext::Universal(in_band_ty_params) => { + ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => { // Add a definition for the in-band `Param`. let def_id = self.resolver.local_def_id(def_node_id); @@ -1460,7 +1461,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let hir_bounds = self.with_hir_id_owner(def_node_id, |this| { this.lower_param_bounds( bounds, - ImplTraitContext::Universal(in_band_ty_params), + ImplTraitContext::Universal(in_band_ty_params, parent_def_id), ) }); // Set the name to `impl Bound1 + Bound2`. @@ -1891,7 +1892,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } this.arena.alloc_from_iter(inputs.iter().map(|param| { if let Some((_, ibty)) = &mut in_band_ty_params { - this.lower_ty_direct(¶m.ty, ImplTraitContext::Universal(ibty)) + this.lower_ty_direct( + ¶m.ty, + ImplTraitContext::Universal( + ibty, + this.current_hir_id_owner.last().unwrap().0, + ), + ) } else { this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed()) } diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index b1dd405a6be68..64d0503834bde 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -221,6 +221,18 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { data.signature = Some(self.arena.alloc(Owner { parent: entry.parent, node: entry.node })); + + let dk_parent = self.definitions.def_key(id.owner).parent; + if let Some(dk_parent) = dk_parent { + let dk_parent = LocalDefId { local_def_index: dk_parent }; + let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent); + if dk_parent.owner != entry.parent.owner { + panic!( + "Different parents for {:?} => dk_parent={:?} actual={:?}", + id.owner, dk_parent, entry.parent, + ) + } + } } else { assert_eq!(entry.parent.owner, id.owner); insert_vec_map( diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 727d6ab53d869..6ef5e1179debc 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -1,4 +1,4 @@ -use crate::Resolver; +use crate::{ImplTraitContext, Resolver}; use rustc_ast::visit::{self, FnKind}; use rustc_ast::walk_list; use rustc_ast::*; @@ -16,14 +16,15 @@ crate fn collect_definitions( fragment: &AstFragment, expansion: ExpnId, ) { - let parent_def = resolver.invocation_parents[&expansion]; - fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion }); + let (parent_def, impl_trait_context) = resolver.invocation_parents[&expansion]; + fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion, impl_trait_context }); } /// Creates `DefId`s for nodes in the AST. struct DefCollector<'a, 'b> { resolver: &'a mut Resolver<'b>, parent_def: LocalDefId, + impl_trait_context: ImplTraitContext, expansion: ExpnId, } @@ -40,6 +41,16 @@ impl<'a, 'b> DefCollector<'a, 'b> { self.parent_def = orig_parent_def; } + fn with_impl_trait( + &mut self, + impl_trait_context: ImplTraitContext, + f: F, + ) { + let orig_itc = std::mem::replace(&mut self.impl_trait_context, impl_trait_context); + f(self); + self.impl_trait_context = orig_itc; + } + fn collect_field(&mut self, field: &'a StructField, index: Option) { let index = |this: &Self| { index.unwrap_or_else(|| { @@ -60,8 +71,9 @@ impl<'a, 'b> DefCollector<'a, 'b> { } fn visit_macro_invoc(&mut self, id: NodeId) { + let id = id.placeholder_to_expn_id(); let old_parent = - self.resolver.invocation_parents.insert(id.placeholder_to_expn_id(), self.parent_def); + self.resolver.invocation_parents.insert(id, (self.parent_def, self.impl_trait_context)); assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation"); } } @@ -103,29 +115,37 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { let def = self.create_def(i.id, def_data, i.span); self.with_parent(def, |this| { - match i.kind { - ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { - // If this is a unit or tuple-like struct, register the constructor. - if let Some(ctor_hir_id) = struct_def.ctor_id() { - this.create_def(ctor_hir_id, DefPathData::Ctor, i.span); + this.with_impl_trait(ImplTraitContext::Existential, |this| { + match i.kind { + ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { + // If this is a unit or tuple-like struct, register the constructor. + if let Some(ctor_hir_id) = struct_def.ctor_id() { + this.create_def(ctor_hir_id, DefPathData::Ctor, i.span); + } } + _ => {} } - _ => {} - } - visit::walk_item(this, i); + visit::walk_item(this, i); + }) }); } fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { if let FnKind::Fn(_, _, sig, _, body) = fn_kind { if let Async::Yes { closure_id, return_impl_trait_id, .. } = sig.header.asyncness { - self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span); + let return_impl_trait_id = + self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span); // For async functions, we need to create their inner defs inside of a // closure to match their desugared representation. Besides that, // we must mirror everything that `visit::walk_fn` below does. self.visit_fn_header(&sig.header); - visit::walk_fn_decl(self, &sig.decl); + for param in &sig.decl.inputs { + self.visit_param(param); + } + self.with_parent(return_impl_trait_id, |this| { + this.visit_fn_ret_ty(&sig.decl.output) + }); let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span); self.with_parent(closure_def, |this| walk_list!(this, visit_block, body)); return; @@ -137,6 +157,14 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { self.create_def(id, DefPathData::Misc, use_tree.span); + match use_tree.kind { + UseTreeKind::Simple(_, id1, id2) => { + self.create_def(id1, DefPathData::Misc, use_tree.prefix.span); + self.create_def(id2, DefPathData::Misc, use_tree.prefix.span); + } + UseTreeKind::Glob => (), + UseTreeKind::Nested(..) => {} + } visit::walk_use_tree(self, use_tree, id); } @@ -191,7 +219,15 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { }; self.create_def(param.id, def_path_data, param.ident.span); - visit::walk_generic_param(self, param); + // impl-Trait can happen inside generic parameters, like + // ``` + // fn foo>() {} + // ``` + // + // In that case, the impl-trait is lowered as an additional generic parameter. + self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| { + visit::walk_generic_param(this, param) + }); } fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { @@ -244,8 +280,19 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { match ty.kind { TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), TyKind::ImplTrait(node_id, _) => { - let parent_def = self.create_def(node_id, DefPathData::ImplTrait, ty.span); - self.with_parent(parent_def, |this| visit::walk_ty(this, ty)); + let parent_def = match self.impl_trait_context { + ImplTraitContext::Universal(item_def) => self.resolver.create_def( + item_def, + node_id, + DefPathData::ImplTrait, + self.expansion, + ty.span, + ), + ImplTraitContext::Existential => { + self.create_def(node_id, DefPathData::ImplTrait, ty.span) + } + }; + self.with_parent(parent_def, |this| visit::walk_ty(this, ty)) } _ => visit::walk_ty(self, ty), } @@ -275,7 +322,13 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { } fn visit_param(&mut self, p: &'a Param) { - if p.is_placeholder { self.visit_macro_invoc(p.id) } else { visit::walk_param(self, p) } + if p.is_placeholder { + self.visit_macro_invoc(p.id) + } else { + self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| { + visit::walk_param(this, p) + }) + } } // This method is called only when we are visiting an individual field diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2ce54658c0b10..ccfb5ff3aa0e6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -156,6 +156,12 @@ impl<'a> ParentScope<'a> { } } +#[derive(Copy, Debug, Clone)] +enum ImplTraitContext { + Existential, + Universal(LocalDefId), +} + #[derive(Eq)] struct BindingError { name: Symbol, @@ -989,8 +995,9 @@ pub struct Resolver<'a> { /// Indices of unnamed struct or variant fields with unresolved attributes. placeholder_field_indices: FxHashMap, /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` - /// we know what parent node that fragment should be attached to thanks to this table. - invocation_parents: FxHashMap, + /// we know what parent node that fragment should be attached to thanks to this table, + /// and how the `impl Trait` fragments were introduced. + invocation_parents: FxHashMap, next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>, /// Some way to know that we are in a *trait* impl in `visit_assoc_item`. @@ -1205,7 +1212,7 @@ impl<'a> Resolver<'a> { node_id_to_def_id.insert(CRATE_NODE_ID, root); let mut invocation_parents = FxHashMap::default(); - invocation_parents.insert(ExpnId::root(), root); + invocation_parents.insert(ExpnId::root(), (root, ImplTraitContext::Existential)); let mut extern_prelude: FxHashMap> = session .opts diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f7010ca94bd2c..2d149c476a60f 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -326,7 +326,7 @@ impl<'a> ResolverExpand for Resolver<'a> { // nearest closing item - we should try to return the closest parent of the ExpnId self.invocation_parents .get(&expn_id) - .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id]) + .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]) } fn has_derive_copy(&self, expn_id: ExpnId) -> bool { diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr index 5cef636e0a817..62e2dc7121097 100644 --- a/src/test/ui/consts/miri_unleashed/tls.stderr +++ b/src/test/ui/consts/miri_unleashed/tls.stderr @@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:12:25 | LL | unsafe { let _val = A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A)) + | ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A)) error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A)) + | ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A)) warning: skipping const checks | diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr index b5c63584c6c14..78100318dc33a 100644 --- a/src/test/ui/generator/print/generator-print-verbose-1.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr @@ -12,7 +12,7 @@ note: generator is not `Send` as this value is used across a yield --> $DIR/generator-print-verbose-1.rs:35:9 | LL | let _non_send_gen = make_non_send_generator(); - | ------------- has type `Opaque(DefId(0:24 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send` + | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send` LL | yield; | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later LL | }; @@ -30,10 +30,10 @@ LL | require_send(send_gen); = help: the trait `Sync` is not implemented for `RefCell` = note: required because of the requirements on the impl of `Send` for `Arc>` = note: required because it appears within the type `[make_gen2>>::{closure#0} upvar_tys=(Arc>) {()}]` - = note: required because it appears within the type `Opaque(DefId(0:29 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc>])` - = note: required because it appears within the type `Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])` - = note: required because it appears within the type `{Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}` - = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]` + = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc>])` + = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])` + = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}` + = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]` error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/impl-trait-in-macro.rs b/src/test/ui/impl-trait/impl-trait-in-macro.rs new file mode 100644 index 0000000000000..3165c9b991572 --- /dev/null +++ b/src/test/ui/impl-trait/impl-trait-in-macro.rs @@ -0,0 +1,20 @@ +use std::fmt::Debug; + +macro_rules! i { + ($($tr:tt)*) => { impl $($tr)* }; +} + +fn foo(x: i!(Debug), y: i!(Debug)) -> String { + let mut a = x; + a = y; //~ ERROR mismatched + format!("{:?}", a) +} + +trait S {} + +fn much_universe, U: IntoIterator)>>( + _: i!(Debug + Clone), +) { +} + +fn main() {} diff --git a/src/test/ui/impl-trait/impl-trait-in-macro.stderr b/src/test/ui/impl-trait/impl-trait-in-macro.stderr new file mode 100644 index 0000000000000..b5f9986ce4089 --- /dev/null +++ b/src/test/ui/impl-trait/impl-trait-in-macro.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/impl-trait-in-macro.rs:9:9 + | +LL | ($($tr:tt)*) => { impl $($tr)* }; + | ---- + | | + | expected type parameter + | found type parameter +... +LL | a = y; + | ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug` + | + = note: expected type parameter `impl Debug` (type parameter `impl Debug`) + found type parameter `impl Debug` (type parameter `impl Debug`) + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.rs b/src/test/ui/impl-trait/universal-two-impl-traits.rs index 1ed47d8f49ead..689c240128d80 100644 --- a/src/test/ui/impl-trait/universal-two-impl-traits.rs +++ b/src/test/ui/impl-trait/universal-two-impl-traits.rs @@ -6,4 +6,11 @@ fn foo(x: impl Debug, y: impl Debug) -> String { format!("{:?}", a) } -fn main() { } +trait S {} + +fn much_universe, U: IntoIterator>>( + _: impl Debug + Clone, +) { +} + +fn main() {}