From 3d401897d76b59c19faf0ef0544d0c4edecd8472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Tue, 30 Jun 2026 18:02:35 +0200 Subject: [PATCH 01/37] Hermit: Don't cast `i32` to `i32` --- library/std/src/sys/fs/hermit.rs | 4 ++-- library/std/src/sys/net/connection/socket/hermit.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 5f69560998293..9fdfb962ceda8 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -342,7 +342,7 @@ impl File { } let fd = unsafe { cvt(hermit_abi::open(path.as_ptr(), flags, mode))? }; - Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) })) + Ok(File(unsafe { FileDesc::from_raw_fd(fd) })) } pub fn file_attr(&self) -> io::Result { @@ -516,7 +516,7 @@ pub fn readdir(path: &Path) -> io::Result { let fd_raw = run_path_with_cstr(path, &|path| { cvt(unsafe { hermit_abi::open(path.as_ptr(), O_RDONLY | O_DIRECTORY, 0) }) })?; - let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) }; + let fd = unsafe { FileDesc::from_raw_fd(fd_raw) }; let root = path.to_path_buf(); // read all director entries diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index ba40da4035b6f..f43395ce8fd80 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -304,8 +304,8 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; - if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } + let raw = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; + if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw))) } } pub fn as_raw(&self) -> RawFd { From 87900d9adefcc65eb93c958481c996fd2545b36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Tue, 30 Jun 2026 17:32:52 +0200 Subject: [PATCH 02/37] Hermit: Inline `InnerReadDir::new` --- library/std/src/sys/fs/hermit.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 9fdfb962ceda8..947d3c0b27762 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -36,12 +36,6 @@ struct InnerReadDir { dir: Vec, } -impl InnerReadDir { - pub fn new(root: PathBuf, dir: Vec) -> Self { - Self { root, dir } - } -} - pub struct ReadDir { inner: Arc, pos: usize, @@ -551,7 +545,7 @@ pub fn readdir(path: &Path) -> io::Result { } } - Ok(ReadDir::new(InnerReadDir::new(root, vec))) + Ok(ReadDir::new(InnerReadDir { root, dir: vec })) } pub fn unlink(path: &Path) -> io::Result<()> { From 149dc77a1c5d5aab0d368788b0281fc9e22b3555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Tue, 30 Jun 2026 17:39:05 +0200 Subject: [PATCH 03/37] Hermit: Avoid unsoundness around dirent64 This is also how it is done on other platforms. --- library/std/src/sys/fs/hermit.rs | 44 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 947d3c0b27762..244e85e32f65d 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -1,4 +1,4 @@ -use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; use crate::os::hermit::ffi::OsStringExt; @@ -189,31 +189,45 @@ impl Iterator for ReadDir { return None; } - let dir = unsafe { &*(self.inner.dir.as_ptr().add(offset) as *const dirent64) }; + let entry_ptr = unsafe { self.inner.dir.as_ptr().add(offset).cast::() }; + + // The dirent64 struct is a weird imaginary thing that isn't ever supposed + // to be worked with by value. Its trailing d_name field is declared + // variously as [c_char; 256] or [c_char; 1] on different systems but + // either way that size is meaningless; only the offset of d_name is + // meaningful. The dirent64 pointers that libc returns from getdents64 are + // allowed to point to allocations smaller _or_ LARGER than implied by the + // definition of the struct. + // + // As such, we need to be even more careful with dirent64 than if its + // contents were "simply" partially initialized data. + // + // Like for uninitialized contents, converting entry_ptr to `&dirent64` + // would not be legal. However, we can use `&raw const (*entry_ptr).d_name` + // to refer the fields individually, because that operation is equivalent + // to `byte_offset` and thus does not require the full extent of `*entry_ptr` + // to be in bounds of the same allocation, only the offset of the field + // being referenced. if counter == self.pos { self.pos += 1; - // After dirent64, the file name is stored. d_reclen represents the length of the dirent64 - // plus the length of the file name. Consequently, file name has a size of d_reclen minus - // the size of dirent64. The file name is always a C string and terminated by `\0`. - // Consequently, we are able to ignore the last byte. - let name_bytes = - unsafe { CStr::from_ptr(&dir.d_name as *const _ as *const c_char).to_bytes() }; - let entry = DirEntry { + // d_name is guaranteed to be null-terminated. + let name = unsafe { CStr::from_ptr((&raw const (*entry_ptr).d_name).cast()) }; + let name_bytes = name.to_bytes(); + + return Some(Ok(DirEntry { root: self.inner.root.clone(), - ino: dir.d_ino, - type_: dir.d_type, + ino: unsafe { (*entry_ptr).d_ino }, + type_: unsafe { (*entry_ptr).d_type }, name: OsString::from_vec(name_bytes.to_vec()), - }; - - return Some(Ok(entry)); + })); } counter += 1; // move to the next dirent64, which is directly stored after the previous one - offset = offset + usize::from(dir.d_reclen); + offset = offset + unsafe { usize::from((*entry_ptr).d_reclen) }; } } } From 736fa96466592abe7227173fdfb0b967282947e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Tue, 30 Jun 2026 15:41:59 +0200 Subject: [PATCH 04/37] Hermit: Avoid cloning `InnerReadDir::root` This optimization was already partially in place, but not used. Other platforms already do this. --- library/std/src/sys/fs/hermit.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 244e85e32f65d..3bf9fb1fe2a77 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -48,8 +48,7 @@ impl ReadDir { } pub struct DirEntry { - /// path to the entry - root: PathBuf, + dir: Arc, /// 64-bit inode number ino: u64, /// File type @@ -217,7 +216,7 @@ impl Iterator for ReadDir { let name_bytes = name.to_bytes(); return Some(Ok(DirEntry { - root: self.inner.root.clone(), + dir: Arc::clone(&self.inner), ino: unsafe { (*entry_ptr).d_ino }, type_: unsafe { (*entry_ptr).d_type }, name: OsString::from_vec(name_bytes.to_vec()), @@ -234,7 +233,7 @@ impl Iterator for ReadDir { impl DirEntry { pub fn path(&self) -> PathBuf { - self.root.join(self.file_name_os_str()) + self.dir.root.join(self.file_name_os_str()) } pub fn file_name(&self) -> OsString { From 5b4b02e649886606dc68722e521b3cde4d08a3f8 Mon Sep 17 00:00:00 2001 From: sjwang05 <63834813+sjwang05@users.noreply.github.com> Date: Thu, 9 Jul 2026 02:25:34 -0700 Subject: [PATCH 05/37] avoid ICE in From/TryFrom cast diag --- .../traits/fulfillment_errors.rs | 32 ++++++++----------- .../ui/traits/explicit-reference-cast-hrtb.rs | 14 ++++++++ .../explicit-reference-cast-hrtb.stderr | 23 +++++++++++++ 3 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 tests/ui/traits/explicit-reference-cast-hrtb.rs create mode 100644 tests/ui/traits/explicit-reference-cast-hrtb.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 617ec6c4ac229..d65715d3df283 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -285,27 +285,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id)) && (self.tcx.is_diagnostic_item(sym::From, leaf_trait_def_id) || self.tcx.is_diagnostic_item(sym::TryFrom, leaf_trait_def_id)) - { - let trait_ref = leaf_trait_predicate.skip_binder().trait_ref; - - if let Some(found_ty) = + && let Some(trait_ref) = + leaf_trait_predicate.no_bound_vars().map(|pred| pred.trait_ref) + && let Some(found_ty) = trait_ref.args.get(1).and_then(|arg| arg.as_type()) - { - let ty = main_trait_predicate.skip_binder().self_ty(); + && let Some(ty) = + main_trait_predicate.no_bound_vars().map(|pred| pred.self_ty()) + && let Some(cast_ty) = + self.find_explicit_cast_type(obligation.param_env, found_ty, ty) + { + let found_ty_str = self.tcx.short_string(found_ty, &mut long_ty_file); + let cast_ty_str = self.tcx.short_string(cast_ty, &mut long_ty_file); - if let Some(cast_ty) = - self.find_explicit_cast_type(obligation.param_env, found_ty, ty) - { - let found_ty_str = - self.tcx.short_string(found_ty, &mut long_ty_file); - let cast_ty_str = - self.tcx.short_string(cast_ty, &mut long_ty_file); - - err.help(format!( - "consider casting the `{found_ty_str}` value to `{cast_ty_str}`", - )); - } - } + err.help(format!( + "consider casting the `{found_ty_str}` value to `{cast_ty_str}`", + )); } *err.long_ty_path() = long_ty_file; diff --git a/tests/ui/traits/explicit-reference-cast-hrtb.rs b/tests/ui/traits/explicit-reference-cast-hrtb.rs new file mode 100644 index 0000000000000..8714bff369b82 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-hrtb.rs @@ -0,0 +1,14 @@ +//! Regression test for #158967 + +struct Foo; + +fn f() +where + for<'a> Foo: From<&'a String>, +{ +} + +fn main() { + f(); + //~^ ERROR the trait bound `for<'a> Foo: From<&'a String>` is not satisfied [E0277] +} diff --git a/tests/ui/traits/explicit-reference-cast-hrtb.stderr b/tests/ui/traits/explicit-reference-cast-hrtb.stderr new file mode 100644 index 0000000000000..4921a87900051 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-hrtb.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `for<'a> Foo: From<&'a String>` is not satisfied + --> $DIR/explicit-reference-cast-hrtb.rs:12:5 + | +LL | f(); + | ^^^ unsatisfied trait bound + | +help: the trait `for<'a> From<&'a String>` is not implemented for `Foo` + --> $DIR/explicit-reference-cast-hrtb.rs:3:1 + | +LL | struct Foo; + | ^^^^^^^^^^ +note: required by a bound in `f` + --> $DIR/explicit-reference-cast-hrtb.rs:7:18 + | +LL | fn f() + | - required by a bound in this function +LL | where +LL | for<'a> Foo: From<&'a String>, + | ^^^^^^^^^^^^^^^^ required by this bound in `f` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From b165183b4258696610598af83ffe0f168c9937f1 Mon Sep 17 00:00:00 2001 From: chiri Date: Sat, 11 Jul 2026 14:27:12 +0300 Subject: [PATCH 06/37] a bit optimize four-digit chunks in integer formatting --- library/core/src/fmt/num.rs | 72 +++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 050822da8f12a..7523bc64942d6 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -690,15 +690,11 @@ impl u128 { unsafe { core::hint::assert_unchecked(offset <= buf.len()) } offset -= 4; - // pull two pairs let quad = remain % 1_00_00; remain /= 1_00_00; - let pair1 = (quad / 100) as usize; - let pair2 = (quad % 100) as usize; - buf[offset + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]); - buf[offset + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]); - buf[offset + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); - buf[offset + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); + // SAFETY: quad is a remainder modulo 10_000. The offset checks + // above reserve exactly four bytes in buf. + unsafe { write_quad(buf, offset, quad) }; } // Format per two digits from the lookup table. @@ -814,32 +810,64 @@ impl i128 { } } +/// Writes `quad` as exactly four digits (for example: `42` becomes `"0042"`). +/// +/// # Safety +/// +/// `quad` must be below 10_000 and `buf[offset..offset + 4]` must be in bounds. +#[inline(always)] +unsafe fn write_quad(buf: &mut [MaybeUninit], offset: usize, quad: u64) { + // SAFETY: These are this function's caller-provided invariants. + unsafe { + core::hint::assert_unchecked(quad < 10_000); + core::hint::assert_unchecked(offset <= buf.len() - 4); + } + + // For the documented range, ceil(2^19 / 100) gives an exact quotiet. + const DIV100_SHIFT: u32 = 19; + const DIV100_RECIPROCAL: u32 = (1 << DIV100_SHIFT) / 100 + 1; + + let quad = quad as u32; + let high = (quad * DIV100_RECIPROCAL) >> DIV100_SHIFT; + let low = quad - high * 100; + let high = high as usize; + let low = low as usize; + + // SAFETY: `high` and `low` are below 100 because quad is below 10_000. The + // destination has four bytes by the precondition, and the two source pairs + // are disjoint from it because `DECIMAL_PAIRS` is static RO storage. + unsafe { + let pairs = DECIMAL_PAIRS.as_ptr(); + let dst = buf.as_mut_ptr().add(offset).cast::(); + core::ptr::copy_nonoverlapping(pairs.add(high * 2), dst, 2); + core::ptr::copy_nonoverlapping(pairs.add(low * 2), dst.add(2), 2); + } +} + /// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET + /// 16 ]`. fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { - // Consume the least-significant decimals from a working copy. + // Callers pass a remainder modulo 10^16 and reserve sixteen output bytes. + unsafe { + core::hint::assert_unchecked(n < 10_000_000_000_000_000); + core::hint::assert_unchecked(OFFSET <= buf.len() - 16); + } + + // Peel four digits at a time from right to left (12345678 -> 1234 | 5678). + // Since 10_000 is constant, LLVM replaces each division with multiply or shift. let mut remain = n; - // Format per four digits from the lookup table. for quad_index in (1..4).rev() { // pull two pairs let quad = remain % 1_00_00; remain /= 1_00_00; - let pair1 = (quad / 100) as usize; - let pair2 = (quad % 100) as usize; - buf[quad_index * 4 + OFFSET + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]); - buf[quad_index * 4 + OFFSET + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]); - buf[quad_index * 4 + OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); - buf[quad_index * 4 + OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); + // SAFETY: modulo bounds quad; OFFSET and quad_index select one of the + // four non-overlapping four-byte regions proven in bounds above. + unsafe { write_quad(buf, quad_index * 4 + OFFSET, quad) }; } - // final two pairs - let pair1 = (remain / 100) as usize; - let pair2 = (remain % 100) as usize; - buf[OFFSET + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]); - buf[OFFSET + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]); - buf[OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); - buf[OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); + // SAFETY: OFFSET starts the first four-byte region proven in bounds above. + unsafe { write_quad(buf, OFFSET, remain) }; } /// Euclidean division plus remainder with constant 1E16 basically consumes 16 From 25435a0fb5db893e578c9132574661a1c40eb9d4 Mon Sep 17 00:00:00 2001 From: chiri Date: Sat, 11 Jul 2026 14:55:42 +0300 Subject: [PATCH 07/37] add SAFETY --- library/core/src/fmt/num.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 7523bc64942d6..53c3e2c60d4d2 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -847,7 +847,8 @@ unsafe fn write_quad(buf: &mut [MaybeUninit], offset: usize, quad: u64) { /// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET + /// 16 ]`. fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { - // Callers pass a remainder modulo 10^16 and reserve sixteen output bytes. + // SAFETY: Every caller passes a remainder produced by division by 10^16, + // and every used `OFFSET` specialization reserves sixteen bytes in `buf`. unsafe { core::hint::assert_unchecked(n < 10_000_000_000_000_000); core::hint::assert_unchecked(OFFSET <= buf.len() - 16); From 576d1bd01e0f4456b0459f3f4f9944c0d89bdec6 Mon Sep 17 00:00:00 2001 From: Jonathan Klimt Date: Fri, 26 Jun 2026 11:22:47 +0200 Subject: [PATCH 08/37] Hermit: Rework `getdents64` implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we read all entries into a huge initialized buffer up front, which does not work correctly since on Hermit 0.12, getdents64 behaves more reasonable and does no longer fail on buffers which cannot hold all entries. Additionally, for each new entry, we started searching for the current position from the start instead of just saving the position directly. The new design uses a fixed-size uninitialized buffer that is read into as necessary. Co-authored-by: Martin Kröning --- library/std/src/sys/fs/hermit.rs | 145 ++++++++++++++++++------------- 1 file changed, 83 insertions(+), 62 deletions(-) diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 3bf9fb1fe2a77..a3c454eaf8eb6 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -1,6 +1,7 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; +use crate::mem::MaybeUninit; use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::hermit_abi::{ self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, @@ -12,9 +13,10 @@ use crate::sync::Arc; use crate::sys::fd::FileDesc; pub use crate::sys::fs::common::{Dir, copy, exists}; use crate::sys::helpers::run_path_with_cstr; +use crate::sys::io::DEFAULT_BUF_SIZE; use crate::sys::time::SystemTime; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, unsupported, unsupported_err}; -use crate::{fmt, mem}; +use crate::{cmp, fmt, mem, slice}; #[derive(Debug)] pub struct File(FileDesc); @@ -33,17 +35,70 @@ impl FileAttr { // all DirEntry's will have a reference to this struct struct InnerReadDir { root: PathBuf, - dir: Vec, } pub struct ReadDir { inner: Arc, + fd: FileDesc, + buf: GetdentsBuffer, +} + +/// A buffer containing [`dirent64`]s, filled with [`getdents64`]. +/// +/// This struct is roughly modeled after the `BufReader`'s `Buffer`. +struct GetdentsBuffer { + // The buffer. + buf: Box<[MaybeUninit]>, + // The current seek offset into `buf`, must always be <= `filled`. pos: usize, + // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are + // initialized with bytes from a read. + filled: usize, } -impl ReadDir { - fn new(inner: InnerReadDir) -> Self { - Self { inner: Arc::new(inner), pos: 0 } +impl GetdentsBuffer { + /// Creates a new buffer with at least `capacity` bytes for use with dirent. + fn with_capacity(capacity: usize) -> Self { + let buf = Box::new_uninit_slice(capacity.div_ceil(size_of::())); + Self { buf, pos: 0, filled: 0 } + } + + fn buffer(&self) -> &[u8] { + // SAFETY: self.pos and self.filled are valid, and self.filled >= self.pos, and + // that region is initialized because those are all invariants of this type. + unsafe { + let ptr = self.buf.as_ptr().cast::>().add(self.pos); + slice::from_raw_parts(ptr, self.filled - self.pos).assume_init_ref() + } + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.filled); + } + + fn fill_buf(&mut self, fd: BorrowedFd<'_>) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.filled { + debug_assert!(self.pos == self.filled); + + let result = unsafe { + cvt(hermit_abi::getdents64( + fd.as_raw_fd(), + self.buf.as_mut_ptr().cast(), + self.buf.len() * size_of::(), + )) + }; + + self.pos = 0; + self.filled = 0; + + self.filled = result? as usize; + } + + Ok(self.buffer()) } } @@ -178,17 +233,18 @@ impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { - let mut counter: usize = 0; - let mut offset: usize = 0; - - // loop over all directory entries and search the entry for the current position loop { - // leave function, if the loop reaches the of the buffer (with all entries) - if offset >= self.inner.dir.len() { + let buf = match self.buf.fill_buf(self.fd.as_fd()) { + Ok(buf) => buf, + Err(err) => return Some(Err(err)), + }; + + if buf.len() == 0 { + // No more entries left. return None; } - let entry_ptr = unsafe { self.inner.dir.as_ptr().add(offset).cast::() }; + let entry_ptr = buf.as_ptr().cast::(); // The dirent64 struct is a weird imaginary thing that isn't ever supposed // to be worked with by value. Its trailing d_name field is declared @@ -208,25 +264,18 @@ impl Iterator for ReadDir { // to be in bounds of the same allocation, only the offset of the field // being referenced. - if counter == self.pos { - self.pos += 1; - - // d_name is guaranteed to be null-terminated. - let name = unsafe { CStr::from_ptr((&raw const (*entry_ptr).d_name).cast()) }; - let name_bytes = name.to_bytes(); - - return Some(Ok(DirEntry { - dir: Arc::clone(&self.inner), - ino: unsafe { (*entry_ptr).d_ino }, - type_: unsafe { (*entry_ptr).d_type }, - name: OsString::from_vec(name_bytes.to_vec()), - })); - } + self.buf.consume(usize::from(unsafe { (*entry_ptr).d_reclen })); - counter += 1; + // d_name is guaranteed to be null-terminated. + let name = unsafe { CStr::from_ptr((&raw const (*entry_ptr).d_name).cast()) }; + let name_bytes = name.to_bytes(); - // move to the next dirent64, which is directly stored after the previous one - offset = offset + unsafe { usize::from((*entry_ptr).d_reclen) }; + return Some(Ok(DirEntry { + dir: Arc::clone(&self.inner), + ino: unsafe { (*entry_ptr).d_ino }, + type_: unsafe { (*entry_ptr).d_type }, + name: OsString::from_vec(name_bytes.to_vec()), + })); } } } @@ -524,41 +573,13 @@ pub fn readdir(path: &Path) -> io::Result { cvt(unsafe { hermit_abi::open(path.as_ptr(), O_RDONLY | O_DIRECTORY, 0) }) })?; let fd = unsafe { FileDesc::from_raw_fd(fd_raw) }; - let root = path.to_path_buf(); - - // read all director entries - let mut vec: Vec = Vec::new(); - let mut sz = 512; - loop { - // reserve memory to receive all directory entries - vec.resize(sz, 0); - let readlen = unsafe { - hermit_abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz) - }; - if readlen > 0 { - // shrink down to the minimal size - vec.resize(readlen.try_into().unwrap(), 0); - break; - } - - // if the buffer is too small, getdents64 returns EINVAL - // otherwise, getdents64 returns an error number - if readlen != (-hermit_abi::errno::EINVAL).into() { - return Err(Error::from_raw_os_error(readlen.try_into().unwrap())); - } - - // we don't have enough memory => try to increase the vector size - sz = sz * 2; - - // 1 MB for directory entries should be enough - // stop here to avoid an endless loop - if sz > 0x100000 { - return Err(Error::from(ErrorKind::Uncategorized)); - } - } + let root = path.to_path_buf(); + let inner = Arc::new(InnerReadDir { root }); + let buf_size = usize::max(DEFAULT_BUF_SIZE, size_of::()); + let buf = GetdentsBuffer::with_capacity(buf_size); - Ok(ReadDir::new(InnerReadDir { root, dir: vec })) + Ok(ReadDir { inner, fd, buf }) } pub fn unlink(path: &Path) -> io::Result<()> { From 0229444c1f15603e9d3cf59fe487a82e95a62fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Wed, 1 Jul 2026 11:18:11 +0200 Subject: [PATCH 09/37] Hermit: Filter out `.` and `..` from `getdents64` While Hermit does not return these yet, it will do so in the future. --- library/std/src/sys/fs/hermit.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index a3c454eaf8eb6..8e1449f050274 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -269,6 +269,9 @@ impl Iterator for ReadDir { // d_name is guaranteed to be null-terminated. let name = unsafe { CStr::from_ptr((&raw const (*entry_ptr).d_name).cast()) }; let name_bytes = name.to_bytes(); + if name_bytes == b"." || name_bytes == b".." { + continue; + } return Some(Ok(DirEntry { dir: Arc::clone(&self.inner), From 551f8d4fcdcc99d3c2070fbb8ac98942752d0ef1 Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Sat, 25 Jul 2026 12:41:54 +0000 Subject: [PATCH 10/37] Add intrinsic-test alias and set test sample rate --- src/bootstrap/src/core/build_steps/test.rs | 4 ++-- .../src/core/builder/cli_paths/snapshots/x_test.snap | 1 + .../builder/cli_paths/snapshots/x_test_skip_coverage.snap | 1 + .../builder/cli_paths/snapshots/x_test_skip_coverage_map.snap | 1 + .../builder/cli_paths/snapshots/x_test_skip_coverage_run.snap | 1 + .../core/builder/cli_paths/snapshots/x_test_skip_tests.snap | 1 + .../cli_paths/snapshots/x_test_skip_tests_coverage.snap | 1 + .../builder/cli_paths/snapshots/x_test_skip_tests_etc.snap | 3 +++ 8 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 44bedaf878e04..6c6450cf1a374 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1010,7 +1010,7 @@ impl Step for IntrinsicTest { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("library/stdarch/crates/intrinsic-test") + run.path("library/stdarch/crates/intrinsic-test").alias("intrinsic-test") } fn is_default_step(_builder: &Builder<'_>) -> bool { @@ -1107,7 +1107,7 @@ impl Step for IntrinsicTest { for skip in &skip_file { cmd.arg("--skip").arg(skip); } - cmd.arg("--sample-percentage").arg("10"); + cmd.arg("--sample-percentage").arg("100"); cmd.arg("--cc-arg-style").arg("gcc"); cmd.env("CC", builder.cc(host)); cmd.env("CFLAGS", cflags); diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap index aa67ecaceabfd..2355d09f9972c 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap @@ -214,4 +214,5 @@ expression: test - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] + - Set({test::intrinsic-test}) - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap index ceb1e8c0130d9..2e9a0ae905bd9 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap @@ -211,4 +211,5 @@ expression: test --skip=coverage - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] + - Set({test::intrinsic-test}) - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap index 2f5ae46107c10..001ec080527a4 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap @@ -214,4 +214,5 @@ expression: test --skip=coverage-map - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] + - Set({test::intrinsic-test}) - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap index b19db9047540e..e535bcde35ead 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap @@ -214,4 +214,5 @@ expression: test --skip=coverage-run - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] + - Set({test::intrinsic-test}) - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap index 79a79462addbb..3250a89374d2a 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap @@ -157,4 +157,5 @@ expression: test --skip=tests - Set({test::src/tools/test-float-parse}) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] + - Set({test::intrinsic-test}) - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap index d0837ff3ce8a2..a4fd7212215b1 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap @@ -211,4 +211,5 @@ expression: test --skip=tests/coverage - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] + - Set({test::intrinsic-test}) - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap index 6aaa2a9592b0e..80dd87e9a5856 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap @@ -135,3 +135,6 @@ expression: test --skip=tests --skip=coverage-map --skip=coverage-run --skip=lib [Test] test::TestFloatParse targets: [x86_64-unknown-linux-gnu] - Set({test::src/tools/test-float-parse}) +[Test] test::IntrinsicTest + targets: [x86_64-unknown-linux-gnu] + - Set({test::intrinsic-test}) From 9894451193b9dc28f4556811a014ac7ea6e76aef Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Sat, 25 Jul 2026 17:45:31 +0000 Subject: [PATCH 11/37] skip intrinsic-test alias on LLVM 21 --- src/ci/docker/scripts/stage_2_test_set1.sh | 2 +- src/ci/docker/scripts/stage_2_test_set2.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/scripts/stage_2_test_set1.sh b/src/ci/docker/scripts/stage_2_test_set1.sh index 884e0c9cb0e88..d63f8ad773016 100755 --- a/src/ci/docker/scripts/stage_2_test_set1.sh +++ b/src/ci/docker/scripts/stage_2_test_set1.sh @@ -15,7 +15,7 @@ fi # Skip intrinsic-test on LLVM 21 to avoid CI failures. if [ "$LLVM_VERSION" = "21" ]; then echo "LLVM_VERSION is 21; skipping intrinsic-test" - SKIP_INTRINSICS="--skip library/stdarch/crates/intrinsic-test" + SKIP_INTRINSICS="--skip intrinsic-test --skip library/stdarch/crates/intrinsic-test" fi ../x.py --stage 2 test \ diff --git a/src/ci/docker/scripts/stage_2_test_set2.sh b/src/ci/docker/scripts/stage_2_test_set2.sh index 6301344f89fc9..d93e5cb55ed5d 100755 --- a/src/ci/docker/scripts/stage_2_test_set2.sh +++ b/src/ci/docker/scripts/stage_2_test_set2.sh @@ -24,7 +24,7 @@ fi # Skip intrinsic-test on LLVM 21 to avoid CI failures. if [ "$LLVM_VERSION" = "21" ]; then echo "LLVM_VERSION is 21; skipping intrinsic-test" - SKIP_INTRINSICS="--skip library/stdarch/crates/intrinsic-test" + SKIP_INTRINSICS="--skip intrinsic-test --skip library/stdarch/crates/intrinsic-test" fi ../x.py --stage 2 test \ From 6618eb62011cf486566afafb42a1e134c9b19f79 Mon Sep 17 00:00:00 2001 From: chiri Date: Tue, 28 Jul 2026 11:12:57 +0300 Subject: [PATCH 12/37] review --- library/core/src/fmt/num.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 53c3e2c60d4d2..315c2cca3f829 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -820,7 +820,7 @@ unsafe fn write_quad(buf: &mut [MaybeUninit], offset: usize, quad: u64) { // SAFETY: These are this function's caller-provided invariants. unsafe { core::hint::assert_unchecked(quad < 10_000); - core::hint::assert_unchecked(offset <= buf.len() - 4); + core::hint::assert_unchecked(offset + 4 <= buf.len()); } // For the documented range, ceil(2^19 / 100) gives an exact quotiet. @@ -851,7 +851,7 @@ fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { // and every used `OFFSET` specialization reserves sixteen bytes in `buf`. unsafe { core::hint::assert_unchecked(n < 10_000_000_000_000_000); - core::hint::assert_unchecked(OFFSET <= buf.len() - 16); + core::hint::assert_unchecked(OFFSET + 16 <= buf.len()); } // Peel four digits at a time from right to left (12345678 -> 1234 | 5678). From 20ec372d195698fb9a68c5a21f75307f626adeac Mon Sep 17 00:00:00 2001 From: chiri Date: Tue, 28 Jul 2026 11:18:23 +0300 Subject: [PATCH 13/37] Update library/core/src/fmt/num.rs Co-authored-by: Clar Fon <15850505+clarfonthey@users.noreply.github.com> --- library/core/src/fmt/num.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 315c2cca3f829..bb6006f86df52 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -823,12 +823,9 @@ unsafe fn write_quad(buf: &mut [MaybeUninit], offset: usize, quad: u64) { core::hint::assert_unchecked(offset + 4 <= buf.len()); } - // For the documented range, ceil(2^19 / 100) gives an exact quotiet. - const DIV100_SHIFT: u32 = 19; - const DIV100_RECIPROCAL: u32 = (1 << DIV100_SHIFT) / 100 + 1; - let quad = quad as u32; - let high = (quad * DIV100_RECIPROCAL) >> DIV100_SHIFT; + // Note: this is equivalent to `quad / 100`, but contains no division instructions + let high = (quad * const { (1 << 19) / 100 + 1 }) >> 19; let low = quad - high * 100; let high = high as usize; let low = low as usize; From c10ff542ea713c9897837107ac30848271360eff Mon Sep 17 00:00:00 2001 From: chiri Date: Tue, 28 Jul 2026 11:39:50 +0300 Subject: [PATCH 14/37] review (x3) --- library/core/src/fmt/num.rs | 41 ++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index bb6006f86df52..9c3d5adb8fe23 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -694,7 +694,9 @@ impl u128 { remain /= 1_00_00; // SAFETY: quad is a remainder modulo 10_000. The offset checks // above reserve exactly four bytes in buf. - unsafe { write_quad(buf, offset, quad) }; + unsafe { + write_quad(buf.get_unchecked_mut(offset..offset + 4), quad); + } } // Format per two digits from the lookup table. @@ -814,28 +816,30 @@ impl i128 { /// /// # Safety /// -/// `quad` must be below 10_000 and `buf[offset..offset + 4]` must be in bounds. +/// `quad` must be below 10_000 and `buf` must contain exactly four bytes. #[inline(always)] -unsafe fn write_quad(buf: &mut [MaybeUninit], offset: usize, quad: u64) { +unsafe fn write_quad(buf: &mut [MaybeUninit], quad: u64) { // SAFETY: These are this function's caller-provided invariants. unsafe { core::hint::assert_unchecked(quad < 10_000); - core::hint::assert_unchecked(offset + 4 <= buf.len()); + core::hint::assert_unchecked(buf.len() == 4); } let quad = quad as u32; - // Note: this is equivalent to `quad / 100`, but contains no division instructions + + // Note: this is equivalent to `quad / 100`, but contains no division instructions. let high = (quad * const { (1 << 19) / 100 + 1 }) >> 19; let low = quad - high * 100; let high = high as usize; let low = low as usize; - // SAFETY: `high` and `low` are below 100 because quad is below 10_000. The - // destination has four bytes by the precondition, and the two source pairs - // are disjoint from it because `DECIMAL_PAIRS` is static RO storage. + // SAFETY: `high` and `low` are below 100 because `quad` is below 10_000. + // The destination has four bytes by the precondition, and the two source + // pairs are disjoint from it because `DECIMAL_PAIRS` is static RO storage. unsafe { let pairs = DECIMAL_PAIRS.as_ptr(); - let dst = buf.as_mut_ptr().add(offset).cast::(); + let dst = buf.as_mut_ptr().cast::(); + core::ptr::copy_nonoverlapping(pairs.add(high * 2), dst, 2); core::ptr::copy_nonoverlapping(pairs.add(low * 2), dst.add(2), 2); } @@ -856,16 +860,25 @@ fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { let mut remain = n; for quad_index in (1..4).rev() { - // pull two pairs let quad = remain % 1_00_00; remain /= 1_00_00; - // SAFETY: modulo bounds quad; OFFSET and quad_index select one of the - // four non-overlapping four-byte regions proven in bounds above. - unsafe { write_quad(buf, quad_index * 4 + OFFSET, quad) }; + + // SAFETY: `OFFSET + quad_index * 4` starts one of the four + // non-overlapping four-byte regions proven in bounds above. + unsafe { + write_quad( + buf.get_unchecked_mut( + OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4, + ), + quad, + ); + } } // SAFETY: OFFSET starts the first four-byte region proven in bounds above. - unsafe { write_quad(buf, OFFSET, remain) }; + unsafe { + write_quad(buf.get_unchecked_mut(OFFSET..OFFSET + 4), remain); + } } /// Euclidean division plus remainder with constant 1E16 basically consumes 16 From dedf120b21c6dd0c0531c99201592cd1bef36756 Mon Sep 17 00:00:00 2001 From: chiri Date: Tue, 28 Jul 2026 11:46:35 +0300 Subject: [PATCH 15/37] fix tidy --- library/core/src/fmt/num.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 9c3d5adb8fe23..7398c9b40b19d 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -867,9 +867,7 @@ fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { // non-overlapping four-byte regions proven in bounds above. unsafe { write_quad( - buf.get_unchecked_mut( - OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4, - ), + buf.get_unchecked_mut(OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4), quad, ); } From ab3e64f0803cc633551f8482a7bed70982622c23 Mon Sep 17 00:00:00 2001 From: SzilvasiPeter Date: Tue, 28 Jul 2026 09:50:31 +0200 Subject: [PATCH 16/37] test: add test suite for the 85681 issue fix: give reason before the issue number --- ...ssage-impl-trait-double-ref-issue-85681.rs | 13 +++++++++++ ...e-impl-trait-double-ref-issue-85681.stderr | 23 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs create mode 100644 tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr diff --git a/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs new file mode 100644 index 0000000000000..cce714757cc62 --- /dev/null +++ b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs @@ -0,0 +1,13 @@ +fn foo(_x: u32, a: impl Into, _y: u32, b: impl Into) { + println!("fox: a={}, b={}", a.into(), b.into()); +} + +fn main() { + let bar: String = "bar".to_string(); + let baz: &str = "baz"; + + for (a, b) in &[(&bar, baz)] { + let a: &String = a; + foo(42, a, 43, b); //~ ERROR: the trait bound `String: From<&&str>` is not satisfied [E0277] + } +} diff --git a/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr new file mode 100644 index 0000000000000..422660d580efc --- /dev/null +++ b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `String: From<&&str>` is not satisfied + --> $DIR/bad-error-message-impl-trait-double-ref-issue-85681.rs:11:24 + | +LL | foo(42, a, 43, b); + | --- ^ the trait `From<&&str>` is not implemented for `String` + | | + | required by a bound introduced by this call + | + = help: consider casting the `&&str` value to `&str` + = note: required for `&&str` to implement `Into` +note: required by a bound in `foo` + --> $DIR/bad-error-message-impl-trait-double-ref-issue-85681.rs:1:56 + | +LL | fn foo(_x: u32, a: impl Into, _y: u32, b: impl Into) { + | ^^^^^^^^^^^^ required by this bound in `foo` +help: consider dereferencing here + | +LL | foo(42, a, 43, *b); + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 66f3da078621a44bf504cbb472146c2b7513eae5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 28 Jul 2026 10:25:53 -0700 Subject: [PATCH 17/37] Refactor `missing_items_err`: factor out function to find suggestion span `missing_items_err` has logic to figure out where in the impl to insert suggestions. Factor that logic out into a function to support reusing it. --- .../rustc_hir_analysis/src/check/check.rs | 3 +- compiler/rustc_hir_analysis/src/check/mod.rs | 34 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 626529cb6fc5b..2cad6a1f5a2d8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1436,8 +1436,7 @@ fn check_impl_items_against_trait<'tcx>( } if !missing_items.is_empty() { - let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id)); - missing_items_err(tcx, impl_id, &missing_items, full_impl_span); + missing_items_err(tcx, impl_id, &missing_items); } if let Some(missing_items) = must_implement_one_of { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index a3bdd0bae7e77..e6b22bd22a883 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -203,22 +203,9 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef } } -fn missing_items_err( - tcx: TyCtxt<'_>, - impl_def_id: LocalDefId, - missing_items: &[ty::AssocItem], - full_impl_span: Span, -) { - let missing_items = - missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait()); - - let missing_items_msg = missing_items - .clone() - .map(|trait_item| trait_item.name().to_string()) - .collect::>() - .join("`, `"); - - let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span) +fn impl_suggestion_span(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) -> Span { + let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_def_id)); + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span) && snippet.ends_with("}") { // `Span` before impl block closing brace. @@ -228,7 +215,20 @@ fn missing_items_err( full_impl_span.with_lo(hi).with_hi(hi) } else { full_impl_span.shrink_to_hi() - }; + } +} + +fn missing_items_err(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ty::AssocItem]) { + let missing_items = + missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait()); + + let missing_items_msg = missing_items + .clone() + .map(|trait_item| trait_item.name().to_string()) + .collect::>() + .join("`, `"); + + let sugg_sp = impl_suggestion_span(tcx, impl_def_id); // Obtain the level of indentation ending in `sugg_sp`. let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new); From 6640449d6e28bd6866aa2274fa55e46855955bd6 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 28 Jul 2026 16:00:18 -0700 Subject: [PATCH 18/37] Refactor `missing_items_err`: factor out function to find suggestions `missing_items_err` has logic to compute a set of suggestions regarding the missing items. Factor that logic out into a function to support reusing it. --- compiler/rustc_hir_analysis/src/check/mod.rs | 21 +++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index e6b22bd22a883..ac9af13ed5078 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -103,6 +103,9 @@ use tracing::debug; use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys; use self::region::region_scope_tree; +use crate::diagnostics::{ + MissingTraitItemLabel, MissingTraitItemSuggestion, MissingTraitItemSuggestionNone, +}; use crate::{check_c_variadic_abi, diagnostics}; /// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`] @@ -218,7 +221,16 @@ fn impl_suggestion_span(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) -> Span { } } -fn missing_items_err(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ty::AssocItem]) { +fn missing_items_suggestions( + tcx: TyCtxt<'_>, + impl_def_id: LocalDefId, + missing_items: &[ty::AssocItem], +) -> ( + String, + Vec, + Vec, + Vec, +) { let missing_items = missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait()); @@ -259,6 +271,13 @@ fn missing_items_err(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ } } + (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) +} + +fn missing_items_err(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ty::AssocItem]) { + let (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) = + missing_items_suggestions(tcx, impl_def_id, missing_items); + tcx.dcx().emit_err(diagnostics::MissingTraitItem { span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(), missing_items_msg, From 740230baafffdc4b27f8a9afab9fa7dbf1fa9ef1 Mon Sep 17 00:00:00 2001 From: Gaurav Kamathe Date: Wed, 29 Jul 2026 11:14:15 +0530 Subject: [PATCH 19/37] Remove unnecessary format --- .../src/error_reporting/infer/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 0af41423b846a..57f1a9788c20c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1366,8 +1366,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if kind1 == kind2 && alias1 == alias2 && !self.tcx.sess.opts.verbose => { let mut strs = (DiagStyledString::new(), DiagStyledString::new()); - strs.0.push_normal(format!("_")); - strs.1.push_normal(format!("_")); + strs.0.push_normal("_"); + strs.1.push_normal("_"); strs } @@ -1376,14 +1376,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { match (alias1.kind, alias2.kind) { (ty::Projection { def_id: def_id1 }, ty::Projection { def_id: def_id2 }) => { // `::Name` - values.0.push_normal(format!("<")); - values.1.push_normal(format!("<")); + values.0.push_normal("<"); + values.1.push_normal("<"); let (trait_ref1, args1) = alias1.trait_ref_and_own_args(self.tcx); let (trait_ref2, args2) = alias2.trait_ref_and_own_args(self.tcx); self.recurse(trait_ref1.self_ty(), trait_ref2.self_ty(), &mut values); - values.0.push_normal(format!(" as ")); - values.1.push_normal(format!(" as ")); + values.0.push_normal(" as "); + values.1.push_normal(" as "); if trait_ref1.def_id == trait_ref2.def_id { if self.tcx.sess.opts.verbose { values @@ -1414,8 +1414,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .1 .push_highlighted(format!("{}", trait_ref2.print_trait_sugared())); } - values.0.push_normal(format!(">::")); - values.1.push_normal(format!(">::")); + values.0.push_normal(">::"); + values.1.push_normal(">::"); let name1 = self.tcx.item_name(def_id1); let name2 = self.tcx.item_name(def_id2); if def_id1 == def_id2 { From 917aa16059e3f0d9d4be7077f3fc4a4a5df7fea3 Mon Sep 17 00:00:00 2001 From: chiri Date: Wed, 29 Jul 2026 11:10:07 +0300 Subject: [PATCH 20/37] review --- library/core/src/fmt/num.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 7398c9b40b19d..d703b817b5a25 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -838,7 +838,7 @@ unsafe fn write_quad(buf: &mut [MaybeUninit], quad: u64) { // pairs are disjoint from it because `DECIMAL_PAIRS` is static RO storage. unsafe { let pairs = DECIMAL_PAIRS.as_ptr(); - let dst = buf.as_mut_ptr().cast::(); + let dst = buf.as_mut_ptr().cast_init(); core::ptr::copy_nonoverlapping(pairs.add(high * 2), dst, 2); core::ptr::copy_nonoverlapping(pairs.add(low * 2), dst.add(2), 2); From af98396a161e714ff6f8aae8976f012bed99da89 Mon Sep 17 00:00:00 2001 From: chiri Date: Wed, 29 Jul 2026 11:27:34 +0300 Subject: [PATCH 21/37] review (x2) --- library/core/src/fmt/num.rs | 52 ++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index d703b817b5a25..f94e5433a5183 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -692,11 +692,12 @@ impl u128 { let quad = remain % 1_00_00; remain /= 1_00_00; - // SAFETY: quad is a remainder modulo 10_000. The offset checks - // above reserve exactly four bytes in buf. - unsafe { - write_quad(buf.get_unchecked_mut(offset..offset + 4), quad); - } + + write_quad( + // SAFETY: `offset >= 4` was asserted above. + unsafe { buf.get_unchecked_mut(offset..offset + 4) }, + quad, + ); } // Format per two digits from the lookup table. @@ -813,12 +814,8 @@ impl i128 { } /// Writes `quad` as exactly four digits (for example: `42` becomes `"0042"`). -/// -/// # Safety -/// -/// `quad` must be below 10_000 and `buf` must contain exactly four bytes. #[inline(always)] -unsafe fn write_quad(buf: &mut [MaybeUninit], quad: u64) { +fn write_quad(buf: &mut [MaybeUninit], quad: u64) { // SAFETY: These are this function's caller-provided invariants. unsafe { core::hint::assert_unchecked(quad < 10_000); @@ -834,15 +831,10 @@ unsafe fn write_quad(buf: &mut [MaybeUninit], quad: u64) { let low = low as usize; // SAFETY: `high` and `low` are below 100 because `quad` is below 10_000. - // The destination has four bytes by the precondition, and the two source - // pairs are disjoint from it because `DECIMAL_PAIRS` is static RO storage. - unsafe { - let pairs = DECIMAL_PAIRS.as_ptr(); - let dst = buf.as_mut_ptr().cast_init(); + unsafe { core::hint::assert_unchecked(high < 100 && low < 100) } - core::ptr::copy_nonoverlapping(pairs.add(high * 2), dst, 2); - core::ptr::copy_nonoverlapping(pairs.add(low * 2), dst.add(2), 2); - } + buf[0..2].write_copy_of_slice(&DECIMAL_PAIRS[high * 2..high * 2 + 2]); + buf[2..4].write_copy_of_slice(&DECIMAL_PAIRS[low * 2..low * 2 + 2]); } /// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET + @@ -863,20 +855,20 @@ fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { let quad = remain % 1_00_00; remain /= 1_00_00; - // SAFETY: `OFFSET + quad_index * 4` starts one of the four - // non-overlapping four-byte regions proven in bounds above. - unsafe { - write_quad( - buf.get_unchecked_mut(OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4), - quad, - ); - } + write_quad( + // SAFETY: `OFFSET + 16 <= buf.len()` and `quad_index < 4`, so this range is within `buf`. + unsafe { + buf.get_unchecked_mut(OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4) + }, + quad, + ); } - // SAFETY: OFFSET starts the first four-byte region proven in bounds above. - unsafe { - write_quad(buf.get_unchecked_mut(OFFSET..OFFSET + 4), remain); - } + write_quad( + // SAFETY: `OFFSET + 16 <= buf.len()` was asserted above. + unsafe { buf.get_unchecked_mut(OFFSET..OFFSET + 4) }, + remain, + ); } /// Euclidean division plus remainder with constant 1E16 basically consumes 16 From bf8708efd809273b6e55d57a7510dd1b81fc02d8 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 28 Jul 2026 14:48:51 -0700 Subject: [PATCH 22/37] Add suggestions for `must_implement_one_of` As with the suggestions for mandatory trait methods, provide suggestions for `must_implement_one_of`, which include the signatures of the trait methods. This makes it easy to copy-paste the signatures into the impl block. Invoke the same logic from `check_drop_xor_pin_drop`, to provide suggestions with the signatures of `drop` and `pin_drop`. Without this change: ``` error[E0046]: not all trait items implemented, missing one of: `read`, `read_buf` --> src/main.rs:3:1 | 3 | impl std::io::Read for R { | ^^^^^^^^^^^^^^^^^^^^^^^^ missing one of `read`, `read_buf` in implementation For more information about this error, try `rustc --explain E0046`. ``` With this change: ``` error[E0046]: not all trait items implemented, missing one of: `read`, `read_buf` --> src/main.rs:3:1 | 3 | impl std::io::Read for R { | ^^^^^^^^^^^^^^^^^^^^^^^^ missing one of `read`, `read_buf` in implementation | = help: implement the missing item: `fn read(&mut self, _: &mut [u8]) -> Result { todo!() }` = help: implement the missing item: `fn read_buf(&mut self, _: BorrowedCursor<'_, u8>) -> Result<(), std::io::Error> { todo!() }` For more information about this error, try `rustc --explain E0046`. ``` --- .../src/check/always_applicable.rs | 12 +++++---- .../rustc_hir_analysis/src/check/check.rs | 9 ++----- compiler/rustc_hir_analysis/src/check/mod.rs | 25 +++++++++++++------ .../rustc_hir_analysis/src/diagnostics.rs | 6 +++++ .../pin-ergonomics/pinned-drop-check.stderr | 6 +++++ .../rustc_must_implement_one_of.stderr | 6 +++++ 6 files changed, 45 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index 9a8008214ed04..71d9b4da64218 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -16,6 +16,7 @@ use rustc_span::sym; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; +use crate::check::missing_items_must_implement_one_of_err; use crate::diagnostics; use crate::hir::def_id::{DefId, LocalDefId}; @@ -394,11 +395,12 @@ fn check_drop_xor_pin_drop<'tcx>( match (drop_span, pin_drop_span) { (None, None) => { if tcx.features().pin_ergonomics() { - return Err(tcx.dcx().emit_err(crate::diagnostics::MissingOneOfTraitItem { - span: tcx.def_span(drop_impl_did), - note: None, - missing_items_msg: "drop`, `pin_drop".to_string(), - })); + return Err(missing_items_must_implement_one_of_err( + tcx, + drop_impl_did, + [sym::drop, sym::pin_drop].into_iter(), + None, + )); } else { return Err(tcx .dcx() diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 2cad6a1f5a2d8..f08541b2dc5d8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1441,13 +1441,8 @@ fn check_impl_items_against_trait<'tcx>( if let Some(missing_items) = must_implement_one_of { let attr_span = find_attr!(tcx, trait_ref.def_id, RustcMustImplementOneOf {attr_span, ..} => *attr_span); - - missing_items_must_implement_one_of_err( - tcx, - tcx.def_span(impl_id), - missing_items, - attr_span, - ); + let missing_items = missing_items.into_iter().map(|i| i.name); + missing_items_must_implement_one_of_err(tcx, impl_id, missing_items, attr_span); } } } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index ac9af13ed5078..2da1f8ed43b1c 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -289,18 +289,29 @@ fn missing_items_err(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ fn missing_items_must_implement_one_of_err( tcx: TyCtxt<'_>, - impl_span: Span, - missing_items: &[Ident], + impl_def_id: LocalDefId, + missing_items: impl Iterator, annotation_span: Option, -) { - let missing_items_msg = - missing_items.iter().map(Ident::to_string).collect::>().join("`, `"); +) -> ErrorGuaranteed { + // Look up the associated items so we can use them to emit better errors. + let trait_def_id = tcx.impl_trait_id(impl_def_id); + let assoc_items = tcx.associated_items(trait_def_id); + let missing_items = missing_items + .flat_map(|s| assoc_items.filter_by_name_unhygienic_and_kind(s, ty::AssocTag::Fn)) + .cloned() + .collect::>(); + + let (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) = + missing_items_suggestions(tcx, impl_def_id, &missing_items); tcx.dcx().emit_err(diagnostics::MissingOneOfTraitItem { - span: impl_span, + span: tcx.def_span(impl_def_id), note: annotation_span, missing_items_msg, - }); + missing_trait_item_label, + missing_trait_item, + missing_trait_item_none, + }) } fn default_body_is_unstable( diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index 0ea353cf14cee..eb0dcb3a346b2 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -966,6 +966,12 @@ pub(crate) struct MissingOneOfTraitItem { pub span: Span, #[note("required because of this annotation")] pub note: Option, + #[subdiagnostic] + pub missing_trait_item_label: Vec, + #[subdiagnostic] + pub missing_trait_item: Vec, + #[subdiagnostic] + pub missing_trait_item_none: Vec, pub missing_items_msg: String, } diff --git a/tests/ui/pin-ergonomics/pinned-drop-check.stderr b/tests/ui/pin-ergonomics/pinned-drop-check.stderr index 3a848c66578b4..3dc6e18a9178e 100644 --- a/tests/ui/pin-ergonomics/pinned-drop-check.stderr +++ b/tests/ui/pin-ergonomics/pinned-drop-check.stderr @@ -71,12 +71,18 @@ error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop | LL | impl Drop for Foo {} | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = help: implement the missing item: `fn pin_drop(self: Pin<&mut Self>) { todo!() }` error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` --> $DIR/pinned-drop-check.rs:60:5 | LL | impl Drop for Bar {} | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = help: implement the missing item: `fn pin_drop(self: Pin<&mut Self>) { todo!() }` error: `Bar` must implement `pin_drop` --> $DIR/pinned-drop-check.rs:87:9 diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr b/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr index 7ad10cfce984f..9868cf8faa084 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr @@ -1,6 +1,12 @@ error[E0046]: not all trait items implemented, missing one of: `eq`, `neq` --> $DIR/rustc_must_implement_one_of.rs:41:1 | +LL | fn eq(&self, other: &Self) -> bool { + | ---------------------------------- `eq` from trait +... +LL | fn neq(&self, other: &Self) -> bool { + | ----------------------------------- `neq` from trait +... LL | impl Equal for T3 {} | ^^^^^^^^^^^^^^^^^ missing one of `eq`, `neq` in implementation | From 50d66b9bed55ca50ae51aedbe7a14a1d88d02fd5 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Wed, 29 Jul 2026 11:17:18 +0200 Subject: [PATCH 23/37] Work around Wine bug 60084 by calling WSAStartup at most once CC [Wine bug 60084](https://bugs.winehq.org/show_bug.cgi?id=60084) CC https://github.com/tokio-rs/mio/issues/1980 Wine's `WSAStartup`/`WSACleanup` are currently not thread-safe (though they probably should be, which is why I reported an upstream bug). Before https://github.com/rust-lang/rust/pull/141809 (and Rust 1.90), Rust used to call `WSAStartup` at most once. This PR restores that behavior. I believe that this is not a regression for real Windows, since the hot path of a `Once` already having executed is well-optimized, it's just one atomic load, like before. --- library/std/src/sys/pal/windows/winsock.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/pal/windows/winsock.rs b/library/std/src/sys/pal/windows/winsock.rs index b110a43ef3aa8..7b2e7fe59171c 100644 --- a/library/std/src/sys/pal/windows/winsock.rs +++ b/library/std/src/sys/pal/windows/winsock.rs @@ -1,18 +1,17 @@ use super::c; use crate::ffi::c_int; -use crate::sync::atomic::Atomic; -use crate::sync::atomic::Ordering::{AcqRel, Relaxed}; +use crate::sync::Once; use crate::{io, mem}; -static WSA_STARTED: Atomic = Atomic::::new(false); +static WSA_INIT: Once = Once::new(); /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. #[inline] pub fn startup() { - if !WSA_STARTED.load(Relaxed) { - wsa_startup(); - } + // Make sure to only call `WSAStartup` once, because it's not thread-safe + // on Wine: https://bugs.winehq.org/show_bug.cgi?id=60084. + WSA_INIT.call_once_force(|_| wsa_startup()); } #[cold] @@ -24,11 +23,6 @@ fn wsa_startup() { &mut data, ); assert_eq!(ret, 0); - if WSA_STARTED.swap(true, AcqRel) { - // If another thread raced with us and called WSAStartup first then call - // WSACleanup so it's as though WSAStartup was only called once. - c::WSACleanup(); - } } } From 51b4904440f883d3e95ed3ac472e501373c1bbba Mon Sep 17 00:00:00 2001 From: Xuyang Zhang Date: Wed, 29 Jul 2026 19:18:10 +0800 Subject: [PATCH 24/37] bootstrap: remove use-lld config alias --- src/bootstrap/src/core/config/config.rs | 10 +--------- src/bootstrap/src/core/config/tests.rs | 10 ---------- src/bootstrap/src/core/config/toml/rust.rs | 3 --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 6cc2811c15f3b..b3ed7d4c6beb7 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -607,7 +607,6 @@ impl Config { stack_protector: rust_stack_protector, strip: rust_strip, bootstrap_override_lld: rust_bootstrap_override_lld, - bootstrap_override_lld_legacy: rust_bootstrap_override_lld_legacy, std_features: rust_std_features, break_on_ice: rust_break_on_ice, rustflags: rust_rustflags, @@ -717,14 +716,7 @@ impl Config { let pgo_rustdoc = init_pgo(pgo_rustdoc, "rustdoc"); let pgo_cargo = init_pgo(pgo_cargo, "cargo"); - if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() { - panic!( - "Cannot use both `rust.use-lld` and `rust.bootstrap-override-lld`. Please use only `rust.bootstrap-override-lld`" - ); - } - - let bootstrap_override_lld = - rust_bootstrap_override_lld.or(rust_bootstrap_override_lld_legacy).unwrap_or_default(); + let bootstrap_override_lld = rust_bootstrap_override_lld.unwrap_or_default(); if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { eprintln!( diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index d84315d87e45a..d179d0713fcda 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -252,16 +252,6 @@ fn rust_lld() { parse("rust.bootstrap-override-lld = false").bootstrap_override_lld, BootstrapOverrideLld::None )); - - // Also check the legacy options - assert!(matches!( - parse("rust.use-lld = true").bootstrap_override_lld, - BootstrapOverrideLld::External - )); - assert!(matches!( - parse("rust.use-lld = false").bootstrap_override_lld, - BootstrapOverrideLld::None - )); } #[test] diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index fa4573ef1734f..f8f383ef18e73 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -51,8 +51,6 @@ define_config! { llvm_bitcode_linker: Option = "llvm-bitcode-linker", lld: Option = "lld", bootstrap_override_lld: Option = "bootstrap-override-lld", - // FIXME: Remove this option in Spring 2026 - bootstrap_override_lld_legacy: Option = "use-lld", llvm_tools: Option = "llvm-tools", deny_warnings: Option = "deny-warnings", backtrace_on_ice: Option = "backtrace-on-ice", @@ -385,7 +383,6 @@ pub fn check_incompatible_options_for_ci_rustc( break_on_ice: _, parallel_frontend_threads: _, bootstrap_override_lld: _, - bootstrap_override_lld_legacy: _, rustflags: _, } = ci_rust_config; diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 062310cc351a7..8892832037ee2 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -661,4 +661,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Obsolete option `build.compiletest-use-stage0-libtest` has no effect and has been removed.", }, + ChangeInfo { + change_id: 160142, + severity: ChangeSeverity::Warning, + summary: "The `rust.use-lld` option has been removed. Use `rust.bootstrap-override-lld` instead.", + }, ]; From 31918e4eddbf5180ee64a0af563d3c3134806e42 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 29 Jul 2026 14:18:32 +0200 Subject: [PATCH 25/37] Rename `rustc_codegen_gcc/errors.rs` into `rustc_codegen_gcc/diagnostics.rs` --- compiler/rustc_codegen_gcc/src/asm.rs | 2 +- compiler/rustc_codegen_gcc/src/back/lto.rs | 2 +- compiler/rustc_codegen_gcc/src/back/write.rs | 2 +- compiler/rustc_codegen_gcc/src/builder.rs | 4 ++-- compiler/rustc_codegen_gcc/src/{errors.rs => diagnostics.rs} | 0 compiler/rustc_codegen_gcc/src/lib.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename compiler/rustc_codegen_gcc/src/{errors.rs => diagnostics.rs} (100%) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 23aeb1e06463c..ee0cef350b42f 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -22,7 +22,7 @@ use rustc_target::asm::*; use crate::builder::Builder; use crate::callee::get_fn; use crate::context::CodegenCx; -use crate::errors::{NulBytesInAsm, UnwindingInlineAsm}; +use crate::diagnostics::{NulBytesInAsm, UnwindingInlineAsm}; use crate::type_of::LayoutGccExt; // Rust asm! and GCC Extended Asm semantics differ substantially. diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 7166ad8b1f17f..98f9abdb05c4c 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -35,7 +35,7 @@ use rustc_log::tracing::info; use tempfile::{TempDir, tempdir}; use crate::back::write::{codegen, save_temp_bitcode}; -use crate::errors::LtoBitcodeFromRlib; +use crate::diagnostics::LtoBitcodeFromRlib; use crate::{GccCodegenBackend, GccContext, LtoMode, to_gcc_opt_level}; struct LtoData { diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 8fd38a2efd600..cf5514412f745 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -12,7 +12,7 @@ use rustc_session::config::OutputType; use rustc_target::spec::SplitDebuginfo; use crate::base::add_pic_option; -use crate::errors::CopyBitcode; +use crate::diagnostics::CopyBitcode; use crate::{GccContext, LtoMode}; pub(crate) fn codegen( diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 7671d2e026b03..a407362638f10 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -36,7 +36,7 @@ use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use crate::abi::FnAbiGccExt; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; -use crate::errors; +use crate::diagnostics; use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; @@ -1803,7 +1803,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _instance: Option>, ) { // FIXME: implement support for explicit tail calls like rustc_codegen_llvm. - self.tcx.dcx().emit_fatal(errors::ExplicitTailCallsUnsupported); + self.tcx.dcx().emit_fatal(diagnostics::ExplicitTailCallsUnsupported); } fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/diagnostics.rs similarity index 100% rename from compiler/rustc_codegen_gcc/src/errors.rs rename to compiler/rustc_codegen_gcc/src/diagnostics.rs diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 4cc4a2d258d14..55c721a9706a6 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -59,7 +59,7 @@ mod context; mod coverageinfo; mod debuginfo; mod declare; -mod errors; +mod diagnostics; mod gcc_util; mod int; mod intrinsic; From 62295450e43dcf1b6eb3e356f2c3f17577e5e53d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 29 Jul 2026 14:25:30 +0200 Subject: [PATCH 26/37] Rename `rustc_codegen_llvm/errors.rs` into `rustc_codegen_llvm/diagnostics.rs` --- compiler/rustc_codegen_llvm/src/attributes.rs | 2 +- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 +- .../src/back/owned_target_machine.rs | 2 +- compiler/rustc_codegen_llvm/src/back/write.rs | 12 ++++++------ compiler/rustc_codegen_llvm/src/consts.rs | 2 +- compiler/rustc_codegen_llvm/src/context.rs | 2 +- .../src/{errors.rs => diagnostics.rs} | 0 compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 7 ++++--- compiler/rustc_codegen_llvm/src/llvm_util.rs | 5 +++-- compiler/rustc_codegen_llvm/src/mono_item.rs | 2 +- 11 files changed, 20 insertions(+), 18 deletions(-) rename compiler/rustc_codegen_llvm/src/{errors.rs => diagnostics.rs} (100%) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 1f00e47a89927..a4176a8feb0f9 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -16,7 +16,7 @@ use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, Stack use smallvec::SmallVec; use crate::context::SimpleCx; -use crate::errors::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; +use crate::diagnostics::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; use crate::llvm::AttributePlace::Function; use crate::llvm::{ self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects, Value, diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index b2d22876c1858..75d9be033a5ef 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -28,7 +28,7 @@ use crate::back::write::{ self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, codegen, save_temp_bitcode, }; -use crate::errors::{LlvmError, LtoBitcodeFromRlib}; +use crate::diagnostics::{LlvmError, LtoBitcodeFromRlib}; use crate::llvm::{self, build_string}; use crate::{LlvmCodegenBackend, ModuleLlvm}; diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 65cf4cad24bd6..350d4ce9ee331 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; use rustc_data_structures::small_c_str::SmallCStr; -use crate::errors::LlvmError; +use crate::diagnostics::LlvmError; use crate::llvm; /// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions. diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 6a0f4fa6d54d2..94883a94f089a 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -34,7 +34,7 @@ use crate::back::profiling::{ use crate::builder::SBuilder; use crate::builder::gpu_offload::scalar_width; use crate::common::AsCCharPtr; -use crate::errors::{ +use crate::diagnostics::{ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, ParseTargetMachineConfig, UnsupportedCompression, WithLlvmError, WriteBytecode, }; @@ -819,7 +819,7 @@ pub(crate) unsafe fn llvm_optimize( device_out_c.as_ptr(), ); if !ok || !device_out.exists() { - dcx.emit_err(crate::errors::OffloadBundleImagesFailed); + dcx.emit_err(crate::diagnostics::OffloadBundleImagesFailed); } } } @@ -837,15 +837,15 @@ pub(crate) unsafe fn llvm_optimize( { let device_pathbuf = PathBuf::from(device_path); if device_pathbuf.is_relative() { - dcx.emit_err(crate::errors::OffloadWithoutAbsPath); + dcx.emit_err(crate::diagnostics::OffloadWithoutAbsPath); } else if device_pathbuf .file_name() .and_then(|n| n.to_str()) .is_some_and(|n| n != "device.bin") { - dcx.emit_err(crate::errors::OffloadWrongFileName); + dcx.emit_err(crate::diagnostics::OffloadWrongFileName); } else if !device_pathbuf.exists() { - dcx.emit_err(crate::errors::OffloadNonexistingPath); + dcx.emit_err(crate::diagnostics::OffloadNonexistingPath); } let host_path = cgcx.output_filenames.path(OutputType::Object); let host_dir = host_path.parent().unwrap(); @@ -859,7 +859,7 @@ pub(crate) unsafe fn llvm_optimize( let ok = unsafe { llvm::LLVMRustOffloadEmbedBufferInModule(llmod2, device_bin_c.as_ptr()) }; if !ok { - dcx.emit_err(crate::errors::OffloadEmbedFailed); + dcx.emit_err(crate::diagnostics::OffloadEmbedFailed); } write_output_file( dcx, diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 8f87acaf675a4..ee752373ceca4 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -21,7 +21,7 @@ use rustc_target::spec::Arch; use tracing::{debug, instrument, trace}; use crate::common::CodegenCx; -use crate::errors::SymbolAlreadyDefined; +use crate::diagnostics::SymbolAlreadyDefined; use crate::llvm::{self, Type, Value, const_ptr_auth}; use crate::type_of::LayoutLlvmExt; use crate::{base, debuginfo}; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8f1910eaced13..89d9be451ebf4 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -238,7 +238,7 @@ pub(crate) unsafe fn create_module<'ll>( .expect("got a non-UTF8 data-layout from LLVM"); if target_data_layout != llvm_data_layout { - tcx.dcx().emit_err(crate::errors::MismatchedDataLayout { + tcx.dcx().emit_err(crate::diagnostics::MismatchedDataLayout { rustc_target: sess.opts.target_triple.to_string().as_str(), rustc_layout: target_data_layout.as_str(), llvm_target: sess.target.llvm_target.borrow(), diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs similarity index 100% rename from compiler/rustc_codegen_llvm/src/errors.rs rename to compiler/rustc_codegen_llvm/src/diagnostics.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 4f80e5c6e81e1..d3a5d06233c95 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -39,7 +39,7 @@ use crate::builder::gpu_offload::{ }; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; -use crate::errors::{ +use crate::diagnostics::{ AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch, OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic, }; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1dd460c409737..3ec0495956c4c 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -59,7 +59,7 @@ mod context; mod coverageinfo; mod debuginfo; mod declare; -mod errors; +mod diagnostics; mod intrinsic; mod llvm; mod llvm_util; @@ -233,10 +233,11 @@ impl CodegenBackend for LlvmCodegenBackend { match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { Ok(_) => {} Err(llvm::EnzymeLibraryError::NotFound { err }) => { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentMissing { err }); + sess.dcx().emit_fatal(crate::diagnostics::AutoDiffComponentMissing { err }); } Err(llvm::EnzymeLibraryError::LoadFailed { err }) => { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { err }); + sess.dcx() + .emit_fatal(crate::diagnostics::AutoDiffComponentUnavailable { err }); } } enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 87d8676cd8018..9ad14925afb14 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -21,7 +21,7 @@ use rustc_target::spec::{ use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; -use crate::{errors, llvm}; +use crate::{diagnostics, llvm}; static INIT: Once = Once::new(); @@ -636,7 +636,8 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { // -Zfixed-x18 if sess.opts.unstable_opts.fixed_x18 { if sess.target.arch != Arch::AArch64 { - sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: sess.target.arch.desc() }); + sess.dcx() + .emit_fatal(diagnostics::FixedX18InvalidArch { arch: sess.target.arch.desc() }); } else { features.push("+reserve-x18".into()); } diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index b746bab643a34..19d43797a875d 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -19,7 +19,7 @@ use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::errors::SymbolAlreadyDefined; +use crate::diagnostics::SymbolAlreadyDefined; use crate::type_of::LayoutLlvmExt; use crate::{base, llvm}; From 580253e6a299b62b2ef6492584b923195945dcad Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 28 Jul 2026 20:22:14 +0200 Subject: [PATCH 27/37] split module resolutions into local and external types, with external having a `OnceLock` around it for parallel import resolution --- .../rustc_resolve/src/build_reduced_graph.rs | 5 +- compiler/rustc_resolve/src/lib.rs | 49 +++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 970d7486d640c..5dd810f7df91b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -41,7 +41,8 @@ use crate::ref_mut::CmCell; use crate::{ BindingKey, Decl, DeclData, DeclKind, DelayedVisResolutionError, ExternModule, ExternPreludeEntry, Finalize, IdentKey, LocalModule, Module, ModuleKind, ModuleOrUniformRoot, - ParentScope, PathResult, Res, Resolver, Segment, Used, VisResolutionError, diagnostics, + ParentScope, PathResult, Res, ResolutionTable, Resolver, Segment, Used, VisResolutionError, + diagnostics, }; impl<'ra, 'tcx> Resolver<'ra, 'tcx> { @@ -336,7 +337,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn build_reduced_graph_external( &self, module: ExternModule<'ra>, - ) -> FxIndexMap> { + ) -> ResolutionTable<'ra> { let mut resolutions = FxIndexMap::default(); let def_id = module.def_id(); let children = self.tcx.module_children(def_id); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 111eae6a4134f..5e31f01cbd48b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -24,7 +24,7 @@ use std::cell::Ref; use std::collections::BTreeSet; use std::ops::ControlFlow; -use std::sync::{Arc, Once}; +use std::sync::{Arc, OnceLock}; use std::{fmt, mem}; use diagnostics::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; @@ -633,7 +633,22 @@ impl BindingKey { } } -type Resolutions<'ra> = CmRefCell>>; +type ResolutionTable<'ra> = FxIndexMap>; + +enum Resolutions<'ra> { + Local(CmRefCell>), + Extern(OnceLock>>), +} + +impl<'ra> Resolutions<'ra> { + fn new(local: bool) -> Self { + if local { + Resolutions::Local(Default::default()) + } else { + Resolutions::Extern(Default::default()) + } + } +} /// One node in the tree of modules. /// @@ -655,8 +670,6 @@ struct ModuleData<'ra> { /// Mapping between names and their (possibly in-progress) resolutions in this module. /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'ra>, - /// True if this is a module from other crate that needs to be populated on access. - populate_on_access: Once, /// Used to disambiguate underscore items (`const _: T = ...`) in the module. underscore_disambiguator: CmCell, @@ -710,6 +723,7 @@ impl<'ra> ModuleData<'ra> { vis: Visibility, arenas: &'ra ResolverArenas<'ra>, ) -> Self { + let lazy_resolutions = Resolutions::new(kind.is_local()); let self_decl = match kind { ModuleKind::Def(def_kind, def_id, ..) => { let expn_id = expansion.as_local().unwrap_or(LocalExpnId::ROOT); @@ -720,8 +734,7 @@ impl<'ra> ModuleData<'ra> { ModuleData { parent, kind, - lazy_resolutions: Default::default(), - populate_on_access: Once::new(), + lazy_resolutions, underscore_disambiguator: CmCell::new(0), unexpanded_invocations: Default::default(), no_implicit_prelude, @@ -2159,15 +2172,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.tcx.hir_arena.alloc_slice(&import_ids) } - fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> { - if !module.is_local() { - // as long as 1 thread is building this external table, all other threads will wait - module.populate_on_access.call_once(|| { - *module.lazy_resolutions.borrow_mut_unchecked() = - self.build_reduced_graph_external(module.expect_extern()); - }); + fn resolutions(&self, module: Module<'ra>) -> &'ra CmRefCell> { + match &module.0.0.lazy_resolutions { + Resolutions::Local(local_res) => local_res, + Resolutions::Extern(extern_res) => { + // as long as 1 thread is building this external table, all other threads will wait + extern_res.get_or_init(|| { + CmRefCell::new(self.build_reduced_graph_external(module.expect_extern())) + }) + } } - &module.0.0.lazy_resolutions } fn resolution( @@ -2920,13 +2934,6 @@ mod ref_mut { CmRefCell(RefCell::new(value)) } - #[track_caller] - // FIXME: this should be eliminated in the process of migration - // to parallel name resolution. - pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> { - self.0.borrow_mut() - } - #[track_caller] pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> { if r.assert_speculative { From c430395aa5174b562ad39f92ed267447f40e960d Mon Sep 17 00:00:00 2001 From: zakrad <49591476+zakrad@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:59:57 +0330 Subject: [PATCH 28/37] Add regression test for nested associated-type projection ICE Deeply nested associated-type projections used to ICE with "type variables should not be hashed" under incremental compilation; they now produce ordinary trait-bound errors. Uses `//@ incremental` so the crash path is exercised. --- ...nested-assoc-type-projection-ice-109864.rs | 39 +++++++++++ ...ed-assoc-type-projection-ice-109864.stderr | 65 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs create mode 100644 tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr diff --git a/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs new file mode 100644 index 0000000000000..ae55712c50a93 --- /dev/null +++ b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs @@ -0,0 +1,39 @@ +//! Regression test for . +//! +//! Deeply nested associated-type projections used to ICE with "type variables +//! should not be hashed" — but only under incremental compilation. They should now +//! produce ordinary trait-bound errors instead of crashing. + +//@ incremental + +struct S; +struct S2

