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/13] 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/13] 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/13] 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/13] 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/13] 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 576d1bd01e0f4456b0459f3f4f9944c0d89bdec6 Mon Sep 17 00:00:00 2001 From: Jonathan Klimt Date: Fri, 26 Jun 2026 11:22:47 +0200 Subject: [PATCH 06/13] 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 07/13] 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 50d66b9bed55ca50ae51aedbe7a14a1d88d02fd5 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Wed, 29 Jul 2026 11:17:18 +0200 Subject: [PATCH 08/13] 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 09/13] 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 10/13] 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 11/13] 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 12/13] 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 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 13/13] 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<()> {