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/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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 8aafa5e3ed9ae8b6094e7b458566a28824646a8b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 16 Jul 2026 23:29:41 +0200 Subject: [PATCH 08/39] [rustdoc] Correctly handle output options with `--show-coverage` --- .../{passes => }/calculate_doc_coverage.rs | 80 +++++++++++-------- src/librustdoc/config.rs | 9 ++- src/librustdoc/core.rs | 7 ++ src/librustdoc/lib.rs | 5 +- src/librustdoc/passes/mod.rs | 9 +-- 5 files changed, 69 insertions(+), 41 deletions(-) rename src/librustdoc/{passes => }/calculate_doc_coverage.rs (81%) diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/calculate_doc_coverage.rs similarity index 81% rename from src/librustdoc/passes/calculate_doc_coverage.rs rename to src/librustdoc/calculate_doc_coverage.rs index adf98afc46cc0..65bab8609f008 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/calculate_doc_coverage.rs @@ -1,6 +1,8 @@ //! Calculates information used for the --show-coverage flag. use std::collections::BTreeMap; +use std::fs::{File, create_dir_all}; +use std::io::{self, BufWriter, Write, stdout}; use std::ops; use rustc_hir as hir; @@ -10,27 +12,37 @@ use rustc_span::{FileName, RemapPathScopeComponents}; use serde::Serialize; use tracing::debug; -use crate::clean; -use crate::config::OutputFormat; +use crate::config::{OutputFormat, RenderOptions}; use crate::core::DocContext; +use crate::docfs::PathError; +use crate::error::Error; use crate::html::markdown::{ErrorCodes, find_testable_code}; -use crate::passes::Pass; -use crate::passes::check_doc_test_visibility::{Tests, should_have_doc_example}; +use crate::passes::{Tests, should_have_doc_example}; use crate::visit::DocVisitor; - -pub(crate) const CALCULATE_DOC_COVERAGE: Pass = Pass { - name: "calculate-doc-coverage", - run: Some(calculate_doc_coverage), - description: "counts the number of items with and without documentation", -}; - -fn calculate_doc_coverage(krate: clean::Crate, ctx: &mut DocContext<'_>) -> clean::Crate { +use crate::{clean, try_err}; + +pub(crate) fn run( + krate: &clean::Crate, + ctx: &mut DocContext<'_>, + options: &RenderOptions, +) -> Result<(), Error> { + let is_json = ctx.output_format == OutputFormat::CoverageJson; + let tcx = ctx.tcx; let mut calc = CoverageCalculator { items: Default::default(), ctx }; calc.visit_crate(&krate); - calc.print_results(); - - krate + if options.output_to_stdout { + calc.print_results(BufWriter::new(stdout().lock())) + .map_err(|error| Error::new(error, "")) + } else { + let out_dir = &options.output; + try_err!(create_dir_all(out_dir), out_dir); + let name = krate.name(tcx); + let mut out_file = out_dir.join(name.as_str()); + out_file.set_extension(if is_json { "json" } else { "txt" }); + let buf = try_err!(File::create_buffered(&out_file), out_file); + calc.print_results(buf).map_err(|error| Error::new(error, out_file)) + } } #[derive(Default, Copy, Clone, Serialize, Debug)] @@ -130,62 +142,66 @@ impl CoverageCalculator<'_, '_> { .expect("failed to convert JSON data to string") } - fn print_results(&self) { + fn print_results(&self, mut buf: impl Write) -> io::Result<()> { let output_format = self.ctx.output_format; if output_format == OutputFormat::CoverageJson { - println!("{}", self.to_json()); - return; + return writeln!(buf, "{}", self.to_json()); } let mut total = ItemCount::default(); - fn print_table_line() { - println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", ""); + fn print_table_line(buf: &mut impl Write) -> io::Result<()> { + writeln!(buf, "+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", "") } fn print_table_record( + buf: &mut impl Write, name: &str, count: ItemCount, percentage: f64, examples_percentage: f64, - ) { - println!( + ) -> io::Result<()> { + writeln!( + buf, "| {name:<35} | {with_docs:>10} | {percentage:>9.1}% | {with_examples:>10} | \ - {examples_percentage:>9.1}% |", + {examples_percentage:>9.1}% |", with_docs = count.with_docs, with_examples = count.with_examples, - ); + ) } - print_table_line(); - println!( + print_table_line(&mut buf)?; + writeln!( + buf, "| {:<35} | {:>10} | {:>10} | {:>10} | {:>10} |", "File", "Documented", "Percentage", "Examples", "Percentage", - ); - print_table_line(); + )?; + print_table_line(&mut buf)?; for (file, &count) in &self.items { if let Some(percentage) = count.percentage() { print_table_record( + &mut buf, &limit_filename_len( file.display(RemapPathScopeComponents::COVERAGE).to_string(), ), count, percentage, count.examples_percentage().unwrap_or(0.), - ); + )?; total += count; } } - print_table_line(); + print_table_line(&mut buf)?; print_table_record( + &mut buf, "Total", total, total.percentage().unwrap_or(0.0), total.examples_percentage().unwrap_or(0.0), - ); - print_table_line(); + )?; + print_table_line(&mut buf) } } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 840f9d025c3cf..0a3cbf537e5f1 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -726,7 +726,14 @@ impl Options { output_to_stdout = out_dir == "-"; PathBuf::from(out_dir) } - (None, None) => PathBuf::from("doc"), + (None, None) => { + if show_coverage { + // If no `-o` option is given and we're in the `--show-coverage` mode, by + // default we print on the stdout. + output_to_stdout = true; + } + PathBuf::from("doc") + } }; let cfgs = matches.opt_strs("cfg"); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c1ae5f977cb89..af1024580c544 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -452,6 +452,13 @@ pub(crate) fn run_global_ctxt( } } + if show_coverage + && let Err(error) = crate::calculate_doc_coverage::run(&krate, &mut ctxt, &render_options) + { + eprintln!("{error}"); + std::process::exit(1); + } + tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc))); krate = diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index be830cad6c735..0fadd78fd30b1 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -105,6 +105,7 @@ macro_rules! map { }} } +mod calculate_doc_coverage; mod clean; mod config; mod core; @@ -955,14 +956,14 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate); } - cache.crate_version = crate_version; - if show_coverage { // if we ran coverage, bail early, we don't need to also generate docs at this point // (also we didn't load in any of the useful passes) return; } + cache.crate_version = crate_version; + rustc_interface::passes::emit_delayed_lints(tcx); if render_opts.dep_info().is_some() { diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 18e1afaf8a242..725c2be4e2121 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -30,14 +30,13 @@ pub(crate) mod collect_intra_doc_links; pub(crate) use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; mod check_doc_test_visibility; -pub(crate) use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; +pub(crate) use self::check_doc_test_visibility::{ + CHECK_DOC_TEST_VISIBILITY, Tests, should_have_doc_example, +}; mod collect_trait_impls; pub(crate) use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; -mod calculate_doc_coverage; -pub(crate) use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE; - mod lint; pub(crate) use self::lint::RUN_LINTS; @@ -81,7 +80,6 @@ pub(crate) const PASSES: &[Pass] = &[ PROPAGATE_STABILITY, COLLECT_INTRA_DOC_LINKS, COLLECT_TRAIT_IMPLS, - CALCULATE_DOC_COVERAGE, RUN_LINTS, ]; @@ -103,7 +101,6 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ pub(crate) const COVERAGE_PASSES: &[ConditionalPass] = &[ ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), - ConditionalPass::always(CALCULATE_DOC_COVERAGE), ]; impl ConditionalPass { From f545db6b9f261b1dc3c58c6d42865fe729960933 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 16 Jul 2026 23:30:02 +0200 Subject: [PATCH 09/39] Add regression test for `--show-coverage` output --- tests/run-make/rustdoc-show-coverage/foo.rs | 5 ++ tests/run-make/rustdoc-show-coverage/rmake.rs | 53 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/run-make/rustdoc-show-coverage/foo.rs create mode 100644 tests/run-make/rustdoc-show-coverage/rmake.rs diff --git a/tests/run-make/rustdoc-show-coverage/foo.rs b/tests/run-make/rustdoc-show-coverage/foo.rs new file mode 100644 index 0000000000000..4892b4ce1ae69 --- /dev/null +++ b/tests/run-make/rustdoc-show-coverage/foo.rs @@ -0,0 +1,5 @@ +pub struct Bar; + +impl Bar { + pub fn foo() {} +} diff --git a/tests/run-make/rustdoc-show-coverage/rmake.rs b/tests/run-make/rustdoc-show-coverage/rmake.rs new file mode 100644 index 0000000000000..eb54bf7e544ca --- /dev/null +++ b/tests/run-make/rustdoc-show-coverage/rmake.rs @@ -0,0 +1,53 @@ +// This test ensures that `-o` option works as expected with `--show-coverage`. +// Regression test for . + +use run_make_support::{path, rustdoc}; +use run_make_support::rfs::{read_to_string, remove_file}; + +fn run_rustdoc(extra_args: &[&str]) -> String { + rustdoc() + .input("foo.rs") + .arg("-Zunstable-options") + .arg("--show-coverage") + .args(extra_args) + .run() + .stdout_utf8() +} + +fn check_print_stdout(extra_args: &[&str], stdout_check: &str) { + let out = run_rustdoc(extra_args); + + // By default, it shouldn't have created a `doc` folder. + assert!(!path("doc").exists(), "`doc` folder created with {extra_args:?}"); + // It should have display its output on stdout. + assert!(out.starts_with(stdout_check), "{out:?} doesn't start with {stdout_check:?}"); +} + +fn check_generate_file(ext: &str, extra_args: &[&str], file_check: &str) { + let mut args = extra_args.to_vec(); + args.push("-o"); + args.push("doc"); + let out = run_rustdoc(&args); + + // By default, it shouldn't have created a `doc` folder. + assert!(path("doc").exists(), "`doc` folder not created with {args:?}"); + let file = format!("doc/foo.{ext}"); + assert!(path(&file).exists()); + + assert!(out.is_empty(), "Shouldn't display anything to stdout and yet we got {out:?}"); + + let content = read_to_string(&file); + assert!(content.starts_with(file_check), "{content:?} doesn't start with {file_check:?}"); + remove_file(file); +} + +fn main() { + check_print_stdout(&[], "+-"); + check_print_stdout(&["-o", "-"], "+-"); + check_print_stdout(&["--output-format=json"], "{"); + check_print_stdout(&["--output-format=json", "-o", "-"], "{"); + + // Now we check that it works with "-o something". + check_generate_file("txt", &[], "+-"); + check_generate_file("json", &["--output-format=json"], "{"); +} From 65b6e98a104e0427bd66e50bdf3bca655320496f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 16 Jul 2026 23:34:15 +0200 Subject: [PATCH 10/39] Add small message to say where the output was generated --- src/librustdoc/calculate_doc_coverage.rs | 4 +++- tests/run-make/rustdoc-show-coverage/rmake.rs | 5 +++-- tests/rustdoc-ui/coverage/allow_missing_docs.rs | 2 +- tests/rustdoc-ui/coverage/basic.rs | 2 +- tests/rustdoc-ui/coverage/doc-examples-json.rs | 2 +- tests/rustdoc-ui/coverage/doc-examples.rs | 2 +- tests/rustdoc-ui/coverage/empty.rs | 2 +- tests/rustdoc-ui/coverage/enum-tuple-documented.rs | 2 +- tests/rustdoc-ui/coverage/enum-tuple.rs | 2 +- tests/rustdoc-ui/coverage/enums.rs | 2 +- tests/rustdoc-ui/coverage/exotic.rs | 2 +- tests/rustdoc-ui/coverage/json.rs | 2 +- tests/rustdoc-ui/coverage/private.rs | 2 +- tests/rustdoc-ui/coverage/statics-consts.rs | 2 +- tests/rustdoc-ui/coverage/traits.rs | 2 +- tests/rustdoc-ui/issues/issue-91713.stdout | 2 -- tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs | 2 +- tests/rustdoc-ui/show-coverage-json.rs | 2 +- tests/rustdoc-ui/show-coverage.rs | 2 +- 19 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/calculate_doc_coverage.rs b/src/librustdoc/calculate_doc_coverage.rs index 65bab8609f008..ae05e362f2383 100644 --- a/src/librustdoc/calculate_doc_coverage.rs +++ b/src/librustdoc/calculate_doc_coverage.rs @@ -41,7 +41,9 @@ pub(crate) fn run( let mut out_file = out_dir.join(name.as_str()); out_file.set_extension(if is_json { "json" } else { "txt" }); let buf = try_err!(File::create_buffered(&out_file), out_file); - calc.print_results(buf).map_err(|error| Error::new(error, out_file)) + calc.print_results(buf).map_err(|error| Error::new(error, &out_file))?; + println!("Generated output into {out_file:?}"); + Ok(()) } } diff --git a/tests/run-make/rustdoc-show-coverage/rmake.rs b/tests/run-make/rustdoc-show-coverage/rmake.rs index eb54bf7e544ca..59693b2829483 100644 --- a/tests/run-make/rustdoc-show-coverage/rmake.rs +++ b/tests/run-make/rustdoc-show-coverage/rmake.rs @@ -1,8 +1,8 @@ // This test ensures that `-o` option works as expected with `--show-coverage`. // Regression test for . -use run_make_support::{path, rustdoc}; use run_make_support::rfs::{read_to_string, remove_file}; +use run_make_support::{path, rustdoc}; fn run_rustdoc(extra_args: &[&str]) -> String { rustdoc() @@ -34,7 +34,8 @@ fn check_generate_file(ext: &str, extra_args: &[&str], file_check: &str) { let file = format!("doc/foo.{ext}"); assert!(path(&file).exists()); - assert!(out.is_empty(), "Shouldn't display anything to stdout and yet we got {out:?}"); + let expected = format!("Generated output into {file:?}\n"); + assert_eq!(out, expected, "Expected {expected:?}, got {out:?}"); let content = read_to_string(&file); assert!(content.starts_with(file_check), "{content:?} doesn't start with {file_check:?}"); diff --git a/tests/rustdoc-ui/coverage/allow_missing_docs.rs b/tests/rustdoc-ui/coverage/allow_missing_docs.rs index 43f0d731fdea0..feca5a1bfe3e9 100644 --- a/tests/rustdoc-ui/coverage/allow_missing_docs.rs +++ b/tests/rustdoc-ui/coverage/allow_missing_docs.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! Make sure to have some docs on your crate root diff --git a/tests/rustdoc-ui/coverage/basic.rs b/tests/rustdoc-ui/coverage/basic.rs index febcc80fbbb50..fc44f6826cb9c 100644 --- a/tests/rustdoc-ui/coverage/basic.rs +++ b/tests/rustdoc-ui/coverage/basic.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass #![feature(extern_types)] diff --git a/tests/rustdoc-ui/coverage/doc-examples-json.rs b/tests/rustdoc-ui/coverage/doc-examples-json.rs index 4aa4bf23771d9..bfec2600cb875 100644 --- a/tests/rustdoc-ui/coverage/doc-examples-json.rs +++ b/tests/rustdoc-ui/coverage/doc-examples-json.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ compile-flags:-Z unstable-options --output-format json --show-coverage +//@ compile-flags:-Z unstable-options --output-format json --show-coverage -o - // This check ensures that only one doc example is counted since they're "optional" on // certain items. diff --git a/tests/rustdoc-ui/coverage/doc-examples.rs b/tests/rustdoc-ui/coverage/doc-examples.rs index 283d9c424aa19..dd8969f934ee2 100644 --- a/tests/rustdoc-ui/coverage/doc-examples.rs +++ b/tests/rustdoc-ui/coverage/doc-examples.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! This test ensure that only rust code examples are counted. diff --git a/tests/rustdoc-ui/coverage/empty.rs b/tests/rustdoc-ui/coverage/empty.rs index bcd3e48988b15..fd9f1e617fbec 100644 --- a/tests/rustdoc-ui/coverage/empty.rs +++ b/tests/rustdoc-ui/coverage/empty.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass // an empty crate still has one item to document: the crate root diff --git a/tests/rustdoc-ui/coverage/enum-tuple-documented.rs b/tests/rustdoc-ui/coverage/enum-tuple-documented.rs index 4cbeb7a164da1..9e88e896f8da7 100644 --- a/tests/rustdoc-ui/coverage/enum-tuple-documented.rs +++ b/tests/rustdoc-ui/coverage/enum-tuple-documented.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass // The point of this test is to ensure that the number of "documented" items diff --git a/tests/rustdoc-ui/coverage/enum-tuple.rs b/tests/rustdoc-ui/coverage/enum-tuple.rs index 5cbc52a7d033f..25d3c9f57bafe 100644 --- a/tests/rustdoc-ui/coverage/enum-tuple.rs +++ b/tests/rustdoc-ui/coverage/enum-tuple.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! (remember the crate root is still a module) diff --git a/tests/rustdoc-ui/coverage/enums.rs b/tests/rustdoc-ui/coverage/enums.rs index 29e4198457610..bdb213c2a53b7 100644 --- a/tests/rustdoc-ui/coverage/enums.rs +++ b/tests/rustdoc-ui/coverage/enums.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! (remember the crate root is still a module) diff --git a/tests/rustdoc-ui/coverage/exotic.rs b/tests/rustdoc-ui/coverage/exotic.rs index 9fc1498cb2a3a..2beb890b21926 100644 --- a/tests/rustdoc-ui/coverage/exotic.rs +++ b/tests/rustdoc-ui/coverage/exotic.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass #![feature(rustdoc_internals)] diff --git a/tests/rustdoc-ui/coverage/json.rs b/tests/rustdoc-ui/coverage/json.rs index bfa8dc7008305..dcab7df252249 100644 --- a/tests/rustdoc-ui/coverage/json.rs +++ b/tests/rustdoc-ui/coverage/json.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ compile-flags:-Z unstable-options --output-format json --show-coverage +//@ compile-flags:-Z unstable-options --output-format json --show-coverage -o - pub mod foo { /// Hello! diff --git a/tests/rustdoc-ui/coverage/private.rs b/tests/rustdoc-ui/coverage/private.rs index 91490eff7a8d5..3b78c5d761dbc 100644 --- a/tests/rustdoc-ui/coverage/private.rs +++ b/tests/rustdoc-ui/coverage/private.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage --document-private-items +//@ compile-flags:-Z unstable-options --show-coverage --document-private-items -o - //@ check-pass #![allow(unused)] diff --git a/tests/rustdoc-ui/coverage/statics-consts.rs b/tests/rustdoc-ui/coverage/statics-consts.rs index 85cc23847396e..5177673f7958a 100644 --- a/tests/rustdoc-ui/coverage/statics-consts.rs +++ b/tests/rustdoc-ui/coverage/statics-consts.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! gotta make sure we can count statics and consts correctly, too diff --git a/tests/rustdoc-ui/coverage/traits.rs b/tests/rustdoc-ui/coverage/traits.rs index 89044369e6a77..37e147004d714 100644 --- a/tests/rustdoc-ui/coverage/traits.rs +++ b/tests/rustdoc-ui/coverage/traits.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass #![feature(trait_alias)] diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index e7b8a1dccf802..0243f6cd533a0 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -8,7 +8,6 @@ strip-aliased-non-local - strips all non-local private aliased items from the ou propagate-stability - propagates stability to child items collect-intra-doc-links - resolves intra-doc links collect-trait-impls - retrieves trait impls for items in the crate -calculate-doc-coverage - counts the number of items with and without documentation run-lints - runs some of rustdoc's lints Default passes for rustdoc: @@ -26,4 +25,3 @@ collect-intra-doc-links Passes run with `--show-coverage`: strip-hidden (when not --document-hidden-items) strip-private (when not --document-private-items) -calculate-doc-coverage diff --git a/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs b/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs index 0609b515e5ca8..97cdedecb0aaf 100644 --- a/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs +++ b/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs @@ -1,2 +1,2 @@ -//@ compile-flags: --show-coverage --output-format=json --emit=dep-info -Zunstable-options +//@ compile-flags: --show-coverage --output-format=json --emit=dep-info -Zunstable-options -o - //@ build-pass diff --git a/tests/rustdoc-ui/show-coverage-json.rs b/tests/rustdoc-ui/show-coverage-json.rs index 3851e34fe3599..e7ddc69d79f8a 100644 --- a/tests/rustdoc-ui/show-coverage-json.rs +++ b/tests/rustdoc-ui/show-coverage-json.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z unstable-options --show-coverage --output-format=json +//@ compile-flags: -Z unstable-options --show-coverage --output-format=json -o - //@ check-pass mod bar { diff --git a/tests/rustdoc-ui/show-coverage.rs b/tests/rustdoc-ui/show-coverage.rs index 00bb1606a82cb..1f9c3a8f805b7 100644 --- a/tests/rustdoc-ui/show-coverage.rs +++ b/tests/rustdoc-ui/show-coverage.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z unstable-options --show-coverage +//@ compile-flags: -Z unstable-options --show-coverage -o - //@ check-pass mod bar { From 854bbe76f0897aeae84b441a6c1d6b9c95a52811 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Jul 2026 12:16:04 +0200 Subject: [PATCH 11/39] Fix `tests/run-make/rustdoc-show-coverage/rmake.rs` by requiring `needs-target-std` --- tests/run-make/rustdoc-show-coverage/rmake.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-make/rustdoc-show-coverage/rmake.rs b/tests/run-make/rustdoc-show-coverage/rmake.rs index 59693b2829483..cc4956f2c58c2 100644 --- a/tests/run-make/rustdoc-show-coverage/rmake.rs +++ b/tests/run-make/rustdoc-show-coverage/rmake.rs @@ -1,6 +1,8 @@ // This test ensures that `-o` option works as expected with `--show-coverage`. // Regression test for . +//@ needs-target-std + use run_make_support::rfs::{read_to_string, remove_file}; use run_make_support::{path, rustdoc}; From 098056ae19c91fd03701e36476a166cb5d84f809 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 24 Jul 2026 12:09:48 +0200 Subject: [PATCH 12/39] Move `rustdoc-ui` `--show-coverage` tests into the `coverage` folder --- tests/rustdoc-ui/{ => coverage}/doctest-output.rs | 0 tests/rustdoc-ui/{ => coverage}/doctest-output.stderr | 0 .../{ => coverage}/output-format-coveragejson-emit-depinfo.rs | 0 .../output-format-coveragejson-emit-depinfo.stdout | 0 .../output-format-json-emit-html.html_non_static.stderr | 0 ...output-format-json-emit-html.html_non_static_coverage.stderr | 0 .../output-format-json-emit-html.html_static.stderr | 0 .../output-format-json-emit-html.html_static_coverage.stderr | 0 tests/rustdoc-ui/{ => coverage}/output-format-json-emit-html.rs | 0 .../{ => coverage}/show-coverage-json-emit-html-non-static.rs | 0 .../show-coverage-json-emit-html-non-static.stderr | 0 tests/rustdoc-ui/{ => coverage}/show-coverage-json.rs | 0 tests/rustdoc-ui/{ => coverage}/show-coverage-json.stdout | 0 tests/rustdoc-ui/{ => coverage}/show-coverage.rs | 0 tests/rustdoc-ui/{ => coverage}/show-coverage.stdout | 2 +- 15 files changed, 1 insertion(+), 1 deletion(-) rename tests/rustdoc-ui/{ => coverage}/doctest-output.rs (100%) rename tests/rustdoc-ui/{ => coverage}/doctest-output.stderr (100%) rename tests/rustdoc-ui/{ => coverage}/output-format-coveragejson-emit-depinfo.rs (100%) rename tests/rustdoc-ui/{ => coverage}/output-format-coveragejson-emit-depinfo.stdout (100%) rename tests/rustdoc-ui/{ => coverage}/output-format-json-emit-html.html_non_static.stderr (100%) rename tests/rustdoc-ui/{ => coverage}/output-format-json-emit-html.html_non_static_coverage.stderr (100%) rename tests/rustdoc-ui/{ => coverage}/output-format-json-emit-html.html_static.stderr (100%) rename tests/rustdoc-ui/{ => coverage}/output-format-json-emit-html.html_static_coverage.stderr (100%) rename tests/rustdoc-ui/{ => coverage}/output-format-json-emit-html.rs (100%) rename tests/rustdoc-ui/{ => coverage}/show-coverage-json-emit-html-non-static.rs (100%) rename tests/rustdoc-ui/{ => coverage}/show-coverage-json-emit-html-non-static.stderr (100%) rename tests/rustdoc-ui/{ => coverage}/show-coverage-json.rs (100%) rename tests/rustdoc-ui/{ => coverage}/show-coverage-json.stdout (100%) rename tests/rustdoc-ui/{ => coverage}/show-coverage.rs (100%) rename tests/rustdoc-ui/{ => coverage}/show-coverage.stdout (90%) diff --git a/tests/rustdoc-ui/doctest-output.rs b/tests/rustdoc-ui/coverage/doctest-output.rs similarity index 100% rename from tests/rustdoc-ui/doctest-output.rs rename to tests/rustdoc-ui/coverage/doctest-output.rs diff --git a/tests/rustdoc-ui/doctest-output.stderr b/tests/rustdoc-ui/coverage/doctest-output.stderr similarity index 100% rename from tests/rustdoc-ui/doctest-output.stderr rename to tests/rustdoc-ui/coverage/doctest-output.stderr diff --git a/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs b/tests/rustdoc-ui/coverage/output-format-coveragejson-emit-depinfo.rs similarity index 100% rename from tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs rename to tests/rustdoc-ui/coverage/output-format-coveragejson-emit-depinfo.rs diff --git a/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.stdout b/tests/rustdoc-ui/coverage/output-format-coveragejson-emit-depinfo.stdout similarity index 100% rename from tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.stdout rename to tests/rustdoc-ui/coverage/output-format-coveragejson-emit-depinfo.stdout diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_non_static.stderr b/tests/rustdoc-ui/coverage/output-format-json-emit-html.html_non_static.stderr similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.html_non_static.stderr rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.html_non_static.stderr diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_non_static_coverage.stderr b/tests/rustdoc-ui/coverage/output-format-json-emit-html.html_non_static_coverage.stderr similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.html_non_static_coverage.stderr rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.html_non_static_coverage.stderr diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_static.stderr b/tests/rustdoc-ui/coverage/output-format-json-emit-html.html_static.stderr similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.html_static.stderr rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.html_static.stderr diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_static_coverage.stderr b/tests/rustdoc-ui/coverage/output-format-json-emit-html.html_static_coverage.stderr similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.html_static_coverage.stderr rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.html_static_coverage.stderr diff --git a/tests/rustdoc-ui/output-format-json-emit-html.rs b/tests/rustdoc-ui/coverage/output-format-json-emit-html.rs similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.rs rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.rs diff --git a/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.rs b/tests/rustdoc-ui/coverage/show-coverage-json-emit-html-non-static.rs similarity index 100% rename from tests/rustdoc-ui/show-coverage-json-emit-html-non-static.rs rename to tests/rustdoc-ui/coverage/show-coverage-json-emit-html-non-static.rs diff --git a/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.stderr b/tests/rustdoc-ui/coverage/show-coverage-json-emit-html-non-static.stderr similarity index 100% rename from tests/rustdoc-ui/show-coverage-json-emit-html-non-static.stderr rename to tests/rustdoc-ui/coverage/show-coverage-json-emit-html-non-static.stderr diff --git a/tests/rustdoc-ui/show-coverage-json.rs b/tests/rustdoc-ui/coverage/show-coverage-json.rs similarity index 100% rename from tests/rustdoc-ui/show-coverage-json.rs rename to tests/rustdoc-ui/coverage/show-coverage-json.rs diff --git a/tests/rustdoc-ui/show-coverage-json.stdout b/tests/rustdoc-ui/coverage/show-coverage-json.stdout similarity index 100% rename from tests/rustdoc-ui/show-coverage-json.stdout rename to tests/rustdoc-ui/coverage/show-coverage-json.stdout diff --git a/tests/rustdoc-ui/show-coverage.rs b/tests/rustdoc-ui/coverage/show-coverage.rs similarity index 100% rename from tests/rustdoc-ui/show-coverage.rs rename to tests/rustdoc-ui/coverage/show-coverage.rs diff --git a/tests/rustdoc-ui/show-coverage.stdout b/tests/rustdoc-ui/coverage/show-coverage.stdout similarity index 90% rename from tests/rustdoc-ui/show-coverage.stdout rename to tests/rustdoc-ui/coverage/show-coverage.stdout index b9e0316545e77..42c17f8bbd696 100644 --- a/tests/rustdoc-ui/show-coverage.stdout +++ b/tests/rustdoc-ui/coverage/show-coverage.stdout @@ -1,7 +1,7 @@ +-------------------------------------+------------+------------+------------+------------+ | File | Documented | Percentage | Examples | Percentage | +-------------------------------------+------------+------------+------------+------------+ -| ...ests/rustdoc-ui/show-coverage.rs | 1 | 50.0% | 1 | 100.0% | +| ...doc-ui/coverage/show-coverage.rs | 1 | 50.0% | 1 | 100.0% | +-------------------------------------+------------+------------+------------+------------+ | Total | 1 | 50.0% | 1 | 100.0% | +-------------------------------------+------------+------------+------------+------------+ From c680b5097300ec4229f27fded5a14e177bf2eead Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 24 Jul 2026 12:14:27 +0200 Subject: [PATCH 13/39] Mention how the `-o` option behaves with the `--show-coverage` option --- src/doc/rustdoc/src/unstable-features.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 26985e67abb6e..9799f60c2802b 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -502,6 +502,15 @@ Calculating code examples follows these rules: * typedef 2. If one of the previously listed items has a code example, then it'll be counted. +If you use the `-o` option with it, it will generate the file into the given older name. For example: + +```shell +rustdoc foo.rs --show-coverage -o doc +``` + +Will generate a `foo.txt` into the `doc` folder. If the `-o` option isn't passed, it will display +on stdout. + ### JSON output When using `--output-format json` with this option, it will display the coverage information in 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 14/39] 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 15/39] 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 41704bd60000d194cd3b1f72eeadbef60b747ec8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jul 2026 23:28:02 +0200 Subject: [PATCH 16/39] Only run `rustdoc-show-coverage/rmake.rs` test on linux to make things easier --- tests/run-make/rustdoc-show-coverage/rmake.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-make/rustdoc-show-coverage/rmake.rs b/tests/run-make/rustdoc-show-coverage/rmake.rs index cc4956f2c58c2..90ad50267b8ad 100644 --- a/tests/run-make/rustdoc-show-coverage/rmake.rs +++ b/tests/run-make/rustdoc-show-coverage/rmake.rs @@ -2,6 +2,8 @@ // Regression test for . //@ needs-target-std +// To not have to deal with windows paths: +//@ only-linux use run_make_support::rfs::{read_to_string, remove_file}; use run_make_support::{path, rustdoc}; From ab3e64f0803cc633551f8482a7bed70982622c23 Mon Sep 17 00:00:00 2001 From: SzilvasiPeter Date: Tue, 28 Jul 2026 09:50:31 +0200 Subject: [PATCH 17/39] 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 18/39] 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 19/39] 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 20/39] 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 bf8708efd809273b6e55d57a7510dd1b81fc02d8 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 28 Jul 2026 14:48:51 -0700 Subject: [PATCH 21/39] 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 22/39] 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 23/39] 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 24/39] 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 25/39] 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 26/39] 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 27/39] 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 28/39] 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 29/39] 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 30/39] 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 31/39] 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 32/39] 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 d80021794effd74c77ed1022cb03525c954357cd Mon Sep 17 00:00:00 2001 From: Rachit2323 Date: Wed, 29 Jul 2026 15:50:08 +0530 Subject: [PATCH 33/39] 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 34/39] 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); } From 9ce1973de5d6581fbf7e07cfda78c1a36115e188 Mon Sep 17 00:00:00 2001 From: Sa4dUs Date: Thu, 18 Jun 2026 10:17:18 +0200 Subject: [PATCH 35/39] add offload intrinsic typecheck --- compiler/rustc_hir_typeck/src/expr.rs | 8 +- compiler/rustc_hir_typeck/src/intrinsicck.rs | 105 ++++++++++++++++++ .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 3 + compiler/rustc_hir_typeck/src/writeback.rs | 16 +++ .../rustc_middle/src/ty/typeck_results.rs | 4 + tests/ui/offload/check_config.fail.stderr | 2 +- tests/ui/offload/check_config.rs | 6 +- 7 files changed, 139 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3bcad2460e78f..359c9263bea9f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -614,7 +614,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - if let ty::FnDef(did, _) = *ty.kind() { + if let ty::FnDef(did, args) = *ty.kind() { let fn_sig = ty.fn_sig(tcx); if tcx.is_intrinsic(did, sym::transmute) { @@ -631,6 +631,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be known if explicitly specified via turbofish). self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id)); } + if tcx.is_intrinsic(did, sym::offload) { + let f = args.type_at(0); + let t = args.type_at(1); + let r = args.type_at(2); + self.deferred_offload_checks.borrow_mut().push((f, t, r, expr.hir_id)); + } if !tcx.features().unsized_fn_params() { // We want to remove some Sized bounds from std functions, // but don't want to expose the removal to stable Rust. diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 430f4d828b91f..4548348edfc7d 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -140,6 +140,108 @@ fn check_transmute<'tcx>( } } +fn check_offload<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + kernel_ty: Ty<'tcx>, + args_ty: Ty<'tcx>, + ret_ty: Ty<'tcx>, + hir_id: HirId, +) -> Result<(), ErrorGuaranteed> { + let span = tcx.hir_span(hir_id); + let ty::FnDef(kernel_def_id, kernel_args) = *kernel_ty.kind() else { + let err = tcx + .sess + .dcx() + .struct_span_err( + span, + format!("expected a function item for the offload kernel, found `{}`", kernel_ty), + ) + .emit(); + return Err(err); + }; + + let kernel_sig = tcx.fn_sig(kernel_def_id).instantiate(tcx, kernel_args).skip_norm_wip(); + let kernel_sig = tcx.instantiate_bound_regions_with_erased(kernel_sig); + + let ty::Tuple(tuple_fields) = *args_ty.kind() else { + let err = tcx + .sess + .dcx() + .struct_span_err( + span, + format!("expected a tuple for the offload arguments, found `{}`", args_ty), + ) + .emit(); + return Err(err); + }; + + if kernel_sig.inputs().len() != tuple_fields.len() { + let err = tcx + .sess + .dcx() + .struct_span_err( + span, + format!( + "offload kernel expects {} arguments, but {} arguments were provided", + kernel_sig.inputs().len(), + tuple_fields.len() + ), + ) + .emit(); + return Err(err); + } + + let normalize = |ty| { + if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)) { + ty + } else { + Ty::new_error_with_message( + tcx, + span, + format!("tried to normalize non-wf type {ty:#?} in check_offload"), + ) + } + }; + + let mut result = Ok(()); + + for (i, (&input_ty, arg_ty)) in kernel_sig.inputs().iter().zip(tuple_fields.iter()).enumerate() + { + let norm_input_ty = normalize(input_ty); + let norm_arg_ty = normalize(arg_ty); + if norm_input_ty != norm_arg_ty { + let err = tcx + .sess + .dcx() + .struct_span_err( + span, + format!( + "type mismatch in offload kernel argument {}: expected `{}`, found `{}`", + i, norm_input_ty, norm_arg_ty + ), + ) + .emit(); + result = Err(err); + } + } + + let norm_kernel_ret = normalize(kernel_sig.output()); + let norm_offload_ret = normalize(ret_ty); + if norm_kernel_ret != norm_offload_ret { + let err = tcx.sess.dcx().struct_span_err( + span, + format!( + "offload kernel return type mismatch: kernel returns `{}`, but offload call expects `{}`", + norm_kernel_ret, norm_offload_ret + ) + ).emit(); + result = Err(err); + } + + result +} + pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), ErrorGuaranteed> { assert!(!tcx.is_typeck_child(owner.to_def_id())); let typeck_results = tcx.typeck(owner); @@ -152,5 +254,8 @@ pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), for &(from, to, hir_id) in &typeck_results.transmutes_to_check { result = result.and(check_transmute(tcx, typing_env, from, to, hir_id)); } + for &(kernel_ty, args_ty, ret_ty, hir_id) in &typeck_results.offloads_to_check { + result = result.and(check_offload(tcx, typing_env, kernel_ty, args_ty, ret_ty, hir_id)); + } result } diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index e4dcead1f7954..a475d073f452d 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -57,6 +57,8 @@ pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) deferred_transmute_checks: RefCell, Ty<'tcx>, HirId)>>, + pub(super) deferred_offload_checks: RefCell, Ty<'tcx>, Ty<'tcx>, HirId)>>, + pub(super) deferred_asm_checks: RefCell, HirId)>>, pub(super) deferred_repeat_expr_checks: @@ -97,6 +99,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), deferred_transmute_checks: RefCell::new(Vec::new()), + deferred_offload_checks: RefCell::new(Vec::new()), deferred_asm_checks: RefCell::new(Vec::new()), deferred_repeat_expr_checks: RefCell::new(Vec::new()), diverging_type_vars: RefCell::new(Default::default()), diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 4161975d88ea9..7b1f38f882747 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -76,6 +76,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_user_provided_sigs(); wbcx.visit_coroutine_interior(); wbcx.visit_transmutes(); + wbcx.visit_offloads(); wbcx.visit_offset_of_container_types(); wbcx.visit_potentially_region_dependent_goals(); @@ -544,6 +545,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_offloads(&mut self) { + let tcx = self.tcx(); + let fcx_typeck_results = self.fcx.typeck_results.borrow(); + assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); + for &(kernel_ty, args_ty, ret_ty, hir_id) in + self.fcx.deferred_offload_checks.borrow().iter() + { + let span = tcx.hir_span(hir_id); + let kernel_ty = self.resolve(kernel_ty, &span); + let args_ty = self.resolve(args_ty, &span); + let ret_ty = self.resolve(ret_ty, &span); + self.typeck_results.offloads_to_check.push((kernel_ty, args_ty, ret_ty, hir_id)); + } + } + fn visit_opaque_types_next(&mut self) { let mut fcx_typeck_results = self.fcx.typeck_results.borrow_mut(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index e11bc6d38495b..7624d860aa1ac 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -223,6 +223,9 @@ pub struct TypeckResults<'tcx> { /// computation. pub transmutes_to_check: Vec<(Ty<'tcx>, Ty<'tcx>, HirId)>, + /// Stores the types involved in calls to `offload` intrinsic. + pub offloads_to_check: Vec<(Ty<'tcx>, Ty<'tcx>, Ty<'tcx>, HirId)>, + /// Container types and field indices of `offset_of!` expressions offset_of_data: ItemLocalMap, VariantIdx, FieldIdx)>>, } @@ -256,6 +259,7 @@ impl<'tcx> TypeckResults<'tcx> { potentially_region_dependent_goals: Default::default(), closure_size_eval: Default::default(), transmutes_to_check: Default::default(), + offloads_to_check: Default::default(), offset_of_data: Default::default(), } } diff --git a/tests/ui/offload/check_config.fail.stderr b/tests/ui/offload/check_config.fail.stderr index a9162ed926cb0..f1c73687889fd 100644 --- a/tests/ui/offload/check_config.fail.stderr +++ b/tests/ui/offload/check_config.fail.stderr @@ -1,4 +1,4 @@ -error: using the offload feature requires -Z offload=Enable +error: using the offload feature requires -Z offload= error: using the offload feature requires -C lto=fat diff --git a/tests/ui/offload/check_config.rs b/tests/ui/offload/check_config.rs index 667c6d9788bae..69afe65a308b4 100644 --- a/tests/ui/offload/check_config.rs +++ b/tests/ui/offload/check_config.rs @@ -3,10 +3,10 @@ //@ needs-enzyme //@[pass] build-pass //@[fail] build-fail -//@[pass] compile-flags: -Zunstable-options -Zoffload=Enable -Clto=fat --emit=metadata +//@[pass] compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat --emit=metadata //@[fail] compile-flags: -Clto=thin -//[fail]~? ERROR: using the offload feature requires -Z offload=Enable +//[fail]~? ERROR: using the offload feature requires -Z offload= //[fail]~? ERROR: using the offload feature requires -C lto=fat #![feature(core_intrinsics)] @@ -17,7 +17,7 @@ fn main() { } fn kernel_1(x: &mut [f32; 256]) { - core::intrinsics::offload(_kernel_1, (x,)) + core::intrinsics::offload(_kernel_1, [1, 1, 1], [1, 1, 1], 0, (x,)) } fn _kernel_1(x: &mut [f32; 256]) {} From f6e39fbff34eb7d921e79836b097028b796cb54c Mon Sep 17 00:00:00 2001 From: Sa4dUs Date: Mon, 29 Jun 2026 20:40:38 +0200 Subject: [PATCH 36/39] fix and add tests --- tests/codegen-llvm/gpu_offload/scalar_host.rs | 21 ++++++++------- tests/codegen-llvm/gpu_offload/slice_host.rs | 4 +-- tests/ui/offload/non_tuple_args.rs | 11 ++++++++ tests/ui/offload/non_tuple_args.stderr | 12 +++++++++ tests/ui/offload/type_mismatch.rs | 25 ++++++++++++++++++ tests/ui/offload/type_mismatch.stderr | 26 +++++++++++++++++++ 6 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 tests/ui/offload/non_tuple_args.rs create mode 100644 tests/ui/offload/non_tuple_args.stderr create mode 100644 tests/ui/offload/type_mismatch.rs create mode 100644 tests/ui/offload/type_mismatch.stderr diff --git a/tests/codegen-llvm/gpu_offload/scalar_host.rs b/tests/codegen-llvm/gpu_offload/scalar_host.rs index 3470761be06c8..66c910c439e46 100644 --- a/tests/codegen-llvm/gpu_offload/scalar_host.rs +++ b/tests/codegen-llvm/gpu_offload/scalar_host.rs @@ -13,21 +13,22 @@ // CHECK: define{{( dso_local)?}} void @main() // CHECK-NOT: define // CHECK: %addr = alloca i64, align 8 -// CHECK: store double 4.200000e+01, ptr [[TMP:%[^,]+]], align 8 -// CHECK: [[VAL:%[0-9]+]] = load double, ptr [[TMP]], align 8 -// CHECK: store double [[VAL]], ptr %addr, align 8 -// CHECK: %1 = getelementptr inbounds nuw i8, ptr %.offload_baseptrs, i64 8 -// CHECK-NEXT: store double [[VAL]], ptr %1, align 8 -// CHECK-NEXT: %2 = getelementptr inbounds nuw i8, ptr %.offload_ptrs, i64 8 -// CHECK-NEXT: store ptr %addr, ptr %2, align 8 +// CHECK: store float 4.200000e+01, ptr [[TMP:%[^,]+]], align 4 +// CHECK: [[VAL:%[0-9]+]] = load i32, ptr [[TMP]], align 4 +// CHECK: [[VAL_I64:%[0-9]+]] = zext i32 [[VAL]] to i64 +// CHECK: store i64 [[VAL_I64]], ptr %addr, align 8 +// CHECK: [[REG_GEP1:%[^,]+]] = getelementptr inbounds nuw i8, ptr %.offload_baseptrs, i64 8 +// CHECK-NEXT: store i64 [[VAL_I64]], ptr [[REG_GEP1]], align 8 +// CHECK-NEXT: [[REG_GEP2:%[^,]+]] = getelementptr inbounds nuw i8, ptr %.offload_ptrs, i64 8 +// CHECK-NEXT: store ptr %addr, ptr [[REG_GEP2]], align 8 // CHECK-NEXT: call void @__tgt_target_data_begin_mapper #[unsafe(no_mangle)] fn main() { - let mut x = 0.0; - let k = core::hint::black_box(42.0); + let mut x = 0.0f32; + let k = core::hint::black_box(42.0f32); - core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, (&mut x, k)); + core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, (&mut x as *mut f32, k)); } unsafe extern "C" { diff --git a/tests/codegen-llvm/gpu_offload/slice_host.rs b/tests/codegen-llvm/gpu_offload/slice_host.rs index d4157d24e03dd..0f27821ef765c 100644 --- a/tests/codegen-llvm/gpu_offload/slice_host.rs +++ b/tests/codegen-llvm/gpu_offload/slice_host.rs @@ -26,8 +26,8 @@ #[unsafe(no_mangle)] fn main() { - let mut x = [0.0, 0.0, 0.0, 0.0]; - core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, ((&mut x) as &mut [f64],)); + let mut x = [0.0f32, 0.0, 0.0, 0.0]; + core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, ((&mut x) as &mut [f32],)); } unsafe extern "C" { diff --git a/tests/ui/offload/non_tuple_args.rs b/tests/ui/offload/non_tuple_args.rs new file mode 100644 index 0000000000000..0a07c99a26d34 --- /dev/null +++ b/tests/ui/offload/non_tuple_args.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat + +#![feature(core_intrinsics)] + +fn main() { + // args_ty is not a tuple + core::intrinsics::offload::<_, _, ()>(kernel_0, [1, 1, 1], [1, 1, 1], 0, 42); + //~^ ERROR `{integer}` is not a tuple +} + +fn kernel_0() {} diff --git a/tests/ui/offload/non_tuple_args.stderr b/tests/ui/offload/non_tuple_args.stderr new file mode 100644 index 0000000000000..8b59d6828c6f2 --- /dev/null +++ b/tests/ui/offload/non_tuple_args.stderr @@ -0,0 +1,12 @@ +error[E0277]: `{integer}` is not a tuple + --> $DIR/non_tuple_args.rs:7:36 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_0, [1, 1, 1], [1, 1, 1], 0, 42); + | ^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `{integer}` + | +note: required by a bound in `offload` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/offload/type_mismatch.rs b/tests/ui/offload/type_mismatch.rs new file mode 100644 index 0000000000000..039519c431db8 --- /dev/null +++ b/tests/ui/offload/type_mismatch.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat + +#![feature(core_intrinsics)] + +fn main() { + // kernel_ty is not a function item + let not_fn = 42; + core::intrinsics::offload::<_, _, ()>(not_fn, [1, 1, 1], [1, 1, 1], 0, ()); + //~^ ERROR expected a function item for the offload kernel, found `i32` + + // argument count mismatch + core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, ()); + //~^ ERROR offload kernel expects 1 arguments, but 0 arguments were provided + + // argument type mismatch + core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, (42.0f64,)); + //~^ ERROR type mismatch in offload kernel argument 0: expected `f32`, found `f64` + + // return type mismatch + let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, ()); + //~^ ERROR offload kernel return type mismatch: kernel returns `()`, but offload call expects `f64` +} + +fn kernel_0() {} +fn kernel_1(_x: f32) {} diff --git a/tests/ui/offload/type_mismatch.stderr b/tests/ui/offload/type_mismatch.stderr new file mode 100644 index 0000000000000..abbf9a0f2f786 --- /dev/null +++ b/tests/ui/offload/type_mismatch.stderr @@ -0,0 +1,26 @@ +error: expected a function item for the offload kernel, found `i32` + --> $DIR/type_mismatch.rs:8:5 + | +LL | core::intrinsics::offload::<_, _, ()>(not_fn, [1, 1, 1], [1, 1, 1], 0, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: offload kernel expects 1 arguments, but 0 arguments were provided + --> $DIR/type_mismatch.rs:12:5 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: type mismatch in offload kernel argument 0: expected `f32`, found `f64` + --> $DIR/type_mismatch.rs:16:5 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, (42.0f64,)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: offload kernel return type mismatch: kernel returns `()`, but offload call expects `f64` + --> $DIR/type_mismatch.rs:20:18 + | +LL | let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + From a6776aad96d37c881976eadf8c521a576da8b513 Mon Sep 17 00:00:00 2001 From: Sa4dUs Date: Thu, 2 Jul 2026 17:59:54 +0300 Subject: [PATCH 37/39] proper location --- compiler/rustc_hir_typeck/src/expr.rs | 1 + compiler/rustc_hir_typeck/src/intrinsicck.rs | 12 ++++++++++++ compiler/rustc_hir_typeck/src/lib.rs | 1 + compiler/rustc_interface/src/passes.rs | 1 + compiler/rustc_middle/src/queries.rs | 5 +++++ 5 files changed, 20 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 359c9263bea9f..cf4f5f6da37e2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -635,6 +635,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let f = args.type_at(0); let t = args.type_at(1); let r = args.type_at(2); + // Defer offload checks to check generics later once types are fully inferred. self.deferred_offload_checks.borrow_mut().push((f, t, r, expr.hir_id)); } if !tcx.features().unsized_fn_params() { diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 4548348edfc7d..746178ca6faeb 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -254,6 +254,18 @@ pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), for &(from, to, hir_id) in &typeck_results.transmutes_to_check { result = result.and(check_transmute(tcx, typing_env, from, to, hir_id)); } + result +} + +pub(crate) fn check_offloads(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), ErrorGuaranteed> { + assert!(!tcx.is_typeck_child(owner.to_def_id())); + let typeck_results = tcx.typeck(owner); + if let Some(e) = typeck_results.tainted_by_errors { + return Err(e); + }; + + let typing_env = ty::TypingEnv::codegen(tcx, owner); + let mut result = Ok(()); for &(kernel_ty, args_ty, ret_ty, hir_id) in &typeck_results.offloads_to_check { result = result.and(check_offload(tcx, typing_env, kernel_ty, args_ty, ret_ty, hir_id)); } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index dce7f0bd67794..5c5bf77609ce2 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -721,6 +721,7 @@ pub fn provide(providers: &mut Providers) { typeck_root, used_trait_imports, check_transmutes: intrinsicck::check_transmutes, + check_offloads: intrinsicck::check_offloads, ..*providers }; } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 2f32a6b208b6c..a914fa997106b 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1153,6 +1153,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { if not_typeck_child { tcx.ensure_ok().mir_borrowck(def_id); tcx.ensure_ok().check_transmutes(def_id); + tcx.ensure_ok().check_offloads(def_id); } tcx.ensure_ok().has_ffi_unwind_calls(def_id); tcx.ensure_ok().check_liveness(def_id); diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index cbd54ec959c6a..50f59c2c95c5a 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -1123,6 +1123,11 @@ rustc_queries! { desc { "check transmute calls inside `{}`", tcx.def_path_str(key) } } + /// Unsafety-check this `LocalDefId`. + query check_offloads(key: LocalDefId) -> Result<(), ErrorGuaranteed> { + desc { "check offload calls inside `{}`", tcx.def_path_str(key) } + } + /// Unsafety-check this `LocalDefId`. query check_unsafety(key: LocalDefId) { desc { "unsafety-checking `{}`", tcx.def_path_str(key) } From 5f61402fb8411a961d263dcaf2c3fb8472a0ea86 Mon Sep 17 00:00:00 2001 From: Marcelo Dominguez Date: Wed, 8 Jul 2026 20:21:00 +0300 Subject: [PATCH 38/39] multiple arg type mismatch --- tests/ui/offload/type_mismatch.rs | 6 ++++++ tests/ui/offload/type_mismatch.stderr | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/ui/offload/type_mismatch.rs b/tests/ui/offload/type_mismatch.rs index 039519c431db8..4079444a0aff1 100644 --- a/tests/ui/offload/type_mismatch.rs +++ b/tests/ui/offload/type_mismatch.rs @@ -19,7 +19,13 @@ fn main() { // return type mismatch let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, ()); //~^ ERROR offload kernel return type mismatch: kernel returns `()`, but offload call expects `f64` + + // multiple argument type mismatch + core::intrinsics::offload::<_, _, ()>(kernel_2, [1, 1, 1], [1, 1, 1], 0, (42.0f64, 42.0f64)); + //~^ ERROR type mismatch in offload kernel argument 0: expected `f32`, found `f64` + //~| ERROR type mismatch in offload kernel argument 1: expected `f32`, found `f64` } fn kernel_0() {} fn kernel_1(_x: f32) {} +fn kernel_2(_x: f32, _y: f32) {} diff --git a/tests/ui/offload/type_mismatch.stderr b/tests/ui/offload/type_mismatch.stderr index abbf9a0f2f786..8cf160ca09486 100644 --- a/tests/ui/offload/type_mismatch.stderr +++ b/tests/ui/offload/type_mismatch.stderr @@ -22,5 +22,17 @@ error: offload kernel return type mismatch: kernel returns `()`, but offload cal LL | let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: type mismatch in offload kernel argument 0: expected `f32`, found `f64` + --> $DIR/type_mismatch.rs:24:5 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_2, [1, 1, 1], [1, 1, 1], 0, (42.0f64, 42.0f64)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: type mismatch in offload kernel argument 1: expected `f32`, found `f64` + --> $DIR/type_mismatch.rs:24:5 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_2, [1, 1, 1], [1, 1, 1], 0, (42.0f64, 42.0f64)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors From 43ebcdabaf4513c4a0fa917cd98462e9583e504d Mon Sep 17 00:00:00 2001 From: Marcelo Dominguez Date: Wed, 29 Jul 2026 22:14:45 +0300 Subject: [PATCH 39/39] fix --- compiler/rustc_hir_typeck/src/expr.rs | 1 + compiler/rustc_hir_typeck/src/intrinsicck.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index cf4f5f6da37e2..385ecc30bf877 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -632,6 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id)); } if tcx.is_intrinsic(did, sym::offload) { + let args = args.skip_binder(); let f = args.type_at(0); let t = args.type_at(1); let r = args.type_at(2); diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 746178ca6faeb..e009be599e36c 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -161,7 +161,8 @@ fn check_offload<'tcx>( return Err(err); }; - let kernel_sig = tcx.fn_sig(kernel_def_id).instantiate(tcx, kernel_args).skip_norm_wip(); + let kernel_sig = + tcx.fn_sig(kernel_def_id).instantiate(tcx, kernel_args.skip_binder()).skip_norm_wip(); let kernel_sig = tcx.instantiate_bound_regions_with_erased(kernel_sig); let ty::Tuple(tuple_fields) = *args_ty.kind() else {