(); //~ ERROR type parameter `P` is never used + +trait Foo { + type Out; +} + +trait Bar { + type Out; +} + +trait Qux { + type Out; +} + +trait Fuzz { + type Out; +} + +impl, B> Fuzz> for S2 { + type Out = <>::Out as Bar< + //~^ ERROR the trait bound `>::Out: Qux` is not satisfied + //~| ERROR the trait bound `>::Out: Bar, _>` is not satisfied + //~| ERROR the trait bound `>::Out: Bar, _>` is not satisfied + S2, + <<>::Out as Qux>::Out as Fuzz>>::Out, + //~^ ERROR the trait bound `>::Out: Qux` is not satisfied + >>::Out; +} + +fn main() {} diff --git a/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr new file mode 100644 index 0000000000000..fdf55aa4c2bdb --- /dev/null +++ b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr @@ -0,0 +1,65 @@ +error[E0392]: type parameter `P` is never used + --> $DIR/nested-assoc-type-projection-ice-109864.rs:10:11 + | +LL | struct S2

(); + | ^ unused type parameter + | + = help: consider removing `P`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `P` to be a const parameter, use `const P: /* Type */` instead + +error[E0277]: the trait bound `>::Out: Qux` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:29:16 + | +LL | type Out = <>::Out as Bar< + | ________________^ +... | +LL | | >>::Out; + | |___________^ the trait `Qux` is not implemented for `>::Out` + | +help: consider further restricting the associated type + | +LL | impl, B> Fuzz> for S2 where >::Out: Qux { + | ++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `>::Out: Bar, _>` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:29:16 + | +LL | type Out = <>::Out as Bar< + | ________________^ +... | +LL | | >>::Out; + | |___________^ the trait `Bar, _>` is not implemented for `>::Out` + | +help: this trait has no implementations, consider adding one + --> $DIR/nested-assoc-type-projection-ice-109864.rs:16:1 + | +LL | trait Bar { + | ^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `>::Out: Qux` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:34:10 + | +LL | <<>::Out as Qux>::Out as Fuzz>>::Out, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qux` is not implemented for `>::Out` + | +help: consider further restricting the associated type + | +LL | impl, B> Fuzz> for S2 where >::Out: Qux { + | ++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `>::Out: Bar, _>` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:29:5 + | +LL | type Out = <>::Out as Bar< + | ^^^^^^^^ the trait `Bar, _>` is not implemented for `>::Out` + | +help: this trait has no implementations, consider adding one + --> $DIR/nested-assoc-type-projection-ice-109864.rs:16:1 + | +LL | trait Bar { + | ^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0392. +For more information about an error, try `rustc --explain E0277`. From d3be642d27900dc18b2e80404344a5b69070af12 Mon Sep 17 00:00:00 2001 From: Rachel Barker Date: Wed, 29 Jul 2026 12:37:26 +0100 Subject: [PATCH 29/37] Mark a doctest as requiring unwinding https://github.com/rust-lang/rust/pull/158547 moved `std::io::BufWriter` to `alloc::io::BufWriter`. That allows it to be used in `no-std` configurations, and in particular on platforms where unwinding isn't supported. However one of the doc tests uses `catch_unwind`, which fails on platforms which cannot unwind. Fix this by copying the magic incantation from a similar doctest in library/core/src/range.rs --- library/alloc/src/io/buffered/bufwriter.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/alloc/src/io/buffered/bufwriter.rs b/library/alloc/src/io/buffered/bufwriter.rs index 4847c1605ac79..806e71c2772ae 100644 --- a/library/alloc/src/io/buffered/bufwriter.rs +++ b/library/alloc/src/io/buffered/bufwriter.rs @@ -490,6 +490,10 @@ impl BufWriter { /// # Example /// /// ``` +/// # // This test requires unwinding to work. +/// # // Disable it when unwinding isn't available. +/// # #[cfg(panic = "unwind")] +/// # fn main() { /// use std::io::{self, BufWriter, Write}; /// use std::panic::{catch_unwind, AssertUnwindSafe}; /// @@ -508,6 +512,9 @@ impl BufWriter { /// let (recovered_writer, buffered_data) = stream.into_parts(); /// assert!(matches!(recovered_writer, PanickingWriter)); /// assert_eq!(buffered_data.unwrap_err().into_inner(), b"some data"); +/// # } +/// # #[cfg(not(panic = "unwind"))] +/// # fn main() {} /// ``` pub struct WriterPanicked { buf: Vec, From dcb0002acb73b4f82d6119ae6d66cd3ecf42630f Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Wed, 29 Jul 2026 13:27:40 +0000 Subject: [PATCH 30/37] remove intrinsic-test path --- src/bootstrap/src/core/build_steps/test.rs | 2 +- src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap | 1 - .../src/core/builder/cli_paths/snapshots/x_test_library.snap | 3 --- .../core/builder/cli_paths/snapshots/x_test_skip_coverage.snap | 1 - .../builder/cli_paths/snapshots/x_test_skip_coverage_map.snap | 1 - .../builder/cli_paths/snapshots/x_test_skip_coverage_run.snap | 1 - .../core/builder/cli_paths/snapshots/x_test_skip_tests.snap | 1 - .../cli_paths/snapshots/x_test_skip_tests_coverage.snap | 1 - src/ci/docker/scripts/stage_2_test_set1.sh | 2 +- src/ci/docker/scripts/stage_2_test_set2.sh | 2 +- 10 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 6c6450cf1a374..17955109124d3 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1010,7 +1010,7 @@ impl Step for IntrinsicTest { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("library/stdarch/crates/intrinsic-test").alias("intrinsic-test") + run.alias("intrinsic-test") } fn is_default_step(_builder: &Builder<'_>) -> bool { diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap index 2355d09f9972c..824440507a89a 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap @@ -215,4 +215,3 @@ expression: test [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - Set({test::intrinsic-test}) - - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap index ba1f6b3c940c3..f97bb839c1e73 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap @@ -21,6 +21,3 @@ expression: test library [Test] test::StdarchVerify targets: [x86_64-unknown-linux-gnu] - Set({test::library/stdarch/crates/stdarch-verify}) -[Test] test::IntrinsicTest - targets: [x86_64-unknown-linux-gnu] - - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap index 2e9a0ae905bd9..98b15298d3dbf 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap @@ -212,4 +212,3 @@ expression: test --skip=coverage [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - Set({test::intrinsic-test}) - - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap index 001ec080527a4..308cc9f079648 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap @@ -215,4 +215,3 @@ expression: test --skip=coverage-map [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - Set({test::intrinsic-test}) - - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap index e535bcde35ead..c7395e025b773 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap @@ -215,4 +215,3 @@ expression: test --skip=coverage-run [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - Set({test::intrinsic-test}) - - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap index 3250a89374d2a..6885e2cd0fe25 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap @@ -158,4 +158,3 @@ expression: test --skip=tests [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - Set({test::intrinsic-test}) - - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap index a4fd7212215b1..0f5f708ea19c0 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap @@ -212,4 +212,3 @@ expression: test --skip=tests/coverage [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - Set({test::intrinsic-test}) - - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/ci/docker/scripts/stage_2_test_set1.sh b/src/ci/docker/scripts/stage_2_test_set1.sh index d63f8ad773016..e7930513c0d62 100755 --- a/src/ci/docker/scripts/stage_2_test_set1.sh +++ b/src/ci/docker/scripts/stage_2_test_set1.sh @@ -15,7 +15,7 @@ fi # Skip intrinsic-test on LLVM 21 to avoid CI failures. if [ "$LLVM_VERSION" = "21" ]; then echo "LLVM_VERSION is 21; skipping intrinsic-test" - SKIP_INTRINSICS="--skip intrinsic-test --skip library/stdarch/crates/intrinsic-test" + SKIP_INTRINSICS="--skip intrinsic-test" fi ../x.py --stage 2 test \ diff --git a/src/ci/docker/scripts/stage_2_test_set2.sh b/src/ci/docker/scripts/stage_2_test_set2.sh index d93e5cb55ed5d..5963924cce529 100755 --- a/src/ci/docker/scripts/stage_2_test_set2.sh +++ b/src/ci/docker/scripts/stage_2_test_set2.sh @@ -24,7 +24,7 @@ fi # Skip intrinsic-test on LLVM 21 to avoid CI failures. if [ "$LLVM_VERSION" = "21" ]; then echo "LLVM_VERSION is 21; skipping intrinsic-test" - SKIP_INTRINSICS="--skip intrinsic-test --skip library/stdarch/crates/intrinsic-test" + SKIP_INTRINSICS="--skip intrinsic-test" fi ../x.py --stage 2 test \ From 3d0b63d90eab56d877f92cdbb3ba92c3a8762f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 22 Jun 2026 13:49:30 +0200 Subject: [PATCH 31/37] hermit/fs: Return `unsupported()` instead of `from_raw_os_error(22)` --- library/std/src/sys/fs/hermit.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index d29ea81c67e6d..ec7836de897bd 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -352,7 +352,7 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn datasync(&self) -> io::Result<()> { @@ -380,7 +380,7 @@ impl File { } pub fn truncate(&self, _size: u64) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -431,15 +431,15 @@ impl File { } pub fn duplicate(&self) -> io::Result { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } } @@ -563,7 +563,7 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { } pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { @@ -571,11 +571,11 @@ pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { } pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn rmdir(path: &Path) -> io::Result<()> { From 6b2608e0d6c97cbbf326a7b5a44eb5fbbf12a99c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 28 Jul 2026 15:09:28 +0300 Subject: [PATCH 32/37] rustc_resolve: Further reduce mutability in resolver --- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- .../rustc_resolve/src/diagnostics/impls.rs | 18 +++---- compiler/rustc_resolve/src/ident.rs | 6 +-- compiler/rustc_resolve/src/imports.rs | 52 ++++++++----------- compiler/rustc_resolve/src/late.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 8 +-- compiler/rustc_resolve/src/lib.rs | 44 ++++++++-------- compiler/rustc_resolve/src/macros.rs | 10 ++-- 8 files changed, 65 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 4ce07ffe45ed7..b723516b70edf 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -279,7 +279,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { res, )) }; - match self.cm().resolve_path( + match self.cm_mut().resolve_path( &segments, None, parent_scope, diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index cbc84540fcdef..212629395c98b 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -782,7 +782,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// This takes the error provided, combines it with the span and any additional spans inside the /// error and emits it. pub(crate) fn report_error( - &mut self, + &self, span: Span, resolution_error: ResolutionError<'ra>, ) -> ErrorGuaranteed { @@ -790,7 +790,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn into_struct_error( - &mut self, + &self, span: Span, resolution_error: ResolutionError<'ra>, ) -> Diag<'_> { @@ -1459,7 +1459,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn add_scope_set_candidates( - &mut self, + &self, suggestions: &mut Vec, scope_set: ScopeSet<'ra>, ps: &ParentScope<'ra>, @@ -1560,7 +1560,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Lookup typo candidate in scope for a macro or import. fn early_lookup_typo_candidate( - &mut self, + &self, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, ident: Ident, @@ -1828,7 +1828,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// N.B., the method does not look into imports, but this is not a problem, /// since we report the definitions (thus, the de-aliased imports). pub(crate) fn lookup_import_candidates( - &mut self, + &self, lookup_ident: Ident, namespace: Namespace, parent_scope: &ParentScope<'ra>, @@ -3310,7 +3310,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// ``` #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_self_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -3330,7 +3330,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// ``` #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_crate_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -3362,7 +3362,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// ``` #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_super_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -3385,7 +3385,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// name as the first part of path. #[instrument(level = "debug", skip(self, parent_scope))] fn make_external_crate_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 1c94779a6009a..3f34af1d01d83 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -346,7 +346,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata, ))); } else if let RibKind::Block(Some(module)) = rib.kind - && let Ok(binding) = self.cm().resolve_ident_in_scope_set( + && let Ok(binding) = self.cm_mut().resolve_ident_in_scope_set( ident, ScopeSet::Module(ns, module.to_module()), parent_scope, @@ -362,7 +362,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let parent_scope = &ParentScope { module: module.to_module(), ..*parent_scope }; let finalize = finalize.map(|f| Finalize { stage: Stage::Late, ..f }); return self - .cm() + .cm_mut() .resolve_ident_in_scope_set( orig_ident, ScopeSet::All(ns), @@ -1457,7 +1457,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Validate a local resolution (from ribs). #[instrument(level = "debug", skip(self, all_ribs))] fn validate_res_from_ribs( - &mut self, + &self, rib_index: usize, rib_ident: Ident, res: Res, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 3f2e24995deab..c00eb97f4c3d6 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -34,9 +34,9 @@ use crate::diagnostics::{ }; use crate::ref_mut::{CmCell, CmRefCell}; use crate::{ - AmbiguityError, BindingKey, CmResolver, Decl, DeclData, DeclKind, Determinacy, Finalize, - IdentKey, ImportSuggestion, ImportSummary, LocalModule, ModuleOrUniformRoot, ParentScope, - PathResult, PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, + AmbiguityError, BindingKey, Decl, DeclData, DeclKind, Determinacy, Finalize, IdentKey, + ImportSuggestion, ImportSummary, LocalModule, ModuleOrUniformRoot, ParentScope, PathResult, + PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; @@ -735,7 +735,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let dummy_decl = self.dummy_decl; let dummy_decl = self.new_import_decl(dummy_decl, import); - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { let ident = IdentKey::new(target); // This can fail, dummies are inserted only in non-occupied slots. let _ = this.try_plant_decl_into_local_module(ident, target.span, ns, dummy_decl); @@ -782,13 +782,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut imports_to_resolve = mem::take(&mut self.indeterminate_imports); self.assert_speculative = true; - let cm_resolver = self.cm(); - rustc_data_structures::sync::par_for_each_slice( &mut imports_to_resolve, |(import, resolution, indeterminate_count)| { - (*resolution, *indeterminate_count) = - cm_resolver.reborrow_ref().resolve_import(*import); + (*resolution, *indeterminate_count) = self.resolve_import(*import); }, ); self.assert_speculative = false; @@ -835,7 +832,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ImportKind::Single { target, decls, .. }, ImportResolutionKind::Single(import_decls), ) => { - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { match import_decls[ns] { PendingDecl::Ready(Some(decl)) => { // We need the `target`, `source` can be extracted. @@ -1116,10 +1113,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// - Other values mean that indeterminate exists under certain namespaces. /// /// Meanwhile, if resolution is successful, its result is returned. - fn resolve_import<'r>( - mut self: CmResolver<'r, 'ra, 'tcx>, - import: Import<'ra>, - ) -> (Option>, usize) { + fn resolve_import(&self, import: Import<'ra>) -> (Option>, usize) { debug!( "(resolving import for module) resolving import `{}::{}` in `{}`", Segment::names_to_string(&import.module_path), @@ -1129,7 +1123,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module = if let Some(module) = import.imported_module.get() { module } else { - let path_res = self.reborrow().maybe_resolve_path( + let path_res = self.cm().maybe_resolve_path( &import.module_path, None, &import.parent_scope, @@ -1157,11 +1151,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut decls = PerNS::default(); let mut indeterminate_count = 0; - self.per_ns_cm(|mut this, ns| { + self.per_ns(|this, ns| { if bindings[ns].get() != PendingDecl::Pending { return; }; - let binding_result = this.reborrow().maybe_resolve_ident_in_module( + let binding_result = this.cm().maybe_resolve_ident_in_module( module, source, ns, @@ -1202,7 +1196,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); - let path_res = self.cm().resolve_path( + let path_res = self.cm_mut().resolve_path( &import.module_path, None, &import.parent_scope, @@ -1370,14 +1364,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // importing it if available. let mut path = import.module_path.clone(); path.push(Segment::from_ident(ident)); - if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.cm().resolve_path( - &path, - None, - &import.parent_scope, - Some(finalize), - ignore_decl, - None, - ) { + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self + .cm_mut() + .resolve_path(&path, None, &import.parent_scope, Some(finalize), ignore_decl, None) + { let res = module.res().map(|r| (r, ident)); for error in &mut self.privacy_errors[privacy_errors_len..] { error.outermost_res = res; @@ -1407,8 +1397,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let mut all_ns_err = true; - self.per_ns(|this, ns| { - let binding = this.cm().resolve_ident_in_module( + self.per_ns_mut(|this, ns| { + let binding = this.cm_mut().resolve_ident_in_module( module, ident, ns, @@ -1472,8 +1462,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if all_ns_err { let mut all_ns_failed = true; - self.per_ns(|this, ns| { - let binding = this.cm().resolve_ident_in_module( + self.per_ns_mut(|this, ns| { + let binding = this.cm_mut().resolve_ident_in_module( module, ident, ns, @@ -1632,7 +1622,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(ident)); - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding)); } @@ -1642,7 +1632,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.owners.get_mut(&import_id).unwrap().import_res[ns] = Some(binding.res()); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 535d11d00d718..f30e6844c861c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1581,7 +1581,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { finalize: Option, source: PathSource<'_, 'ast, 'ra>, ) -> PathResult<'ra> { - self.r.cm().resolve_path_with_ribs( + self.r.cm_mut().resolve_path_with_ribs( path, opt_ns, &self.parent_scope, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e26bfa6b96d51..f2ce21377acce 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2067,7 +2067,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn update_err_for_private_tuple_struct_fields( - &mut self, + &self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>, def_id: DefId, @@ -2177,7 +2177,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } }; - let bad_struct_syntax_suggestion = |this: &mut Self, err: &mut Diag<'_>, def_id: DefId| { + let bad_struct_syntax_suggestion = |this: &Self, err: &mut Diag<'_>, def_id: DefId| { let (followed_by_brace, closing_brace) = this.followed_by_brace(span); match source { @@ -2629,7 +2629,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_alternative_construction_methods( - &mut self, + &self, def_id: DefId, err: &mut Diag<'_>, path_span: Span, @@ -2784,7 +2784,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn lookup_assoc_candidate( - &mut self, + &self, ident: Ident, ns: Namespace, filter_fn: FilterFn, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2dbf32dc20288..c703cf3d7e576 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1990,27 +1990,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - /// Returns a conditionally mutable resolver. - /// - /// Currently only dependent on `assert_speculative`, if `assert_speculative` is false, - /// the resolver will allow mutation; otherwise, it will be immutable. - fn cm(&mut self) -> CmResolver<'_, 'ra, 'tcx> { - CmResolver::new(self, !self.assert_speculative) + /// Returns a conditionally mutable resolver that cannot be mutated. + fn cm(&self) -> CmResolver<'_, 'ra, 'tcx> { + CmResolver::from_ref(self) + } + + /// Returns a conditionally mutable resolver that can be mutated. + /// Will panic if the `assert_speculative` field is true. + fn cm_mut(&mut self) -> CmResolver<'_, 'ra, 'tcx> { + assert!(!self.assert_speculative); + CmResolver::from_mut(self) } /// Runs the function on each namespace. - fn per_ns(&mut self, mut f: F) { + fn per_ns(&self, mut f: F) { f(self, TypeNS); f(self, ValueNS); f(self, MacroNS); } - fn per_ns_cm<'r, F: FnMut(CmResolver<'_, 'ra, 'tcx>, Namespace)>( - mut self: CmResolver<'r, 'ra, 'tcx>, - mut f: F, - ) { - f(self.reborrow(), TypeNS); - f(self.reborrow(), ValueNS); + fn per_ns_mut(&mut self, mut f: F) { + f(self, TypeNS); + f(self, ValueNS); f(self, MacroNS); } @@ -2080,7 +2081,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let scope_set = ScopeSet::All(TypeNS); let ctxt = Macros20NormalizedSyntaxContext::new(sp.ctxt()); - self.cm().visit_scopes(scope_set, parent_scope, ctxt, sp, None, |mut this, scope, _, _| { + let cmr = self.cm_mut(); + cmr.visit_scopes(scope_set, parent_scope, ctxt, sp, None, |mut this, scope, _, _| { match scope { Scope::ModuleNonGlobs(module, _) => { this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); @@ -2464,7 +2466,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, /// just that an error occurred. fn resolve_rustdoc_path( - &mut self, + &self, path_str: &str, ns: Namespace, parent_scope: ParentScope<'ra>, @@ -2834,16 +2836,12 @@ mod ref_mut { } impl<'a, T> RefOrMut<'a, T> { - pub(crate) fn new(p: &'a mut T, mutable: bool) -> Self { - RefOrMut { p, mutable, _marker: PhantomData } + pub(crate) fn from_ref(r: &'a T) -> Self { + RefOrMut { p: r as *const T as *mut T, mutable: false, _marker: PhantomData } } - pub(crate) fn reborrow_ref(&self) -> RefOrMut<'_, T> { - assert!( - !self.mutable, - "Tried to reborrow a mutable `RefOrMut` through shared reference." - ); - RefOrMut { p: self.p, mutable: self.mutable, _marker: PhantomData } + pub(crate) fn from_mut(r: &'a mut T) -> Self { + RefOrMut { p: r as *mut T, mutable: true, _marker: PhantomData } } /// This is needed because this wraps a `&mut T` and is therefore not `Copy`. diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 54f9aa8e914ec..1e9d60ca21551 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -613,7 +613,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { invoc_in_mod_inert_attr: Option, suggestion_span: Option, ) -> Result<(&'ra Arc, Res), Indeterminate> { - let (ext, res) = match self.cm().resolve_macro_or_delegation_path( + let (ext, res) = match self.cm_mut().resolve_macro_or_delegation_path( path, kind, parent_scope, @@ -966,7 +966,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for seg in &mut path { seg.id = None; } - match self.cm().resolve_path( + match self.cm_mut().resolve_path( &path, Some(ns), &parent_scope, @@ -1063,7 +1063,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let macro_resolutions = self.single_segment_macro_resolutions.take(self); for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { - match self.cm().resolve_ident_in_scope_set( + match self.cm_mut().resolve_ident_in_scope_set( ident, ScopeSet::Macro(kind), &parent_scope, @@ -1117,7 +1117,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let builtin_attrs = mem::take(&mut self.builtin_attrs); for (ident, parent_scope) in builtin_attrs { - let _ = self.cm().resolve_ident_in_scope_set( + let _ = self.cm_mut().resolve_ident_in_scope_set( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, @@ -1295,7 +1295,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn path_accessible( - &mut self, + &self, expn_id: LocalExpnId, path: &ast::Path, namespaces: &[Namespace], From c9f7b9697ed831973c309166b06efae33c9c8d38 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 28 Jul 2026 18:51:04 +0300 Subject: [PATCH 33/37] rustc_resolve: Turn `RefOrMut` into an enum --- compiler/rustc_resolve/src/lib.rs | 56 ++++++++++++------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c703cf3d7e576..e3365ed9ca0c8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1992,14 +1992,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Returns a conditionally mutable resolver that cannot be mutated. fn cm(&self) -> CmResolver<'_, 'ra, 'tcx> { - CmResolver::from_ref(self) + CmResolver::Ref(self) } /// Returns a conditionally mutable resolver that can be mutated. /// Will panic if the `assert_speculative` field is true. fn cm_mut(&mut self) -> CmResolver<'_, 'ra, 'tcx> { - assert!(!self.assert_speculative); - CmResolver::from_mut(self) + assert!(!self.assert_speculative, "can't mutably borrow speculative resolver"); + CmResolver::Mut(self) } /// Runs the function on each namespace. @@ -2793,7 +2793,7 @@ pub fn provide(providers: &mut Providers) { /// /// `Cm` stands for "conditionally mutable". /// -/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. +/// Prefer constructing it through `Resolver::cm(_mut)` to ensure correctness. type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; // FIXME: These are cells for caches that can be populated even during speculative resolution, @@ -2804,64 +2804,52 @@ use std::cell::{Cell as CacheCell, RefCell as CacheRefCell}; mod ref_mut { use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut}; use std::fmt; - use std::marker::PhantomData; use std::ops::Deref; use crate::Resolver; - /// A wrapper around a mutable reference that conditionally allows mutable access. - pub(crate) struct RefOrMut<'a, T> { - // We keep a raw pointer because it makes `reborrow_ref` possible. It is always safe to - // cast this to a `&T` because `RefOrMut` is only created through `new` which takes - // a `&mut T`. - p: *mut T, - mutable: bool, - _marker: PhantomData<&'a mut T>, + /// A reference type that conditionally allows mutable access. + pub(crate) enum RefOrMut<'a, T> { + Ref(&'a T), + Mut(&'a mut T), } impl<'a, T> Deref for RefOrMut<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { - // SAFETY: `RefOrMUt` is only constructable through a `&mut T`. - unsafe { self.p.as_ref_unchecked() } + match self { + RefOrMut::Ref(r) => r, + RefOrMut::Mut(r) => r, + } } } impl<'a, T> AsRef for RefOrMut<'a, T> { fn as_ref(&self) -> &T { - // SAFETY: `RefOrMUt` is only constructable through a `&mut T`. - unsafe { self.p.as_ref_unchecked() } + &*self } } impl<'a, T> RefOrMut<'a, T> { - pub(crate) fn from_ref(r: &'a T) -> Self { - RefOrMut { p: r as *const T as *mut T, mutable: false, _marker: PhantomData } - } - - pub(crate) fn from_mut(r: &'a mut T) -> Self { - RefOrMut { p: r as *mut T, mutable: true, _marker: PhantomData } - } - - /// This is needed because this wraps a `&mut T` and is therefore not `Copy`. + /// This is needed because the type may allow mutable access and is therefore not `Copy`. pub(crate) fn reborrow(&mut self) -> RefOrMut<'_, T> { - RefOrMut { p: self.p, mutable: self.mutable, _marker: PhantomData } + match self { + RefOrMut::Ref(r) => RefOrMut::Ref(r), + RefOrMut::Mut(r) => RefOrMut::Mut(r), + } } /// Returns a mutable reference to the inner value if allowed. /// /// # Panics /// - /// Panics if the `mutable` flag is false. + /// Panics if the wrapped reference is immutable. #[track_caller] pub(crate) fn get_mut(&mut self) -> &mut T { - match self.mutable { - false => panic!("can't mutably borrow speculative resolver"), - // SAFETY: - // - `RefOrMut` is only constructable through a `&mut T` and we - // have tested that it may indeed be used as a `&mut T` in this match. - true => unsafe { self.p.as_mut_unchecked() }, + match self { + RefOrMut::Ref(_) => panic!("can't mutably borrow an immutable reference"), + RefOrMut::Mut(r) => r, } } } From 836421626b30feea6e959a1d95f79c3c34fbb1fa Mon Sep 17 00:00:00 2001 From: joboet Date: Sun, 19 Jul 2026 14:59:56 +0200 Subject: [PATCH 34/37] core: implement bounded random sampling --- library/core/src/random.rs | 218 ++++++++++++++++++++++++++++++++++--- 1 file changed, 204 insertions(+), 14 deletions(-) diff --git a/library/core/src/random.rs b/library/core/src/random.rs index 7275b3c203b5c..7246be3c44ef2 100644 --- a/library/core/src/random.rs +++ b/library/core/src/random.rs @@ -1,6 +1,6 @@ //! Random value generation. -use crate::ops::RangeFull; +use crate::range::{RangeFull, RangeInclusive}; /// A source of randomness. #[unstable(feature = "random", issue = "130703")] @@ -34,7 +34,7 @@ impl Distribution for RangeFull { } } -macro_rules! impl_primitive { +macro_rules! impl_full { ($t:ty) => { impl Distribution<$t> for RangeFull { fn sample(&self, source: &mut (impl Rng + ?Sized)) -> $t { @@ -46,15 +46,205 @@ macro_rules! impl_primitive { }; } -impl_primitive!(u8); -impl_primitive!(i8); -impl_primitive!(u16); -impl_primitive!(i16); -impl_primitive!(u32); -impl_primitive!(i32); -impl_primitive!(u64); -impl_primitive!(i64); -impl_primitive!(u128); -impl_primitive!(i128); -impl_primitive!(usize); -impl_primitive!(isize); +impl_full!(u8); +impl_full!(i8); +impl_full!(u16); +impl_full!(i16); +impl_full!(u32); +impl_full!(i32); +impl_full!(u64); +impl_full!(i64); +impl_full!(u128); +impl_full!(i128); +impl_full!(usize); +impl_full!(isize); + +#[cold] +fn empty_range() -> ! { + panic!("cannot sample from an empty distribution") +} + +macro_rules! lemire_sample { + ($name:ident($ty:ty)) => { + // Unbiased uniform sampling of a number within the range [0, bound). + // + // By performing some clever modular arithmetic, this algorithm manages + // to both reduce divisions and minimize the chance of sample rejections. + // + // Algorithm from: + // spellchecker:off + // Daniel Lemire. 2019. Fast Random Integer Generation in an Interval. + // ACM Trans. Model. Comput. Simul. 29, 1, Article 3 (January 2019), 12 pages. + // https://doi.org/10.1145/3230636 + // spellchecker:on + fn $name(bound: $ty, source: &mut (impl Rng + ?Sized)) -> $ty { + debug_assert_ne!(bound, 0); + + let sample: $ty = (..).sample(source); + + let (mut l, mut res) = sample.carrying_mul(bound, 0); + if l < bound { + let t = bound.wrapping_neg() % bound; + while l < t { + let sample: $ty = (..).sample(source); + (l, res) = sample.carrying_mul(bound, 0); + } + } + + debug_assert!(res < bound); + res + } + }; +} + +lemire_sample!(bounded32(u32)); +lemire_sample!(bounded64(u64)); +lemire_sample!(bounded128(u128)); + +macro_rules! impl_range { + ($unsigned:ty, $signed:ty as $base:ty => $bounded:ident) => { + impl Distribution<$unsigned> for RangeInclusive<$unsigned> { + /// Chooses a random number within the range. + /// + /// Every possible result value is equally likely. In other words, + /// this operation uses unbiased uniform sampling. + /// + /// # Panics + /// + /// Panics if the range is empty. + /// + /// # Side-channels + /// + /// This implementation does not claim to be resistant against side- + /// channel attacks. In particular, the execution time of this operation + /// may leak information about the returned value, and not just the + /// values of the range bounds. While this implementation tries to + /// avoid operations with particularly data-dependent timing (such + /// as divisions), Rust as a language has no facilities for ensuring + /// data-independent timing, voiding all promises about side-channel- + /// freedom. + /// + /// # Examples + /// + /// A D20 dice roll: + /// ``` + /// #![feature(random)] + /// + /// use std::random::{Distribution, SystemRng}; + /// use std::range::RangeInclusive; + /// + /// let roll = RangeInclusive::from(1..=20).sample(&mut SystemRng); + /// assert!(1 <= roll && roll <= 20); + /// if roll == 20 { + /// println!("Wow! You achieve writing a sound linked list."); + /// } else { + /// println!("Miri attacks!"); + /// } + /// ``` + #[inline] + fn sample(&self, source: &mut (impl Rng + ?Sized)) -> $unsigned { + if self.start > self.last { + empty_range(); + } + + if self.start == self.last { + return self.start; + } + + let Some(bound) = (self.last - self.start).checked_add(1) else { + // Overflow can only occur for Self::MIN..=Self::MAX, meaning + // the range is effectively unbounded. + return RangeFull.sample(source); + }; + + let offset = if bound.is_power_of_two() { + let sample: $unsigned = RangeFull.sample(source); + sample & (bound - 1) + } else { + $bounded(bound as $base, source) as $unsigned + }; + + self.start + offset + } + } + + impl Distribution<$signed> for RangeInclusive<$signed> { + /// Chooses a random number within the range. + /// + /// Every possible result value is equally likely. In other words, + /// this operation uses unbiased uniform sampling. + /// + /// # Panics + /// + /// Panics if the range is empty. + /// + /// # Side-channels + /// + /// This implementation does not claim to be resistant against side- + /// channel attacks. In particular, the execution time of this operation + /// may leak information about the returned value, and not just the + /// values of the range bounds. While this implementation tries to + /// avoid operations with particularly data-dependent timing (such + /// as divisions), Rust as a language has no facilities for ensuring + /// data-independent timing, voiding all promises about side-channel- + /// freedom. + /// + /// # Examples + /// + /// A D20 dice roll: + /// ``` + /// #![feature(random)] + /// + /// use std::random::{Distribution, SystemRng}; + /// use std::range::RangeInclusive; + /// + /// let roll = RangeInclusive::from(1..=20).sample(&mut SystemRng); + /// assert!(1 <= roll && roll <= 20); + /// if roll == 20 { + /// println!("Wow! You achieve writing a sound linked list."); + /// } else { + /// println!("Miri attacks!"); + /// } + /// ``` + #[inline] + fn sample(&self, source: &mut (impl Rng + ?Sized)) -> $signed { + if self.start > self.last { + empty_range(); + } + + if self.start == self.last { + return self.start; + } + + let Some(bound) = self.last.wrapping_sub(self.start).cast_unsigned().checked_add(1) + else { + // Overflow can only occur for Self::MIN..=Self::MAX, meaning + // the range is effectively unbounded. + return RangeFull.sample(source); + }; + + let offset = if bound.is_power_of_two() { + let sample: $unsigned = RangeFull.sample(source); + sample & (bound - 1) + } else { + $bounded(bound as $base, source) as $unsigned + }; + + self.start.wrapping_add_unsigned(offset) + } + } + }; +} + +// Use 32-bit integers for small integers since it reduces the likelihood of +// sample rejections. +impl_range!(u8, i8 as u32 => bounded32); +impl_range!(u16, i16 as u32 => bounded32); + +impl_range!(u32, i32 as u32 => bounded32); +impl_range!(u64, i64 as u64 => bounded64); +impl_range!(u128, i128 as u128 => bounded128); +#[cfg(any(target_pointer_width = "16", target_pointer_width = "32",))] +impl_range!(usize, isize as u32 => bounded32); +#[cfg(target_pointer_width = "64")] +impl_range!(usize, isize as u64 => bounded64); From c257aefd56c79af1ac53265f74d225c9660c70bd Mon Sep 17 00:00:00 2001 From: chiri Date: Wed, 29 Jul 2026 18:29:20 +0300 Subject: [PATCH 35/37] review (x3) --- library/core/src/fmt/num.rs | 40 ++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index f94e5433a5183..1a986d88e0e0d 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -693,11 +693,11 @@ impl u128 { let quad = remain % 1_00_00; remain /= 1_00_00; - write_quad( - // SAFETY: `offset >= 4` was asserted above. - unsafe { buf.get_unchecked_mut(offset..offset + 4) }, - quad, - ); + // SAFETY: quad is a remainder modulo 10_000. The offset checks + // above reserve exactly four bytes in buf. + unsafe { + write_quad(buf.get_unchecked_mut(offset..offset + 4), quad); + } } // Format per two digits from the lookup table. @@ -814,8 +814,12 @@ impl i128 { } /// Writes `quad` as exactly four digits (for example: `42` becomes `"0042"`). +/// +/// # Safety +/// +/// `quad` must be below 10_000 and `buf` must contain exactly four bytes. #[inline(always)] -fn write_quad(buf: &mut [MaybeUninit], quad: u64) { +unsafe fn write_quad(buf: &mut [MaybeUninit], quad: u64) { // SAFETY: These are this function's caller-provided invariants. unsafe { core::hint::assert_unchecked(quad < 10_000); @@ -855,20 +859,20 @@ fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { let quad = remain % 1_00_00; remain /= 1_00_00; - write_quad( - // SAFETY: `OFFSET + 16 <= buf.len()` and `quad_index < 4`, so this range is within `buf`. - unsafe { - buf.get_unchecked_mut(OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4) - }, - quad, - ); + // SAFETY: `OFFSET + quad_index * 4` starts one of the four + // non-overlapping four-byte regions proven in bounds above. + unsafe { + write_quad( + buf.get_unchecked_mut(OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4), + quad, + ); + } } - write_quad( - // SAFETY: `OFFSET + 16 <= buf.len()` was asserted above. - unsafe { buf.get_unchecked_mut(OFFSET..OFFSET + 4) }, - remain, - ); + // SAFETY: OFFSET starts the first four-byte region proven in bounds above. + unsafe { + write_quad(buf.get_unchecked_mut(OFFSET..OFFSET + 4), remain); + } } /// Euclidean division plus remainder with constant 1E16 basically consumes 16 From d80021794effd74c77ed1022cb03525c954357cd Mon Sep 17 00:00:00 2001 From: Rachit2323 Date: Wed, 29 Jul 2026 15:50:08 +0530 Subject: [PATCH 36/37] iter: specialize Take::count using advance_by --- library/core/src/iter/adapters/take.rs | 13 ++++ library/coretests/tests/iter/adapters/take.rs | 63 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index ecd462c60eda3..3df2c70801644 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -56,6 +56,19 @@ where } } + #[inline] + fn count(mut self) -> usize { + if self.n == 0 { + return 0; + } + // Advancing consumes the same elements `next` would have yielded, + // while benefiting from the inner iterator's `advance_by` fast path. + match self.iter.advance_by(self.n) { + Ok(()) => self.n, + Err(remaining) => self.n - remaining.get(), + } + } + #[inline] fn size_hint(&self) -> (usize, Option) { if self.n == 0 { diff --git a/library/coretests/tests/iter/adapters/take.rs b/library/coretests/tests/iter/adapters/take.rs index b932059afec8a..700bd3f44a1d1 100644 --- a/library/coretests/tests/iter/adapters/take.rs +++ b/library/coretests/tests/iter/adapters/take.rs @@ -260,3 +260,66 @@ fn test_reverse_on_zip() { assert_eq!((1, 0), (one, zero)); } } + +#[test] +fn test_iterator_take_count() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + + // take shorter than, equal to, and longer than the underlying iterator + assert_eq!(xs.iter().take(0).count(), 0); + assert_eq!(xs.iter().take(5).count(), 5); + assert_eq!(xs.iter().take(10).count(), 10); + assert_eq!(xs.iter().take(11).count(), 10); + assert_eq!(xs.iter().take(usize::MAX).count(), 10); + + // partially consumed + let mut it = xs.iter().take(5); + it.next(); + it.next(); + assert_eq!(it.count(), 3); + + let mut it = xs.iter().take(20); + it.next(); + assert_eq!(it.count(), 9); + + // `count` must observe the same elements `next` would have yielded: + // a side-effecting inner iterator sees exactly min(n, len) closure calls. + let mut calls = 0; + let count = (0..10) + .map(|x| { + calls += 1; + x + }) + .take(3) + .count(); + assert_eq!(count, 3); + assert_eq!(calls, 3); + + // stateful filter: count agrees with the number of elements actually yielded + let mut budget = 7; + let yielded: Vec = (1..100) + .filter(|&x| { + if x <= budget { + budget -= 1; + true + } else { + false + } + }) + .take(10) + .collect(); + + let mut budget = 7; + let counted = (1..100) + .filter(|&x| { + if x <= budget { + budget -= 1; + true + } else { + false + } + }) + .take(10) + .count(); + assert_eq!(counted, yielded.len()); +} From 953e83e139c0e21c8f74b3ade9b07d16ffe260d4 Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 29 Jul 2026 17:16:21 +0100 Subject: [PATCH 37/37] Use correct feature gates for `f16`/`f128` `From` impls --- library/core/src/convert/num.rs | 42 ++++-- .../feature-gate-f128.e2015.stderr | 138 ++++++++++++++++-- .../feature-gate-f128.e2018.stderr | 138 ++++++++++++++++-- tests/ui/feature-gates/feature-gate-f128.rs | 15 +- .../feature-gate-f16.e2015.stderr | 78 ++++++++-- .../feature-gate-f16.e2018.stderr | 78 ++++++++-- tests/ui/feature-gates/feature-gate-f16.rs | 9 +- 7 files changed, 434 insertions(+), 64 deletions(-) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 1125f437c1538..8a5f72bac8c2f 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -138,27 +138,27 @@ impl_from!(i16 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.2 // of the `f16`/`f128` impls can be used on stable as the `f16` and `f128` types are unstable). // signed integer -> float -impl_from!(i8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i8 => f16, #[unstable(feature = "f16", issue = "116909")], #[unstable_feature_bound(f16)]); impl_from!(i8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(i8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i8 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(i16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(i16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i16 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(i32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i32 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(i64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); // unsigned integer -> float -impl_from!(u8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u8 => f16, #[unstable(feature = "f16", issue = "116909")], #[unstable_feature_bound(f16)]); impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u8 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u16 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u32 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(u64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); // float -> float @@ -170,20 +170,22 @@ impl_from!(u64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unsta // // See also . impl_from!(f16 => f32, #[unstable(feature = "f32_from_f16", issue = "154005")], #[unstable_feature_bound(f32_from_f16)]); -impl_from!(f16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(f16 => f64, #[unstable(feature = "f16", issue = "116909")], #[unstable_feature_bound(f16)]); +// Also #[unstable(feature = "f16", issue = "116909")]: +impl_from!(f16 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f16, f128)]); impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(f32 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); +impl_from!(f64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); macro_rules! impl_float_from_bool { ( + $(#[$attr:meta])* $float:ty $(; doctest_prefix: $(#[doc = $doctest_prefix:literal])* doctest_suffix: $(#[doc = $doctest_suffix:literal])* )? ) => { - #[stable(feature = "float_from_bool", since = "1.68.0")] + $(#[$attr])* #[rustc_const_unstable(feature = "const_convert", issue = "143773")] const impl From for $float { #[doc = concat!("Converts a [`bool`] to [`", stringify!($float),"`] losslessly.")] @@ -210,6 +212,8 @@ macro_rules! impl_float_from_bool { // boolean -> float impl_float_from_bool!( + #[unstable(feature = "f16", issue = "116909")] + #[unstable_feature_bound(f16)] f16; doctest_prefix: // rustdoc doesn't remove the conventional space after the `///` @@ -220,9 +224,17 @@ impl_float_from_bool!( doctest_suffix: ///# } ); -impl_float_from_bool!(f32); -impl_float_from_bool!(f64); impl_float_from_bool!( + #[stable(feature = "float_from_bool", since = "1.68.0")] + f32 +); +impl_float_from_bool!( + #[stable(feature = "float_from_bool", since = "1.68.0")] + f64 +); +impl_float_from_bool!( + #[unstable(feature = "f128", issue = "116909")] + #[unstable_feature_bound(f128)] f128; doctest_prefix: ///# #![allow(unused_features)] diff --git a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr index 627010a935475..2cf3eacf07523 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr @@ -19,27 +19,127 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:13:12 + --> $DIR/feature-gate-f128.rs:13:18 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:16:12 + --> $DIR/feature-gate-f128.rs:16:18 | -LL | let e: f128 = 1u64.into(); - | ^^^^ +LL | let from_u8: f128 = 1_u8.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:17:19 + | +LL | let from_i16: f128 = 1_i16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:18:19 + | +LL | let from_u16: f128 = 1_u16.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:21:11 + --> $DIR/feature-gate-f128.rs:19:19 + | +LL | let from_i32: f128 = 1_i32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:20:19 + | +LL | let from_u32: f128 = 1_u32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:21:19 + | +LL | let from_i64: f128 = 1_i64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:22:19 + | +LL | let from_u64: f128 = 1_u64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:23:19 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:26:19 + | +LL | let from_f32: f128 = 1.0_f32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:27:19 + | +LL | let from_f64: f128 = 1.0_f64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:28:20 + | +LL | let from_bool: f128 = true.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:32:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -49,7 +149,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:24:8 + --> $DIR/feature-gate-f128.rs:35:8 | LL | a: f128, | ^^^^ @@ -78,17 +178,27 @@ LL | let c = 0f128; = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f128.rs:23:26 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: use of unstable library feature `f128` - --> $DIR/feature-gate-f128.rs:13:24 + --> $DIR/feature-gate-f128.rs:13:30 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: required for `f128` to implement `From` - = note: required for `i64` to implement `Into` + = note: required for `f128` to implement `From` + = note: required for `i8` to implement `Into` -error: aborting due to 9 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr index 627010a935475..2cf3eacf07523 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr @@ -19,27 +19,127 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:13:12 + --> $DIR/feature-gate-f128.rs:13:18 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:16:12 + --> $DIR/feature-gate-f128.rs:16:18 | -LL | let e: f128 = 1u64.into(); - | ^^^^ +LL | let from_u8: f128 = 1_u8.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:17:19 + | +LL | let from_i16: f128 = 1_i16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:18:19 + | +LL | let from_u16: f128 = 1_u16.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:21:11 + --> $DIR/feature-gate-f128.rs:19:19 + | +LL | let from_i32: f128 = 1_i32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:20:19 + | +LL | let from_u32: f128 = 1_u32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:21:19 + | +LL | let from_i64: f128 = 1_i64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:22:19 + | +LL | let from_u64: f128 = 1_u64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:23:19 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:26:19 + | +LL | let from_f32: f128 = 1.0_f32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:27:19 + | +LL | let from_f64: f128 = 1.0_f64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:28:20 + | +LL | let from_bool: f128 = true.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:32:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -49,7 +149,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:24:8 + --> $DIR/feature-gate-f128.rs:35:8 | LL | a: f128, | ^^^^ @@ -78,17 +178,27 @@ LL | let c = 0f128; = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f128.rs:23:26 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: use of unstable library feature `f128` - --> $DIR/feature-gate-f128.rs:13:24 + --> $DIR/feature-gate-f128.rs:13:30 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: required for `f128` to implement `From` - = note: required for `i64` to implement `Into` + = note: required for `f128` to implement `From` + = note: required for `i8` to implement `Into` -error: aborting due to 9 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.rs b/tests/ui/feature-gates/feature-gate-f128.rs index 13851b72c70f2..3b64c71a23122 100644 --- a/tests/ui/feature-gates/feature-gate-f128.rs +++ b/tests/ui/feature-gates/feature-gate-f128.rs @@ -10,11 +10,22 @@ pub fn main() { let a: f128 = 100.0; //~ ERROR the type `f128` is unstable let b = 0.0f128; //~ ERROR the type `f128` is unstable let c = 0f128; //~ ERROR the type `f128` is unstable - let d: f128 = 1i64.into(); + let from_i8: f128 = 1_i8.into(); //~^ ERROR the type `f128` is unstable //~| ERROR use of unstable library feature `f128` - let e: f128 = 1u64.into(); + let from_u8: f128 = 1_u8.into(); //~ ERROR the type `f128` is unstable + let from_i16: f128 = 1_i16.into(); //~ ERROR the type `f128` is unstable + let from_u16: f128 = 1_u16.into(); //~ ERROR the type `f128` is unstable + let from_i32: f128 = 1_i32.into(); //~ ERROR the type `f128` is unstable + let from_u32: f128 = 1_u32.into(); //~ ERROR the type `f128` is unstable + let from_i64: f128 = 1_i64.into(); //~ ERROR the type `f128` is unstable + let from_u64: f128 = 1_u64.into(); //~ ERROR the type `f128` is unstable + let from_f16: f128 = 1.0_f16.into(); //~^ ERROR the type `f128` is unstable + //~| ERROR the type `f16` is unstable + let from_f32: f128 = 1.0_f32.into(); //~ ERROR the type `f128` is unstable + let from_f64: f128 = 1.0_f64.into(); //~ ERROR the type `f128` is unstable + let from_bool: f128 = true.into(); //~ ERROR the type `f128` is unstable foo(1.23); } diff --git a/tests/ui/feature-gates/feature-gate-f16.e2015.stderr b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr index b53f12af48fc8..3bc77d00e2384 100644 --- a/tests/ui/feature-gates/feature-gate-f16.e2015.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr @@ -18,8 +18,48 @@ LL | let a: f16 = 100.0; = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f16.rs:17:20 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:20:18 + | +LL | let from_i8: f16 = 1_i8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:21:18 + | +LL | let from_u8: f16 = 1_u8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:22:20 + | +LL | let from_bool: f16 = true.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:19:11 + --> $DIR/feature-gate-f16.rs:26:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +69,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:22:8 + --> $DIR/feature-gate-f16.rs:29:8 | LL | a: f16, | ^^^ @@ -59,26 +99,46 @@ LL | let c = 0f16; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:13:18 + --> $DIR/feature-gate-f16.rs:13:25 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:16:25 + | +LL | let into_f64: f64 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:17:27 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `f32_from_f16` - --> $DIR/feature-gate-f16.rs:13:25 + --> $DIR/feature-gate-f16.rs:13:32 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^ | = help: add `#![feature(f32_from_f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: required for `f32` to implement `From` = note: required for `f16` to implement `Into` -error: aborting due to 8 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr index b53f12af48fc8..3bc77d00e2384 100644 --- a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr @@ -18,8 +18,48 @@ LL | let a: f16 = 100.0; = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f16.rs:17:20 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:20:18 + | +LL | let from_i8: f16 = 1_i8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:21:18 + | +LL | let from_u8: f16 = 1_u8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:22:20 + | +LL | let from_bool: f16 = true.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:19:11 + --> $DIR/feature-gate-f16.rs:26:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +69,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:22:8 + --> $DIR/feature-gate-f16.rs:29:8 | LL | a: f16, | ^^^ @@ -59,26 +99,46 @@ LL | let c = 0f16; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:13:18 + --> $DIR/feature-gate-f16.rs:13:25 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:16:25 + | +LL | let into_f64: f64 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:17:27 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `f32_from_f16` - --> $DIR/feature-gate-f16.rs:13:25 + --> $DIR/feature-gate-f16.rs:13:32 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^ | = help: add `#![feature(f32_from_f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: required for `f32` to implement `From` = note: required for `f16` to implement `Into` -error: aborting due to 8 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f16.rs b/tests/ui/feature-gates/feature-gate-f16.rs index 6babc6c5c03ce..6211581db1c7a 100644 --- a/tests/ui/feature-gates/feature-gate-f16.rs +++ b/tests/ui/feature-gates/feature-gate-f16.rs @@ -10,9 +10,16 @@ pub fn main() { let a: f16 = 100.0; //~ ERROR the type `f16` is unstable let b = 0.0f16; //~ ERROR the type `f16` is unstable let c = 0f16; //~ ERROR the type `f16` is unstable - let d: f32 = 1.0f16.into(); + let into_f32: f32 = 1.0f16.into(); //~^ ERROR the type `f16` is unstable //~| ERROR use of unstable library feature `f32_from_f16` + let into_f64: f64 = 1.0_f16.into(); //~ ERROR the type `f16` is unstable + let into_f128: f128 = 1.0_f16.into(); + //~^ ERROR the type `f16` is unstable + //~| ERROR the type `f128` is unstable + let from_i8: f16 = 1_i8.into(); //~ ERROR the type `f16` is unstable + let from_u8: f16 = 1_u8.into(); //~ ERROR the type `f16` is unstable + let from_bool: f16 = true.into(); //~ ERROR the type `f16` is unstable foo(1.23); }