From 1a1d180effb3fc78b98d1a02979df80d96db6bca Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Tue, 3 Jun 2025 04:54:36 +0000 Subject: [PATCH 01/27] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 553d410b2bc7f..15f06b60d0f9c 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -337c11e5932275e7d450c1f2e26f289f0ddfa717 +99426c570eebec8dcba2eaa8f5057265346aaedc From 80a95b745e0d156fd9fce7cb66de0377a4df2781 Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Mon, 2 Jun 2025 21:49:13 +0200 Subject: [PATCH 02/27] native-lib: allow multiple libraries and/or dirs --- src/tools/miri/README.md | 6 +- src/tools/miri/src/alloc_addresses/mod.rs | 4 +- src/tools/miri/src/bin/miri.rs | 19 ++++-- src/tools/miri/src/eval.rs | 7 +-- src/tools/miri/src/machine.rs | 14 ++--- src/tools/miri/src/shims/foreign_items.rs | 2 +- src/tools/miri/src/shims/native_lib.rs | 75 ++++++++++++----------- 7 files changed, 70 insertions(+), 57 deletions(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index de521393cd0ab..126a8dc47362a 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -398,9 +398,11 @@ to Miri failing to detect cases of undefined behavior in a program. **unsound** since the fallback body might not be checking for all UB. * `-Zmiri-native-lib=` is an experimental flag for providing support for calling native functions from inside the interpreter via FFI. The flag is supported only on - Unix systems. Functions not provided by that file are still executed via the usual Miri shims. + Unix systems. Functions not provided by that file are still executed via the usual Miri shims. If + a path to a directory is specified, all files in that directory are included nonrecursively. This + flag can be passed multiple times to specify multiple files and/or directories. **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause Undefined Behavior in - Miri itself! And of course, Miri cannot do any checks on the actions taken by the native code. + Miri itself! And of course, Miri often cannot do any checks on the actions taken by the native code. Note that Miri has its own handling of file descriptors, so if you want to replace *some* functions working on file descriptors, you will have to replace *all* of them, or the two kinds of file descriptors will be mixed up. This is **work in progress**; currently, only integer and diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 12a320b967678..4a038fe648735 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -132,7 +132,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { assert!(!matches!(info.kind, AllocKind::Dead)); // This allocation does not have a base address yet, pick or reuse one. - if this.machine.native_lib.is_some() { + if !this.machine.native_lib.is_empty() { // In native lib mode, we use the "real" address of the bytes for this allocation. // This ensures the interpreted program and native code have the same view of memory. let params = this.machine.get_default_alloc_params(); @@ -413,7 +413,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, MiriAllocBytes> { let this = self.eval_context_ref(); assert!(this.tcx.try_get_global_alloc(id).is_some()); - if this.machine.native_lib.is_some() { + if !this.machine.native_lib.is_empty() { // In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`. // This additional call ensures that some `MiriAllocBytes` are always prepared, just in case // this function gets called before the first time `addr_from_alloc_id` gets called. diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 0121472d330f5..f8168853d3aaf 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -692,11 +692,18 @@ fn main() { }; } else if let Some(param) = arg.strip_prefix("-Zmiri-native-lib=") { let filename = param.to_string(); - if std::path::Path::new(&filename).exists() { - if let Some(other_filename) = miri_config.native_lib { - show_error!("-Zmiri-native-lib is already set to {}", other_filename.display()); + let file_path = std::path::Path::new(&filename); + if file_path.exists() { + // For directories, nonrecursively add all normal files inside + if let Ok(dir) = file_path.read_dir() { + for lib in dir.filter_map(|res| res.ok()) { + if lib.file_type().unwrap().is_file() { + miri_config.native_lib.push(lib.path().to_owned()); + } + } + } else { + miri_config.native_lib.push(filename.into()); } - miri_config.native_lib = Some(filename.into()); } else { show_error!("-Zmiri-native-lib `{}` does not exist", filename); } @@ -731,12 +738,12 @@ fn main() { "Tree Borrows does not support integer-to-pointer casts, and hence requires strict provenance" ); } - if miri_config.native_lib.is_some() { + if !miri_config.native_lib.is_empty() { show_error!("Tree Borrows is not compatible with calling native functions"); } } // Native calls and strict provenance are not compatible. - if miri_config.native_lib.is_some() && miri_config.provenance_mode == ProvenanceMode::Strict { + if !miri_config.native_lib.is_empty() && miri_config.provenance_mode == ProvenanceMode::Strict { show_error!("strict provenance is not compatible with calling native functions"); } // You can set either one seed or many. diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 8fe034d258297..1477f103ca5e1 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -148,9 +148,8 @@ pub struct MiriConfig { pub report_progress: Option, /// Whether Stacked Borrows and Tree Borrows retagging should recurse into fields of datatypes. pub retag_fields: RetagFields, - /// The location of a shared object file to load when calling external functions - /// FIXME! consider allowing users to specify paths to multiple files, or to a directory - pub native_lib: Option, + /// The location of the shared object files to load when calling external functions + pub native_lib: Vec, /// Run a garbage collector for BorTags every N basic blocks. pub gc_interval: u32, /// The number of CPUs to be reported by miri. @@ -197,7 +196,7 @@ impl Default for MiriConfig { preemption_rate: 0.01, // 1% report_progress: None, retag_fields: RetagFields::Yes, - native_lib: None, + native_lib: vec![], gc_interval: 10_000, num_cpus: 1, page_size: None, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 15b3653d7aef9..b221dd8509251 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -558,9 +558,9 @@ pub struct MiriMachine<'tcx> { /// Handle of the optional shared object file for native functions. #[cfg(unix)] - pub native_lib: Option<(libloading::Library, std::path::PathBuf)>, + pub native_lib: Vec<(libloading::Library, std::path::PathBuf)>, #[cfg(not(unix))] - pub native_lib: Option, + pub native_lib: Vec, /// Run a garbage collector for BorTags every N basic blocks. pub(crate) gc_interval: u32, @@ -720,7 +720,7 @@ impl<'tcx> MiriMachine<'tcx> { extern_statics: FxHashMap::default(), rng: RefCell::new(rng), #[cfg(target_os = "linux")] - allocator: if config.native_lib.is_some() { + allocator: if !config.native_lib.is_empty() { Some(Rc::new(RefCell::new(crate::alloc::isolated_alloc::IsolatedAlloc::new()))) } else { None }, tracked_alloc_ids: config.tracked_alloc_ids.clone(), @@ -732,7 +732,7 @@ impl<'tcx> MiriMachine<'tcx> { basic_block_count: 0, monotonic_clock: MonotonicClock::new(config.isolated_op == IsolatedOp::Allow), #[cfg(unix)] - native_lib: config.native_lib.as_ref().map(|lib_file_path| { + native_lib: config.native_lib.iter().map(|lib_file_path| { let host_triple = rustc_session::config::host_tuple(); let target_triple = tcx.sess.opts.target_triple.tuple(); // Check if host target == the session target. @@ -752,11 +752,11 @@ impl<'tcx> MiriMachine<'tcx> { }, lib_file_path.clone(), ) - }), + }).collect(), #[cfg(not(unix))] - native_lib: config.native_lib.as_ref().map(|_| { + native_lib: config.native_lib.iter().map(|_| { panic!("calling functions from native libraries via FFI is only supported on Unix") - }), + }).collect(), gc_interval: config.gc_interval, since_gc: 0, num_cpus: config.num_cpus, diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index b08b522d279a0..81a5046b2260e 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -238,7 +238,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // First deal with any external C functions in linked .so file. #[cfg(unix)] - if this.machine.native_lib.as_ref().is_some() { + if !this.machine.native_lib.is_empty() { use crate::shims::native_lib::EvalContextExt as _; // An Ok(false) here means that the function being called was not exported // by the specified `.so` file; we should continue and check if it corresponds to diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 1e6c93333c157..40440bf6da419 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -87,47 +87,52 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Get the pointer to the function of the specified name in the shared object file, - /// if it exists. The function must be in the shared object file specified: we do *not* - /// return pointers to functions in dependencies of the library. + /// if it exists. The function must be in one of the shared object files specified: + /// we do *not* return pointers to functions in dependencies of libraries. fn get_func_ptr_explicitly_from_lib(&mut self, link_name: Symbol) -> Option { let this = self.eval_context_mut(); - // Try getting the function from the shared library. - let (lib, lib_path) = this.machine.native_lib.as_ref().unwrap(); - let func: libloading::Symbol<'_, unsafe extern "C" fn()> = - unsafe { lib.get(link_name.as_str().as_bytes()).ok()? }; - #[expect(clippy::as_conversions)] // fn-ptr to raw-ptr cast needs `as`. - let fn_ptr = *func.deref() as *mut std::ffi::c_void; + // Try getting the function from one of the shared libraries. + for (lib, lib_path) in &this.machine.native_lib { + let Ok(func): Result, _> = + (unsafe { lib.get(link_name.as_str().as_bytes()) }) + else { + continue; + }; + #[expect(clippy::as_conversions)] // fn-ptr to raw-ptr cast needs `as`. + let fn_ptr = *func.deref() as *mut std::ffi::c_void; - // FIXME: this is a hack! - // The `libloading` crate will automatically load system libraries like `libc`. - // On linux `libloading` is based on `dlsym`: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#202 - // and `dlsym`(https://linux.die.net/man/3/dlsym) looks through the dependency tree of the - // library if it can't find the symbol in the library itself. - // So, in order to check if the function was actually found in the specified - // `machine.external_so_lib` we need to check its `dli_fname` and compare it to - // the specified SO file path. - // This code is a reimplementation of the mechanism for getting `dli_fname` in `libloading`, - // from: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#411 - // using the `libc` crate where this interface is public. - let mut info = std::mem::MaybeUninit::::zeroed(); - unsafe { - if libc::dladdr(fn_ptr, info.as_mut_ptr()) != 0 { - let info = info.assume_init(); - #[cfg(target_os = "cygwin")] - let fname_ptr = info.dli_fname.as_ptr(); - #[cfg(not(target_os = "cygwin"))] - let fname_ptr = info.dli_fname; - assert!(!fname_ptr.is_null()); - if std::ffi::CStr::from_ptr(fname_ptr).to_str().unwrap() - != lib_path.to_str().unwrap() - { - return None; + // FIXME: this is a hack! + // The `libloading` crate will automatically load system libraries like `libc`. + // On linux `libloading` is based on `dlsym`: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#202 + // and `dlsym`(https://linux.die.net/man/3/dlsym) looks through the dependency tree of the + // library if it can't find the symbol in the library itself. + // So, in order to check if the function was actually found in the specified + // `machine.external_so_lib` we need to check its `dli_fname` and compare it to + // the specified SO file path. + // This code is a reimplementation of the mechanism for getting `dli_fname` in `libloading`, + // from: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#411 + // using the `libc` crate where this interface is public. + let mut info = std::mem::MaybeUninit::::zeroed(); + unsafe { + if libc::dladdr(fn_ptr, info.as_mut_ptr()) != 0 { + let info = info.assume_init(); + #[cfg(target_os = "cygwin")] + let fname_ptr = info.dli_fname.as_ptr(); + #[cfg(not(target_os = "cygwin"))] + let fname_ptr = info.dli_fname; + assert!(!fname_ptr.is_null()); + if std::ffi::CStr::from_ptr(fname_ptr).to_str().unwrap() + != lib_path.to_str().unwrap() + { + return None; + } } } - } - // Return a pointer to the function. - Some(CodePtr(fn_ptr)) + // Return a pointer to the function. + return Some(CodePtr(fn_ptr)); + } + None } } From beff63bb98effefbc9204ff52a66a92545120786 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 4 Jun 2025 04:54:56 +0000 Subject: [PATCH 03/27] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 15f06b60d0f9c..2bc38eebfc299 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -99426c570eebec8dcba2eaa8f5057265346aaedc +792fc2b033aea7ea7b766e38bdc40f7d6bdce8c3 From 869baeaf9207e86fa9a8e8a3319d7ae080e4a07c Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 5 Jun 2025 04:55:14 +0000 Subject: [PATCH 04/27] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 2bc38eebfc299..437d4218cfad8 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -792fc2b033aea7ea7b766e38bdc40f7d6bdce8c3 +81a964c23ea4fe9ab52b4449bb166bf280035797 From 8c410ca291a68bf23ca3694b1bbda631323b12cd Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 6 Jun 2025 04:55:10 +0000 Subject: [PATCH 05/27] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 437d4218cfad8..1e97cdf5bde99 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -81a964c23ea4fe9ab52b4449bb166bf280035797 +cf423712b9e95e9f6ec84b1ecb3d125e55ac8d56 From b1652dc7d53e24196d3745f6196411c61ccd53fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 Jun 2025 18:52:26 +0200 Subject: [PATCH 06/27] use File::lock to implement flock, and add a test for File::lock --- src/tools/miri/Cargo.lock | 1 - src/tools/miri/Cargo.toml | 7 -- src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/shims/unix/fs.rs | 113 +++++--------------------- src/tools/miri/tests/pass/shims/fs.rs | 33 +++++++- 5 files changed, 50 insertions(+), 105 deletions(-) diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 6f4bd3eab51a2..192d4f444c2ff 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -555,7 +555,6 @@ dependencies = [ "tempfile", "tikv-jemalloc-sys", "ui_test", - "windows-sys", ] [[package]] diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index e4d7abdb0f73e..a314488bb2533 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -40,13 +40,6 @@ libc = "0.2" libffi = "4.0.0" libloading = "0.8" -[target.'cfg(target_family = "windows")'.dependencies] -windows-sys = { version = "0.59", features = [ - "Win32_Foundation", - "Win32_System_IO", - "Win32_Storage_FileSystem", -] } - [dev-dependencies] ui_test = "0.29.1" colored = "2" diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 51ec19af52a07..dfefe2f4b0525 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -16,6 +16,7 @@ #![feature(unqualified_local_imports)] #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] +#![feature(file_lock)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 31cb269059c16..0f7d453b296c9 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -2,7 +2,8 @@ use std::borrow::Cow; use std::fs::{ - DirBuilder, File, FileType, OpenOptions, ReadDir, read_dir, remove_dir, remove_file, rename, + DirBuilder, File, FileType, OpenOptions, ReadDir, TryLockError, read_dir, remove_dir, + remove_file, rename, }; use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; @@ -89,103 +90,27 @@ impl UnixFileDescription for FileHandle { communicate_allowed: bool, op: FlockOp, ) -> InterpResult<'tcx, io::Result<()>> { - // cfg(bootstrap) - macro_rules! cfg_select_dispatch { - ($($tokens:tt)*) => { - #[cfg(bootstrap)] - cfg_match! { $($tokens)* } - - #[cfg(not(bootstrap))] - cfg_select! { $($tokens)* } - }; - } - assert!(communicate_allowed, "isolation should have prevented even opening a file"); - cfg_select_dispatch! { - all(target_family = "unix", not(target_os = "solaris")) => { - use std::os::fd::AsRawFd; - - use FlockOp::*; - // We always use non-blocking call to prevent interpreter from being blocked - let (host_op, lock_nb) = match op { - SharedLock { nonblocking } => (libc::LOCK_SH | libc::LOCK_NB, nonblocking), - ExclusiveLock { nonblocking } => (libc::LOCK_EX | libc::LOCK_NB, nonblocking), - Unlock => (libc::LOCK_UN, false), - }; - let fd = self.file.as_raw_fd(); - let ret = unsafe { libc::flock(fd, host_op) }; - let res = match ret { - 0 => Ok(()), - -1 => { - let err = io::Error::last_os_error(); - if !lock_nb && err.kind() == io::ErrorKind::WouldBlock { - throw_unsup_format!("blocking `flock` is not currently supported"); - } - Err(err) - } - ret => panic!("Unexpected return value from flock: {ret}"), - }; - interp_ok(res) + use FlockOp::*; + // We must not block the interpreter loop, so we always `try_lock`. + let (res, nonblocking) = match op { + SharedLock { nonblocking } => (self.file.try_lock_shared(), nonblocking), + ExclusiveLock { nonblocking } => (self.file.try_lock(), nonblocking), + Unlock => { + return interp_ok(self.file.unlock()); } - target_family = "windows" => { - use std::os::windows::io::AsRawHandle; - - use windows_sys::Win32::Foundation::{ - ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, TRUE, - }; - use windows_sys::Win32::Storage::FileSystem::{ - LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, LockFileEx, UnlockFile, - }; - - let fh = self.file.as_raw_handle(); - - use FlockOp::*; - let (ret, lock_nb) = match op { - SharedLock { nonblocking } | ExclusiveLock { nonblocking } => { - // We always use non-blocking call to prevent interpreter from being blocked - let mut flags = LOCKFILE_FAIL_IMMEDIATELY; - if matches!(op, ExclusiveLock { .. }) { - flags |= LOCKFILE_EXCLUSIVE_LOCK; - } - let ret = unsafe { LockFileEx(fh, flags, 0, !0, !0, &mut std::mem::zeroed()) }; - (ret, nonblocking) - } - Unlock => { - let ret = unsafe { UnlockFile(fh, 0, 0, !0, !0) }; - (ret, false) - } - }; + }; - let res = match ret { - TRUE => Ok(()), - FALSE => { - let mut err = io::Error::last_os_error(); - // This only runs on Windows hosts so we can use `raw_os_error`. - // We have to be careful not to forward that error code to target code. - let code: u32 = err.raw_os_error().unwrap().try_into().unwrap(); - if matches!(code, ERROR_IO_PENDING | ERROR_LOCK_VIOLATION) { - if lock_nb { - // The io error mapping does not know about these error codes, - // so we translate it to `WouldBlock` manually. - let desc = format!("LockFileEx wouldblock error: {err}"); - err = io::Error::new(io::ErrorKind::WouldBlock, desc); - } else { - throw_unsup_format!("blocking `flock` is not currently supported"); - } - } - Err(err) - } - _ => panic!("Unexpected return value: {ret}"), - }; - interp_ok(res) - } - _ => { - let _ = op; - throw_unsup_format!( - "flock is supported only on UNIX (except Solaris) and Windows hosts" - ); - } + match res { + Ok(()) => interp_ok(Ok(())), + Err(TryLockError::Error(err)) => interp_ok(Err(err)), + Err(TryLockError::WouldBlock) => + if nonblocking { + interp_ok(Err(ErrorKind::WouldBlock.into())) + } else { + throw_unsup_format!("blocking `flock` is not currently supported"); + }, } } } diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 87df43ca7e57f..2f30827c9336b 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -2,12 +2,12 @@ #![feature(io_error_more)] #![feature(io_error_uncategorized)] +#![feature(file_lock)] use std::collections::BTreeMap; use std::ffi::OsString; use std::fs::{ - File, OpenOptions, canonicalize, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, - rename, + self, File, OpenOptions, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename, }; use std::io::{Error, ErrorKind, IsTerminal, Read, Result, Seek, SeekFrom, Write}; use std::path::Path; @@ -33,6 +33,8 @@ fn main() { test_canonicalize(); #[cfg(unix)] test_pread_pwrite(); + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + test_flock(); } } @@ -240,7 +242,7 @@ fn test_canonicalize() { let path = dir_path.join("test_file"); drop(File::create(&path).unwrap()); - let p = canonicalize(format!("{}/./test_file", dir_path.to_string_lossy())).unwrap(); + let p = fs::canonicalize(format!("{}/./test_file", dir_path.to_string_lossy())).unwrap(); assert_eq!(p.to_string_lossy().find("/./"), None); remove_dir_all(&dir_path).unwrap(); @@ -351,3 +353,28 @@ fn test_pread_pwrite() { f.read_exact(&mut buf1).unwrap(); assert_eq!(&buf1, b" m"); } + +// This function does seem to exist on Illumos but std does not expose it there. +#[cfg(not(any(target_os = "solaris", target_os = "illumos")))] +fn test_flock() { + let bytes = b"Hello, World!\n"; + let path = utils::prepare_with_content("miri_test_fs_flock.txt", bytes); + let file1 = OpenOptions::new().read(true).write(true).open(&path).unwrap(); + let file2 = OpenOptions::new().read(true).write(true).open(&path).unwrap(); + + // Test that we can apply many shared locks + file1.lock_shared().unwrap(); + file2.lock_shared().unwrap(); + // Test that shared lock prevents exclusive lock + assert!(matches!(file1.try_lock().unwrap_err(), fs::TryLockError::WouldBlock)); + // Unlock shared lock + file1.unlock().unwrap(); + file2.unlock().unwrap(); + // Take exclusive lock + file1.lock().unwrap(); + // Test that shared lock prevents exclusive and shared locks + assert!(matches!(file2.try_lock().unwrap_err(), fs::TryLockError::WouldBlock)); + assert!(matches!(file2.try_lock_shared().unwrap_err(), fs::TryLockError::WouldBlock)); + // Unlock exclusive lock + file1.unlock().unwrap(); +} From dc14e732326df21d4889cc2bef8318f77f1092a7 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sun, 27 Apr 2025 21:20:38 +0200 Subject: [PATCH 07/27] Delete unused variant and document AttributeKind --- .../src/attributes.rs | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d2d1285b0756f..845e4d5e5d0fa 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -57,14 +57,6 @@ impl OptimizeAttr { } } -#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)] -pub enum DiagnosticAttribute { - // tidy-alphabetical-start - DoNotRecommend, - OnUnimplemented, - // tidy-alphabetical-end -} - #[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)] pub enum ReprAttr { ReprInt(IntType), @@ -160,40 +152,52 @@ impl Deprecation { #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub enum AttributeKind { // tidy-alphabetical-start + /// Represents `#[rustc_allow_const_fn_unstable]`. AllowConstFnUnstable(ThinVec), + + /// Represents `#[allow_internal_unstable]`. AllowInternalUnstable(ThinVec<(Symbol, Span)>), + + /// Represents `#[rustc_default_body_unstable]`. BodyStability { stability: DefaultBodyStability, /// Span of the `#[rustc_default_body_unstable(...)]` attribute span: Span, }, + + /// Represents `#[rustc_confusables]`. Confusables { symbols: ThinVec, // FIXME(jdonszelmann): remove when target validation code is moved first_span: Span, }, + + /// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`. ConstStability { stability: PartialConstStability, /// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute span: Span, }, + + /// Represents `#[rustc_const_stable_indirect]`. ConstStabilityIndirect, - Deprecation { - deprecation: Deprecation, - span: Span, - }, - Diagnostic(DiagnosticAttribute), - DocComment { - style: AttrStyle, - kind: CommentKind, - span: Span, - comment: Symbol, - }, + + /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute). + Deprecation { deprecation: Deprecation, span: Span }, + + /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). + DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, + + /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), + + /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), + + /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`. Stability { stability: Stability, - /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute + /// Span of the attribute. span: Span, }, // tidy-alphabetical-end From 5fdacfe1b7a99ddd5b850cc9a1cdc006da0c62b4 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sun, 27 Apr 2025 21:59:09 +0200 Subject: [PATCH 08/27] Force exhaustive handling of every parsed attribute --- compiler/rustc_passes/src/check_attr.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0777d442b5942..467f709906815 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -132,7 +132,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target, attrs, ), - _ => { + Attribute::Parsed(AttributeKind::AllowConstFnUnstable { .. }) => { + self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) + } + Attribute::Parsed(AttributeKind::Deprecation { .. }) => { + self.check_deprecated(hir_id, attr, span, target) + } + Attribute::Parsed(AttributeKind::DocComment { .. }) => { /* `#[doc]` is actually a lot more than just doc comments, so is checked below*/ + } + Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */ + } + Attribute::Parsed( + AttributeKind::BodyStability { .. } + | AttributeKind::ConstStabilityIndirect + | AttributeKind::MacroTransparency(_), + ) => { /* do nothing */ } + Attribute::Unparsed(_) => { match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend, ..] => { self.check_do_not_recommend(attr.span(), hir_id, target, attr, item) @@ -169,9 +184,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_layout_scalar_valid_range(attr, span, target) } [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), - [sym::rustc_allow_const_fn_unstable, ..] => { - self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) - } [sym::rustc_std_internal_symbol, ..] => { self.check_rustc_std_internal_symbol(attr, span, target) } @@ -229,7 +241,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target), - [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target), [sym::macro_use, ..] | [sym::macro_escape, ..] => { self.check_macro_use(hir_id, attr, target) } @@ -283,7 +294,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::pointee // FIXME(derive_coerce_pointee) | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) | sym::used // handled elsewhere to restrict to static items - | sym::repr // handled elsewhere to restrict to type decls items | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) From 24921a1c5e3510f7eba8ff9b5bc8d2abccaa9831 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 7 Jun 2025 04:53:58 +0000 Subject: [PATCH 09/27] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 1e97cdf5bde99..84a353bfbcf38 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -cf423712b9e95e9f6ec84b1ecb3d125e55ac8d56 +775e0c8aeb8f63192854b27156f8b05a06b51814 From e6ddcf4f521bf385b542e7b2adf1c0ab8f7b85e8 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 7 Jun 2025 05:02:30 +0000 Subject: [PATCH 10/27] fmt --- src/tools/miri/src/shims/backtrace.rs | 10 ++++++++-- src/tools/miri/src/shims/unix/linux_like/epoll.rs | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 8606735c913eb..feb83ca8829ab 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -169,8 +169,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags), } - this.write_scalar(Scalar::from_u32(lineno), &this.project_field(dest, FieldIdx::from_u32(2))?)?; - this.write_scalar(Scalar::from_u32(colno), &this.project_field(dest, FieldIdx::from_u32(3))?)?; + this.write_scalar( + Scalar::from_u32(lineno), + &this.project_field(dest, FieldIdx::from_u32(2))?, + )?; + this.write_scalar( + Scalar::from_u32(colno), + &this.project_field(dest, FieldIdx::from_u32(3))?, + )?; // Support a 4-field struct for now - this is deprecated // and slated for removal. diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs index f971fb10b1998..d460abc783dd5 100644 --- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs @@ -286,7 +286,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if op == epoll_ctl_add || op == epoll_ctl_mod { // Read event bitmask and data from epoll_event passed by caller. - let mut events = this.read_scalar(&this.project_field(&event, FieldIdx::ZERO)?)?.to_u32()?; + let mut events = + this.read_scalar(&this.project_field(&event, FieldIdx::ZERO)?)?.to_u32()?; let data = this.read_scalar(&this.project_field(&event, FieldIdx::ONE)?)?.to_u64()?; // Unset the flag we support to discover if any unsupported flags are used. From cd7533ab44cbc7b1b50b582d45a574af6eec12b7 Mon Sep 17 00:00:00 2001 From: sayantn Date: Thu, 8 May 2025 01:06:23 +0530 Subject: [PATCH 11/27] Stabilize the `keylocker_x86` flag, and the `kl` and `widekl` target features --- compiler/rustc_feature/src/accepted.rs | 2 ++ compiler/rustc_feature/src/unstable.rs | 2 -- compiler/rustc_target/src/target_features.rs | 4 ++-- library/core/src/lib.rs | 1 - .../ui/feature-gates/feature-gate-keylocker_x86.rs | 6 ------ .../feature-gates/feature-gate-keylocker_x86.stderr | 13 ------------- 6 files changed, 4 insertions(+), 24 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-keylocker_x86.rs delete mode 100644 tests/ui/feature-gates/feature-gate-keylocker_x86.stderr diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ffa6ffb40b61a..21e957427040c 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -259,6 +259,8 @@ declare_features! ( /// Allows some increased flexibility in the name resolution rules, /// especially around globs and shadowing (RFC 1560). (accepted, item_like_imports, "1.15.0", Some(35120)), + // Allows using the `kl` and `widekl` target features and the associated intrinsics + (accepted, keylocker_x86, "CURRENT_RUSTC_VERSION", Some(134813)), /// Allows `'a: { break 'a; }`. (accepted, label_break_value, "1.65.0", Some(48594)), /// Allows `let...else` statements. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index b46eac6d8a602..44413b756e1bc 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -546,8 +546,6 @@ declare_features! ( (incomplete, inherent_associated_types, "1.52.0", Some(8995)), /// Allows using `pointer` and `reference` in intra-doc links (unstable, intra_doc_pointers, "1.51.0", Some(80896)), - // Allows using the `kl` and `widekl` target features and the associated intrinsics - (unstable, keylocker_x86, "1.86.0", Some(134813)), // Allows setting the threshold for the `large_assignments` lint. (unstable, large_assignments, "1.52.0", Some(83518)), /// Allow to have type alias types for inter-crate use. diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 682c4c5068f9e..ecf6fba263017 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -443,7 +443,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("fma", Stable, &["avx"]), ("fxsr", Stable, &[]), ("gfni", Stable, &["sse2"]), - ("kl", Unstable(sym::keylocker_x86), &["sse2"]), + ("kl", Stable, &["sse2"]), ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]), ("lzcnt", Stable, &[]), ("movbe", Stable, &[]), @@ -471,7 +471,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("tbm", Unstable(sym::tbm_target_feature), &[]), ("vaes", Stable, &["avx2", "aes"]), ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]), - ("widekl", Unstable(sym::keylocker_x86), &["kl"]), + ("widekl", Stable, &["kl"]), ("x87", Unstable(sym::x87_target_feature), &[]), ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]), ("xsave", Stable, &[]), diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index f2a5c40bada0b..b7bd2f837c103 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -190,7 +190,6 @@ #![feature(aarch64_unstable_target_feature)] #![feature(arm_target_feature)] #![feature(hexagon_target_feature)] -#![feature(keylocker_x86)] #![feature(loongarch_target_feature)] #![feature(mips_target_feature)] #![feature(powerpc_target_feature)] diff --git a/tests/ui/feature-gates/feature-gate-keylocker_x86.rs b/tests/ui/feature-gates/feature-gate-keylocker_x86.rs deleted file mode 100644 index cef80ad41a892..0000000000000 --- a/tests/ui/feature-gates/feature-gate-keylocker_x86.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ only-x86_64 -#[target_feature(enable = "kl")] -//~^ ERROR: currently unstable -unsafe fn foo() {} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-keylocker_x86.stderr b/tests/ui/feature-gates/feature-gate-keylocker_x86.stderr deleted file mode 100644 index ed814d3a3ce2e..0000000000000 --- a/tests/ui/feature-gates/feature-gate-keylocker_x86.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: the target feature `kl` is currently unstable - --> $DIR/feature-gate-keylocker_x86.rs:2:18 - | -LL | #[target_feature(enable = "kl")] - | ^^^^^^^^^^^^^ - | - = note: see issue #134813 for more information - = help: add `#![feature(keylocker_x86)]` 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: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. From 370a7fade9da867520bed302c8a09c7c8d0d0842 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 8 Jun 2025 04:56:16 +0000 Subject: [PATCH 12/27] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 84a353bfbcf38..d1a5ef7b7fce3 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -775e0c8aeb8f63192854b27156f8b05a06b51814 +a5584a8fe16037dc01782064fa41424a6dbe9987 From db95049fa1a8834095e15ec8c03734a436b11547 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 9 Jun 2025 04:56:52 +0000 Subject: [PATCH 13/27] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index d1a5ef7b7fce3..c8721bb36001f 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -a5584a8fe16037dc01782064fa41424a6dbe9987 +c31cccb7b5cc098b1a8c1794ed38d7fdbec0ccb0 From 4e8d5837df7cd7c83d91e14ad107a7422ab0ed36 Mon Sep 17 00:00:00 2001 From: Xinglu Chen Date: Mon, 2 Jun 2025 12:21:39 +0200 Subject: [PATCH 14/27] Add `-Zmiri-tree-borrows-no-precise-interior-mut` flag --- src/tools/miri/README.md | 4 + src/tools/miri/src/bin/miri.rs | 20 ++++- src/tools/miri/src/borrow_tracker/mod.rs | 29 +++++-- .../src/borrow_tracker/tree_borrows/mod.rs | 87 ++++++++++++++----- src/tools/miri/src/diagnostics.rs | 5 +- src/tools/miri/src/lib.rs | 4 +- .../pass/tree_borrows/cell-inside-struct.rs | 34 ++++++++ .../tree_borrows/cell-inside-struct.stderr | 6 ++ 8 files changed, 154 insertions(+), 35 deletions(-) create mode 100644 src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.rs create mode 100644 src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.stderr diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index de521393cd0ab..f89708e0d8f20 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -458,6 +458,10 @@ to Miri failing to detect cases of undefined behavior in a program. This is much less likely with Stacked Borrows. Using Tree Borrows currently implies `-Zmiri-strict-provenance` because integer-to-pointer casts are not supported in this mode, but that may change in the future. +* `-Zmiri-tree-borrows-no-precise-interior-mut` makes Tree Borrows + track interior mutable data on the level of references instead of on the + byte-level as is done by default. Therefore, with this flag, Tree + Borrows will be more permissive. * `-Zmiri-force-page-size=` overrides the default page size for an architecture, in multiples of 1k. `4` is default for most targets. This value should always be a power of 2 and nonzero. diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 0121472d330f5..1d3742cb0e98a 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -35,7 +35,7 @@ use std::sync::{Arc, Once}; use miri::{ BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType, - ProvenanceMode, RetagFields, ValidationMode, + ProvenanceMode, RetagFields, TreeBorrowsParams, ValidationMode, }; use rustc_abi::ExternAbi; use rustc_data_structures::sync; @@ -554,8 +554,21 @@ fn main() { } else if arg == "-Zmiri-disable-stacked-borrows" { miri_config.borrow_tracker = None; } else if arg == "-Zmiri-tree-borrows" { - miri_config.borrow_tracker = Some(BorrowTrackerMethod::TreeBorrows); + miri_config.borrow_tracker = + Some(BorrowTrackerMethod::TreeBorrows(TreeBorrowsParams { + precise_interior_mut: true, + })); miri_config.provenance_mode = ProvenanceMode::Strict; + } else if arg == "-Zmiri-tree-borrows-no-precise-interior-mut" { + match &mut miri_config.borrow_tracker { + Some(BorrowTrackerMethod::TreeBorrows(params)) => { + params.precise_interior_mut = false; + } + _ => + show_error!( + "`-Zmiri-tree-borrows` is required before `-Zmiri-tree-borrows-no-precise-interior-mut`" + ), + }; } else if arg == "-Zmiri-disable-data-race-detector" { miri_config.data_race_detector = false; miri_config.weak_memory_emulation = false; @@ -725,7 +738,7 @@ fn main() { } } // Tree Borrows implies strict provenance, and is not compatible with native calls. - if matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows)) { + if matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows { .. })) { if miri_config.provenance_mode != ProvenanceMode::Strict { show_error!( "Tree Borrows does not support integer-to-pointer casts, and hence requires strict provenance" @@ -735,6 +748,7 @@ fn main() { show_error!("Tree Borrows is not compatible with calling native functions"); } } + // Native calls and strict provenance are not compatible. if miri_config.native_lib.is_some() && miri_config.provenance_mode == ProvenanceMode::Strict { show_error!("strict provenance is not compatible with calling native functions"); diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index b66c561d2b8ad..36c61053a3205 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -226,7 +226,13 @@ pub enum BorrowTrackerMethod { /// Stacked Borrows, as implemented in borrow_tracker/stacked_borrows StackedBorrows, /// Tree borrows, as implemented in borrow_tracker/tree_borrows - TreeBorrows, + TreeBorrows(TreeBorrowsParams), +} + +/// Parameters that Tree Borrows can take. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct TreeBorrowsParams { + pub precise_interior_mut: bool, } impl BorrowTrackerMethod { @@ -237,6 +243,13 @@ impl BorrowTrackerMethod { config.retag_fields, )) } + + pub fn get_tree_borrows_params(self) -> TreeBorrowsParams { + match self { + BorrowTrackerMethod::TreeBorrows(params) => params, + _ => panic!("can only be called when `BorrowTrackerMethod` is `TreeBorrows`"), + } + } } impl GlobalStateInner { @@ -252,7 +265,7 @@ impl GlobalStateInner { AllocState::StackedBorrows(Box::new(RefCell::new(Stacks::new_allocation( id, alloc_size, self, kind, machine, )))), - BorrowTrackerMethod::TreeBorrows => + BorrowTrackerMethod::TreeBorrows { .. } => AllocState::TreeBorrows(Box::new(RefCell::new(Tree::new_allocation( id, alloc_size, self, kind, machine, )))), @@ -271,7 +284,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_retag_ptr_value(kind, val), - BorrowTrackerMethod::TreeBorrows => this.tb_retag_ptr_value(kind, val), + BorrowTrackerMethod::TreeBorrows { .. } => this.tb_retag_ptr_value(kind, val), } } @@ -284,7 +297,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_retag_place_contents(kind, place), - BorrowTrackerMethod::TreeBorrows => this.tb_retag_place_contents(kind, place), + BorrowTrackerMethod::TreeBorrows { .. } => this.tb_retag_place_contents(kind, place), } } @@ -293,7 +306,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_protect_place(place), - BorrowTrackerMethod::TreeBorrows => this.tb_protect_place(place), + BorrowTrackerMethod::TreeBorrows { .. } => this.tb_protect_place(place), } } @@ -302,7 +315,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_expose_tag(alloc_id, tag), - BorrowTrackerMethod::TreeBorrows => this.tb_expose_tag(alloc_id, tag), + BorrowTrackerMethod::TreeBorrows { .. } => this.tb_expose_tag(alloc_id, tag), } } @@ -319,7 +332,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.tcx.tcx.dcx().warn("Stacked Borrows does not support named pointers; `miri_pointer_name` is a no-op"); interp_ok(()) } - BorrowTrackerMethod::TreeBorrows => + BorrowTrackerMethod::TreeBorrows { .. } => this.tb_give_pointer_debug_name(ptr, nth_parent, name), } } @@ -333,7 +346,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let method = borrow_tracker.borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.print_stacks(alloc_id), - BorrowTrackerMethod::TreeBorrows => this.print_tree(alloc_id, show_unnamed), + BorrowTrackerMethod::TreeBorrows { .. } => this.print_tree(alloc_id, show_unnamed), } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 411ae89da9060..ce8fe03ee477d 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -312,8 +312,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let span = this.machine.current_span(); - let alloc_extra = this.get_alloc_extra(alloc_id)?; - let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); // Store initial permissions and their corresponding range. let mut perms_map: RangeMap = RangeMap::new( @@ -342,36 +340,83 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert!(new_perm.freeze_access); let protected = new_perm.protector.is_some(); - this.visit_freeze_sensitive(place, ptr_size, |range, frozen| { - has_unsafe_cell = has_unsafe_cell || !frozen; - - // We are only ever `Frozen` inside the frozen bits. - let (perm, access) = if frozen { + let precise_interior_mut = this + .machine + .borrow_tracker + .as_mut() + .unwrap() + .get_mut() + .borrow_tracker_method + .get_tree_borrows_params() + .precise_interior_mut; + + let default_perm = if !precise_interior_mut { + // NOTE: Using `ty_is_freeze` doesn't give the same result as going through the range + // and computing `has_unsafe_cell`. This is because of zero-sized `UnsafeCell`, for which + // `has_unsafe_cell` is false, but `!ty_is_freeze` is true. + let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env()); + let (perm, access) = if ty_is_freeze { (new_perm.freeze_perm, new_perm.freeze_access) } else { (new_perm.nonfreeze_perm, new_perm.nonfreeze_access) }; + let sifa = perm.strongest_idempotent_foreign_access(protected); + let new_loc = if access { + LocationState::new_accessed(perm, sifa) + } else { + LocationState::new_non_accessed(perm, sifa) + }; + + for (_loc_range, loc) in perms_map.iter_mut_all() { + *loc = new_loc; + } + + perm + } else { + this.visit_freeze_sensitive(place, ptr_size, |range, frozen| { + has_unsafe_cell = has_unsafe_cell || !frozen; - // Store initial permissions. - for (_loc_range, loc) in perms_map.iter_mut(range.start, range.size) { + // We are only ever `Frozen` inside the frozen bits. + let (perm, access) = if frozen { + (new_perm.freeze_perm, new_perm.freeze_access) + } else { + (new_perm.nonfreeze_perm, new_perm.nonfreeze_access) + }; let sifa = perm.strongest_idempotent_foreign_access(protected); // NOTE: Currently, `access` is false if and only if `perm` is Cell, so this `if` // doesn't not change whether any code is UB or not. We could just always use // `new_accessed` and everything would stay the same. But that seems conceptually // odd, so we keep the initial "accessed" bit of the `LocationState` in sync with whether // a read access is performed below. - if access { - *loc = LocationState::new_accessed(perm, sifa); + let new_loc = if access { + LocationState::new_accessed(perm, sifa) } else { - *loc = LocationState::new_non_accessed(perm, sifa); + LocationState::new_non_accessed(perm, sifa) + }; + + // Store initial permissions. + for (_loc_range, loc) in perms_map.iter_mut(range.start, range.size) { + *loc = new_loc; } - } - // Some reborrows incur a read access to the parent. - if access { + interp_ok(()) + })?; + + // Allow lazily writing to surrounding data if we found an `UnsafeCell`. + if has_unsafe_cell { new_perm.nonfreeze_perm } else { new_perm.freeze_perm } + }; + + let alloc_extra = this.get_alloc_extra(alloc_id)?; + let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); + + for (perm_range, perm) in perms_map.iter_mut_all() { + if perm.is_accessed() { + // Some reborrows incur a read access to the parent. // Adjust range to be relative to allocation start (rather than to `place`). - let mut range_in_alloc = range; - range_in_alloc.start += base_offset; + let range_in_alloc = AllocRange { + start: Size::from_bytes(perm_range.start) + base_offset, + size: Size::from_bytes(perm_range.end - perm_range.start), + }; tree_borrows.perform_access( orig_tag, @@ -382,7 +427,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; // Also inform the data race model (but only if any bytes are actually affected). - if range.size.bytes() > 0 { + if range_in_alloc.size.bytes() > 0 { if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() { data_race.read( alloc_id, @@ -394,8 +439,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } - interp_ok(()) - })?; + } // Record the parent-child pair in the tree. tree_borrows.new_child( @@ -403,8 +447,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { orig_tag, new_tag, perms_map, - // Allow lazily writing to surrounding data if we found an `UnsafeCell`. - if has_unsafe_cell { new_perm.nonfreeze_perm } else { new_perm.freeze_perm }, + default_perm, protected, span, )?; diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 1728a9cfd6de6..58bf163bfadee 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -682,7 +682,10 @@ impl<'tcx> MiriMachine<'tcx> { ), ]; if self.borrow_tracker.as_ref().is_some_and(|b| { - matches!(b.borrow().borrow_tracker_method(), BorrowTrackerMethod::TreeBorrows) + matches!( + b.borrow().borrow_tracker_method(), + BorrowTrackerMethod::TreeBorrows { .. } + ) }) { v.push( note!("Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used") diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 8802216448f6e..8b457b98017ee 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -112,7 +112,9 @@ pub use crate::borrow_tracker::stacked_borrows::{ EvalContextExt as _, Item, Permission, Stack, Stacks, }; pub use crate::borrow_tracker::tree_borrows::{EvalContextExt as _, Tree}; -pub use crate::borrow_tracker::{BorTag, BorrowTrackerMethod, EvalContextExt as _, RetagFields}; +pub use crate::borrow_tracker::{ + BorTag, BorrowTrackerMethod, EvalContextExt as _, RetagFields, TreeBorrowsParams, +}; pub use crate::clock::{Instant, MonotonicClock}; pub use crate::concurrency::cpu_affinity::MAX_CPUS; pub use crate::concurrency::data_race::{ diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.rs b/src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.rs new file mode 100644 index 0000000000000..fd68685a2f442 --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.rs @@ -0,0 +1,34 @@ +//! The same as `tests/fail/tree-borrows/cell-inside-struct` but with +//! precise tracking of interior mutability disabled. +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-no-precise-interior-mut +#[path = "../../utils/mod.rs"] +#[macro_use] +mod utils; + +use std::cell::Cell; + +struct Foo { + field1: u32, + field2: Cell, +} + +pub fn main() { + let root = Foo { field1: 42, field2: Cell::new(88) }; + unsafe { + let a = &root; + + name!(a as *const Foo, "a"); + + let a: *const Foo = a as *const Foo; + let a: *mut Foo = a as *mut Foo; + + let alloc_id = alloc_id!(a); + print_state!(alloc_id); + + // Writing to `field2`, which is interior mutable, should be allowed. + (*a).field2.set(10); + + // Writing to `field1` should be allowed because it also has the `Cell` permission. + (*a).field1 = 88; + } +} diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.stderr new file mode 100644 index 0000000000000..1d939329040fa --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.stderr @@ -0,0 +1,6 @@ +────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 8 +| Act | └─┬── +|?Cel | └──── +────────────────────────────────────────────────── From cbdbd81158efa5821b77f0a53d5fc370f6b321bb Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 15 May 2025 16:38:46 -0700 Subject: [PATCH 15/27] Change __rust_no_alloc_shim_is_unstable to be a function --- compiler/rustc_ast/src/expand/allocator.rs | 2 +- .../rustc_codegen_cranelift/src/allocator.rs | 40 +++++++--- compiler/rustc_codegen_gcc/src/allocator.rs | 78 ++++++++++--------- compiler/rustc_codegen_llvm/src/allocator.rs | 74 ++++++++++-------- .../src/back/symbol_export.rs | 14 +--- compiler/rustc_symbol_mangling/src/v0.rs | 4 - library/alloc/src/alloc.rs | 7 +- src/tools/miri/src/shims/extern_static.rs | 4 - src/tools/miri/src/shims/foreign_items.rs | 4 + .../miri/tests/pass/alloc-access-tracking.rs | 4 +- tests/codegen/alloc-optimisation.rs | 3 +- tests/codegen/unwind-landingpad-inline.rs | 6 +- tests/codegen/vec-iter-collect-len.rs | 6 +- tests/codegen/vec-optimizes-away.rs | 3 +- tests/run-make/no-alloc-shim/foo.rs | 6 +- tests/run-make/no-alloc-shim/rmake.rs | 22 ++++-- tests/run-make/symbols-all-mangled/rmake.rs | 8 -- 17 files changed, 154 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index dd8d5ae624a3c..7dee2ed17b4be 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -22,7 +22,7 @@ pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'st } } -pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable"; +pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2"; pub enum AllocatorTy { Layout, diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 9cff8a84db3d9..ffb932a3c38e6 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -1,6 +1,7 @@ //! Allocator shim // Adapted from rustc +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, default_fn_name, global_fn_name, @@ -97,16 +98,31 @@ fn codegen_inner( data.define(Box::new([val])); module.define_data(data_id, &data).unwrap(); - let data_id = module - .declare_data( - &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - Linkage::Export, - false, - false, - ) - .unwrap(); - let mut data = DataDescription::new(); - data.set_align(1); - data.define(Box::new([0])); - module.define_data(data_id, &data).unwrap(); + { + let sig = Signature { + call_conv: module.target_config().default_call_conv, + params: vec![], + returns: vec![], + }; + let func_id = module + .declare_function( + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + Linkage::Export, + &sig, + ) + .unwrap(); + + let mut ctx = Context::new(); + ctx.func.signature = sig; + let mut func_ctx = FunctionBuilderContext::new(); + let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); + + let block = bcx.create_block(); + bcx.switch_to_block(block); + bcx.ins().return_(&[]); + bcx.seal_all_blocks(); + bcx.finalize(); + + module.define_function(func_id, &mut ctx).unwrap(); + } } diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index f4ebd42ee2dc0..cf8aa500c778f 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen( let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - create_wrapper_function(tcx, context, &from_name, &to_name, &types, output); + create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output); } } @@ -66,7 +66,7 @@ pub(crate) unsafe fn codegen( tcx, context, &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)), + Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))), &[usize, usize], None, ); @@ -81,21 +81,21 @@ pub(crate) unsafe fn codegen( let value = context.new_rvalue_from_int(i8, value as i32); global.global_set_initializer_rvalue(value); - let name = mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE); - let global = context.new_global(None, GlobalKind::Exported, i8, name); - #[cfg(feature = "master")] - global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc( - tcx.sess.default_visibility(), - ))); - let value = context.new_rvalue_from_int(i8, 0); - global.global_set_initializer_rvalue(value); + create_wrapper_function( + tcx, + context, + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + None, + &[], + None, + ); } fn create_wrapper_function( tcx: TyCtxt<'_>, context: &Context<'_>, from_name: &str, - to_name: &str, + to_name: Option<&str>, types: &[Type<'_>], output: Option>, ) { @@ -124,34 +124,40 @@ fn create_wrapper_function( // TODO(antoyo): emit unwind tables. } - let args: Vec<_> = types - .iter() - .enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index))) - .collect(); - let callee = context.new_function( - None, - FunctionType::Extern, - output.unwrap_or(void), - &args, - to_name, - false, - ); - #[cfg(feature = "master")] - callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - let block = func.new_block("entry"); - let args = args - .iter() - .enumerate() - .map(|(i, _)| func.get_param(i as i32).to_rvalue()) - .collect::>(); - let ret = context.new_call(None, callee, &args); - //llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - block.end_with_return(None, ret); + if let Some(to_name) = to_name { + let args: Vec<_> = types + .iter() + .enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index))) + .collect(); + let callee = context.new_function( + None, + FunctionType::Extern, + output.unwrap_or(void), + &args, + to_name, + false, + ); + #[cfg(feature = "master")] + callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::>(); + let ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + block.end_with_return(None, ret); + } else { + block.add_eval(None, ret); + block.end_with_void_return(None); + } } else { + assert!(output.is_none()); block.end_with_void_return(None); } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 4a78e69497994..9dca63cfc8d4f 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen( let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false); + create_wrapper_function(tcx, &cx, &from_name, Some(&to_name), &args, output, false); } } @@ -66,7 +66,7 @@ pub(crate) unsafe fn codegen( tcx, &cx, &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)), + Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))), &[usize, usize], // size, align None, true, @@ -81,11 +81,16 @@ pub(crate) unsafe fn codegen( let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::set_initializer(ll_g, llval); - let name = mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE); - let ll_g = cx.declare_global(&name, i8); - llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); - let llval = llvm::LLVMConstInt(i8, 0, False); - llvm::set_initializer(ll_g, llval); + // __rust_no_alloc_shim_is_unstable_v2 + create_wrapper_function( + tcx, + &cx, + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + None, + &[], + None, + false, + ); } if tcx.sess.opts.debuginfo != DebugInfo::None { @@ -99,7 +104,7 @@ fn create_wrapper_function( tcx: TyCtxt<'_>, cx: &SimpleCx<'_>, from_name: &str, - to_name: &str, + to_name: Option<&str>, args: &[&Type], output: Option<&Type>, no_return: bool, @@ -128,33 +133,38 @@ fn create_wrapper_function( attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); } - let callee = declare_simple_fn( - &cx, - to_name, - llvm::CallConv::CCallConv, - llvm::UnnamedAddr::Global, - llvm::Visibility::Hidden, - ty, - ); - if let Some(no_return) = no_return { - // -> ! DIFlagNoReturn - attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); - } - llvm::set_visibility(callee, llvm::Visibility::Hidden); - let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; - let mut bx = SBuilder::build(&cx, llbb); - let args = args - .iter() - .enumerate() - .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) - .collect::>(); - let ret = bx.call(ty, callee, &args, None); - llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - bx.ret(ret); + + if let Some(to_name) = to_name { + let callee = declare_simple_fn( + &cx, + to_name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::Hidden, + ty, + ); + if let Some(no_return) = no_return { + // -> ! DIFlagNoReturn + attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); + } + llvm::set_visibility(callee, llvm::Visibility::Hidden); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) + .collect::>(); + let ret = bx.call(ty, callee, &args, None); + llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + bx.ret(ret); + } else { + bx.ret_void() + } } else { + assert!(output.is_none()); bx.ret_void() } } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 92b9b6e132e74..d0b6c7470fb9a 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -219,6 +219,7 @@ fn exported_symbols_provider_local<'tcx>( .chain([ mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), ]) { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); @@ -232,19 +233,6 @@ fn exported_symbols_provider_local<'tcx>( }, )); } - - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new( - tcx, - &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - )); - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Data, - used: false, - }, - )) } if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 49a5e20d7cf8b..1db8ad72b321c 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -85,10 +85,6 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin if item_name == "rust_eh_personality" { // rust_eh_personality must not be renamed as LLVM hard-codes the name return "rust_eh_personality".to_owned(); - } else if item_name == "__rust_no_alloc_shim_is_unstable" { - // Temporary back compat hack to give people the chance to migrate to - // include #[rustc_std_internal_symbol]. - return "__rust_no_alloc_shim_is_unstable".to_owned(); } let prefix = "_R"; diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index e1cc4ba25c4ea..b4176e9c1f4d0 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -31,8 +31,9 @@ unsafe extern "Rust" { #[rustc_std_internal_symbol] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; + #[rustc_nounwind] #[rustc_std_internal_symbol] - static __rust_no_alloc_shim_is_unstable: u8; + fn __rust_no_alloc_shim_is_unstable_v2(); } /// The global memory allocator. @@ -88,7 +89,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); + __rust_no_alloc_shim_is_unstable_v2(); __rust_alloc(layout.size(), layout.align()) } @@ -171,7 +172,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); + __rust_no_alloc_shim_is_unstable_v2(); __rust_alloc_zeroed(layout.size(), layout.align()) } diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 2feed5a835228..a2ea3dbd88b11 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -45,10 +45,6 @@ impl<'tcx> MiriMachine<'tcx> { /// Sets up the "extern statics" for this machine. pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> { - // "__rust_no_alloc_shim_is_unstable" - let val = ImmTy::from_int(0, ecx.machine.layouts.u8); // always 0, value does not matter - Self::alloc_extern_static(ecx, "__rust_no_alloc_shim_is_unstable", val)?; - // "__rust_alloc_error_handler_should_panic" let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic(); let val = ImmTy::from_int(val, ecx.machine.layouts.u8); diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index ae04ca018ab29..5d163828b051d 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -611,6 +611,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(new_ptr, dest) }); } + name if name == this.mangle_internal_symbol("__rust_no_alloc_shim_is_unstable_v2") => { + // This is a no-op shim that only exists to prevent making the allocator shims instantly stable. + let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; + } // C memory handling functions "memcmp" => { diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs index 0e88951dc43f9..9eba0ca171bc6 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.rs +++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort -//@normalize-stderr-test: "id 20" -> "id $$ALLOC" +//@compile-flags: -Zmiri-track-alloc-id=19 -Zmiri-track-alloc-accesses -Cpanic=abort +//@normalize-stderr-test: "id 19" -> "id $$ALLOC" //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations) extern "Rust" { diff --git a/tests/codegen/alloc-optimisation.rs b/tests/codegen/alloc-optimisation.rs index 19f14647c1d7d..3735860d510fb 100644 --- a/tests/codegen/alloc-optimisation.rs +++ b/tests/codegen/alloc-optimisation.rs @@ -5,7 +5,8 @@ pub fn alloc_test(data: u32) { // CHECK-LABEL: @alloc_test // CHECK-NEXT: start: - // CHECK-NEXT: {{.*}} load volatile i8, ptr @{{.*}}__rust_no_alloc_shim_is_unstable, align 1 + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() // CHECK-NEXT: ret void let x = Box::new(data); drop(x); diff --git a/tests/codegen/unwind-landingpad-inline.rs b/tests/codegen/unwind-landingpad-inline.rs index 920774b340240..1cf606279e623 100644 --- a/tests/codegen/unwind-landingpad-inline.rs +++ b/tests/codegen/unwind-landingpad-inline.rs @@ -10,8 +10,10 @@ // See https://github.com/rust-lang/rust/issues/46515 // CHECK-LABEL: @check_no_escape_in_landingpad // CHECK: start: -// CHECK-NEXT: __rust_no_alloc_shim_is_unstable -// CHECK-NEXT: __rust_no_alloc_shim_is_unstable +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM:_R.+__rust_no_alloc_shim_is_unstable_v2]]() +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM]]() // CHECK-NEXT: ret void #[no_mangle] pub fn check_no_escape_in_landingpad(f: fn()) { diff --git a/tests/codegen/vec-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs index a88573522d4d8..807548ef883f5 100644 --- a/tests/codegen/vec-iter-collect-len.rs +++ b/tests/codegen/vec-iter-collect-len.rs @@ -4,7 +4,9 @@ #[no_mangle] pub fn get_len() -> usize { // CHECK-LABEL: @get_len - // CHECK-NOT: call - // CHECK-NOT: invoke + // CHECK-NEXT: start: + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() + // CHECK-NEXT: ret i{{[0-9]+}} 3 [1, 2, 3].iter().collect::>().len() } diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs index f6ed2898bdaaa..93b55454b108c 100644 --- a/tests/codegen/vec-optimizes-away.rs +++ b/tests/codegen/vec-optimizes-away.rs @@ -5,7 +5,8 @@ pub fn sum_me() -> i32 { // CHECK-LABEL: @sum_me // CHECK-NEXT: {{^.*:$}} - // CHECK-NEXT: {{.*}} load volatile i8, ptr @{{.*}}__rust_no_alloc_shim_is_unstable, align 1 + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() // CHECK-NEXT: ret i32 6 vec![1, 2, 3].iter().sum::() } diff --git a/tests/run-make/no-alloc-shim/foo.rs b/tests/run-make/no-alloc-shim/foo.rs index 42606961f8bb2..b5d0d394d2b9f 100644 --- a/tests/run-make/no-alloc-shim/foo.rs +++ b/tests/run-make/no-alloc-shim/foo.rs @@ -1,4 +1,4 @@ -#![feature(default_alloc_error_handler)] +#![feature(rustc_attrs)] #![no_std] #![no_main] @@ -31,8 +31,8 @@ unsafe impl GlobalAlloc for Alloc { } #[cfg(not(check_feature_gate))] -#[no_mangle] -static __rust_no_alloc_shim_is_unstable: u8 = 0; +#[rustc_std_internal_symbol] +fn __rust_no_alloc_shim_is_unstable_v2() {} #[no_mangle] extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const i8) -> i32 { diff --git a/tests/run-make/no-alloc-shim/rmake.rs b/tests/run-make/no-alloc-shim/rmake.rs index d61ef5de8c56c..47cabfc208c77 100644 --- a/tests/run-make/no-alloc-shim/rmake.rs +++ b/tests/run-make/no-alloc-shim/rmake.rs @@ -7,12 +7,6 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -//@ ignore-msvc -//FIXME(Oneirical): Getting this to work on MSVC requires passing libcmt.lib to CC, -// which is not trivial to do. -// Tracking issue: https://github.com/rust-lang/rust/issues/128602 -// Discussion: https://github.com/rust-lang/rust/pull/128407#discussion_r1702439172 - use run_make_support::{cc, has_extension, has_prefix, run, rustc, shallow_find_files}; fn main() { @@ -30,15 +24,28 @@ fn main() { has_prefix(path, "libcompiler_builtins") && has_extension(path, "rlib") }); + #[allow(unused_mut)] + let mut platform_args = Vec::::new(); + #[cfg(target_env = "msvc")] + { + platform_args.push("-MD".to_string()); + + // `/link` tells MSVC that the remaining arguments are linker options. + platform_args.push("/link".to_string()); + platform_args.push("vcruntime.lib".to_string()); + platform_args.push("msvcrt.lib".to_string()); + } + cc().input("foo.o") .out_exe("foo") + .args(&platform_args) .args(&alloc_libs) .args(&core_libs) .args(&compiler_builtins_libs) .run(); run("foo"); - // Check that linking without __rust_no_alloc_shim_is_unstable defined fails + // Check that linking without __rust_no_alloc_shim_is_unstable_v2 defined fails rustc() .input("foo.rs") .crate_type("bin") @@ -48,6 +55,7 @@ fn main() { .run(); cc().input("foo.o") .out_exe("foo") + .args(&platform_args) .args(&alloc_libs) .args(&core_libs) .args(&compiler_builtins_libs) diff --git a/tests/run-make/symbols-all-mangled/rmake.rs b/tests/run-make/symbols-all-mangled/rmake.rs index 79ddd06bb94be..2cf579758002a 100644 --- a/tests/run-make/symbols-all-mangled/rmake.rs +++ b/tests/run-make/symbols-all-mangled/rmake.rs @@ -35,10 +35,6 @@ fn symbols_check_archive(path: &str) { continue; // All compiler-builtins symbols must remain unmangled } - if name == "__rust_no_alloc_shim_is_unstable" { - continue; // FIXME remove exception once we mangle this symbol - } - if name.contains("rust_eh_personality") { continue; // Unfortunately LLVM doesn't allow us to mangle this symbol } @@ -75,10 +71,6 @@ fn symbols_check(path: &str) { continue; } - if name == "__rust_no_alloc_shim_is_unstable" { - continue; // FIXME remove exception once we mangle this symbol - } - if name.contains("rust_eh_personality") { continue; // Unfortunately LLVM doesn't allow us to mangle this symbol } From 3ed1787714c93172e4fc52fbece23245cc9dd5cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 28 Dec 2024 02:19:35 +0000 Subject: [PATCH 16/27] Detect when attribute is provided by missing `derive` macro ``` error: cannot find attribute `empty_helper` in this scope --> $DIR/derive-helper-legacy-limits.rs:17:3 | LL | #[empty_helper] | ^^^^^^^^^^^^ | help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute | LL + #[derive(Empty)] LL | struct S2; | ``` Look at proc-macro attributes when encountering unknown attribute ``` error: cannot find attribute `sede` in this scope --> src/main.rs:18:7 | 18 | #[sede(untagged)] | ^^^^ | help: the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute | 18 | #[serde(untagged)] | ~~~~~ error: cannot find attribute `serde` in this scope --> src/main.rs:12:7 | 12 | #[serde(untagged)] | ^^^^^ | = note: `serde` is in scope, but it is a crate, not an attribute help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute | 10 | #[derive(Serialize, Deserialize)] | ``` --- compiler/rustc_resolve/src/diagnostics.rs | 137 +++++++++++++++++- compiler/rustc_resolve/src/ident.rs | 1 + compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_resolve/src/macros.rs | 30 +++- .../diagnostic-derive.stderr | 14 ++ tests/ui/macros/auxiliary/serde.rs | 19 +++ tests/ui/macros/missing-derive-1.rs | 33 +++++ tests/ui/macros/missing-derive-1.stderr | 47 ++++++ tests/ui/macros/missing-derive-2.rs | 26 ++++ tests/ui/macros/missing-derive-2.stderr | 47 ++++++ tests/ui/macros/missing-derive-3.rs | 24 +++ tests/ui/macros/missing-derive-3.stderr | 32 ++++ .../derive-helper-legacy-limits.stderr | 6 + .../proc-macro/derive-helper-shadowing.stderr | 2 + .../proc-macro/disappearing-resolution.stderr | 6 + 16 files changed, 422 insertions(+), 6 deletions(-) create mode 100644 tests/ui/macros/auxiliary/serde.rs create mode 100644 tests/ui/macros/missing-derive-1.rs create mode 100644 tests/ui/macros/missing-derive-1.stderr create mode 100644 tests/ui/macros/missing-derive-2.rs create mode 100644 tests/ui/macros/missing-derive-2.stderr create mode 100644 tests/ui/macros/missing-derive-3.rs create mode 100644 tests/ui/macros/missing-derive-3.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 201b1c0a493bc..4f0a285b9b82a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1054,6 +1054,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false, false, None, + None, ) else { continue; }; @@ -1482,7 +1483,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ident: Ident, krate: &Crate, + sugg_span: Option, ) { + // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used + // for suggestions. + self.visit_scopes( + ScopeSet::Macro(MacroKind::Derive), + &parent_scope, + ident.span.ctxt(), + |this, scope, _use_prelude, _ctxt| { + let Scope::Module(m, _) = scope else { + return None; + }; + for (_, resolution) in this.resolutions(m).borrow().iter() { + let Some(binding) = resolution.borrow().binding else { + continue; + }; + let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) = + binding.res() + else { + continue; + }; + // By doing this all *imported* macros get added to the `macro_map` even if they + // are *unused*, which makes the later suggestions find them and work. + let _ = this.get_macro_by_def_id(def_id); + } + None::<()> + }, + ); + let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind); let suggestion = self.early_lookup_typo_candidate( ScopeSet::Macro(macro_kind), @@ -1490,7 +1519,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, is_expected, ); - self.add_typo_suggestion(err, suggestion, ident.span); + if !self.add_typo_suggestion(err, suggestion, ident.span) { + self.detect_derive_attribute(err, ident, parent_scope, sugg_span); + } let import_suggestions = self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); @@ -1623,6 +1654,110 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + /// Given an attribute macro that failed to be resolved, look for `derive` macros that could + /// provide it, either as-is or with small typos. + fn detect_derive_attribute( + &self, + err: &mut Diag<'_>, + ident: Ident, + parent_scope: &ParentScope<'ra>, + sugg_span: Option, + ) { + // Find all of the `derive`s in scope and collect their corresponding declared + // attributes. + // FIXME: this only works if the crate that owns the macro that has the helper_attr + // has already been imported. + let mut derives = vec![]; + let mut all_attrs: FxHashMap> = FxHashMap::default(); + // We're collecting these in a hashmap, and handle ordering the output further down. + #[allow(rustc::potential_query_instability)] + for (def_id, data) in &self.macro_map { + for helper_attr in &data.ext.helper_attrs { + let item_name = self.tcx.item_name(*def_id); + all_attrs.entry(*helper_attr).or_default().push(item_name); + if helper_attr == &ident.name { + derives.push(item_name); + } + } + } + let kind = MacroKind::Derive.descr(); + if !derives.is_empty() { + // We found an exact match for the missing attribute in a `derive` macro. Suggest it. + derives.sort(); + derives.dedup(); + let msg = match &derives[..] { + [derive] => format!(" `{derive}`"), + [start @ .., last] => format!( + "s {} and `{last}`", + start.iter().map(|d| format!("`{d}`")).collect::>().join(", ") + ), + [] => unreachable!("we checked for this to be non-empty 10 lines above!?"), + }; + let msg = format!( + "`{}` is an attribute that can be used by the {kind}{msg}, you might be \ + missing a `derive` attribute", + ident.name, + ); + let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind + { + let span = self.def_span(id); + if span.from_expansion() { + None + } else { + // For enum variants sugg_span is empty but we can get the enum's Span. + Some(span.shrink_to_lo()) + } + } else { + // For items this `Span` will be populated, everything else it'll be None. + sugg_span + }; + match sugg_span { + Some(span) => { + err.span_suggestion_verbose( + span, + msg, + format!( + "#[derive({})]\n", + derives + .iter() + .map(|d| d.to_string()) + .collect::>() + .join(", ") + ), + Applicability::MaybeIncorrect, + ); + } + None => { + err.note(msg); + } + } + } else { + // We didn't find an exact match. Look for close matches. If any, suggest fixing typo. + #[allow(rustc::potential_query_instability)] // We're immediately sorting these. + let mut all_attr_names: Vec = all_attrs.keys().cloned().collect(); + all_attr_names.sort(); + if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None) + && let Some(macros) = all_attrs.get(&best_match) + { + let msg = match ¯os[..] { + [] => return, + [name] => format!(" `{name}` accepts"), + [start @ .., end] => format!( + "s {} and `{end}` accept", + start.iter().map(|m| format!("`{m}`")).collect::>().join(", "), + ), + }; + let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute"); + err.span_suggestion_verbose( + ident.span, + msg, + best_match, + Applicability::MaybeIncorrect, + ); + } + } + } + pub(crate) fn add_typo_suggestion( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 180d6af219d11..68fbe48ebcb08 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -460,6 +460,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, force, ignore_import, + None, ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3dc285fdab690..fa4b024c422f0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4509,7 +4509,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; if let Ok((_, res)) = - self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None) + self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None) { return Ok(Some(PartialRes::new(res))); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9ba70abd4d933..2ff48c503c559 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1139,7 +1139,7 @@ pub struct Resolver<'ra, 'tcx> { proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: - Vec<(Ident, MacroKind, ParentScope<'ra>, Option>)>, + Vec<(Ident, MacroKind, ParentScope<'ra>, Option>, Option)>, multi_segment_macro_resolutions: Vec<(Vec, Span, MacroKind, ParentScope<'ra>, Option, Namespace)>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index ee905065b966b..e80d4422e3748 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -12,7 +12,8 @@ use rustc_attr_data_structures::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ - DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, + Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, + SyntaxExtensionKind, }; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{ @@ -294,6 +295,14 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { && self.tcx.def_kind(mod_def_id) == DefKind::Mod }) .map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id); + let sugg_span = match &invoc.kind { + InvocationKind::Attr { item: Annotatable::Item(item), .. } + if !item.span.from_expansion() => + { + Some(item.span.shrink_to_lo()) + } + _ => None, + }; let (ext, res) = self.smart_resolve_macro_path( path, kind, @@ -304,6 +313,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { force, deleg_impl, looks_like_invoc_in_mod_inert_attr, + sugg_span, )?; let span = invoc.span(); @@ -386,6 +396,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { true, force, None, + None, ) { Ok((Some(ext), _)) => { if !ext.helper_attrs.is_empty() { @@ -528,6 +539,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force: bool, deleg_impl: Option, invoc_in_mod_inert_attr: Option, + suggestion_span: Option, ) -> Result<(Arc, Res), Indeterminate> { let (ext, res) = match self.resolve_macro_or_delegation_path( path, @@ -538,6 +550,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { deleg_impl, invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)), None, + suggestion_span, ) { Ok((Some(ext), res)) => (ext, res), Ok((None, res)) => (self.dummy_ext(kind), res), @@ -681,6 +694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trace: bool, force: bool, ignore_import: Option>, + suggestion_span: Option, ) -> Result<(Option>, Res), Determinacy> { self.resolve_macro_or_delegation_path( path, @@ -691,6 +705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, None, ignore_import, + suggestion_span, ) } @@ -704,6 +719,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { deleg_impl: Option, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, ignore_import: Option>, + suggestion_span: Option, ) -> Result<(Option>, Res), Determinacy> { let path_span = ast_path.span; let mut path = Segment::from_path(ast_path); @@ -768,6 +784,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { kind, *parent_scope, binding.ok(), + suggestion_span, )); } @@ -905,7 +922,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); - for (ident, kind, parent_scope, initial_binding) in macro_resolutions { + for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { match self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(kind), @@ -946,7 +963,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expected, ident, }); - self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate); + self.unresolved_macro_suggestions( + &mut err, + kind, + &parent_scope, + ident, + krate, + sugg_span, + ); err.emit(); } } diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 03fca17aa55d4..001699b2bc726 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -583,18 +583,32 @@ error: cannot find attribute `multipart_suggestion` in this scope | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ + | +help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute + | +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { + | error: cannot find attribute `multipart_suggestion` in this scope --> $DIR/diagnostic-derive.rs:647:3 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^ + | +help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute + | +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { + | error: cannot find attribute `multipart_suggestion` in this scope --> $DIR/diagnostic-derive.rs:651:7 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated` --> $DIR/diagnostic-derive.rs:75:8 diff --git a/tests/ui/macros/auxiliary/serde.rs b/tests/ui/macros/auxiliary/serde.rs new file mode 100644 index 0000000000000..355b650bcf390 --- /dev/null +++ b/tests/ui/macros/auxiliary/serde.rs @@ -0,0 +1,19 @@ +//@ force-host +//@ no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro_derive(Serialize, attributes(serde))] +pub fn serialize(ts: TokenStream) -> TokenStream { + quote!{} +} + +#[proc_macro_derive(Deserialize, attributes(serde))] +pub fn deserialize(ts: TokenStream) -> TokenStream { + quote!{} +} diff --git a/tests/ui/macros/missing-derive-1.rs b/tests/ui/macros/missing-derive-1.rs new file mode 100644 index 0000000000000..b5221fbca60a8 --- /dev/null +++ b/tests/ui/macros/missing-derive-1.rs @@ -0,0 +1,33 @@ +//@aux-build:serde.rs + +// derive macros imported and used + +extern crate serde; +use serde::{Serialize, Deserialize}; + +#[serde(untagged)] //~ ERROR cannot find attribute `serde` +enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize` + A, + B, +} + +enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize` + A, + #[serde(untagged)] //~ ERROR cannot find attribute `serde` + B, +} + +enum C { + A, + #[sede(untagged)] //~ ERROR cannot find attribute `sede` + B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute +} + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +enum D { + A, + B, +} + +fn main() {} diff --git a/tests/ui/macros/missing-derive-1.stderr b/tests/ui/macros/missing-derive-1.stderr new file mode 100644 index 0000000000000..d7255d5937e06 --- /dev/null +++ b/tests/ui/macros/missing-derive-1.stderr @@ -0,0 +1,47 @@ +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-1.rs:8:3 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-1.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute + | +LL + #[derive(Serialize, Deserialize)] +LL | enum A { + | + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-1.rs:16:7 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-1.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute + | +LL + #[derive(Serialize, Deserialize)] +LL | enum B { + | + +error: cannot find attribute `sede` in this scope + --> $DIR/missing-derive-1.rs:22:7 + | +LL | #[sede(untagged)] + | ^^^^ + | +help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute + | +LL | #[serde(untagged)] + | + + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/missing-derive-2.rs b/tests/ui/macros/missing-derive-2.rs new file mode 100644 index 0000000000000..754aab0287ade --- /dev/null +++ b/tests/ui/macros/missing-derive-2.rs @@ -0,0 +1,26 @@ +//@aux-build:serde.rs + +// derive macros imported but unused + +extern crate serde; +use serde::{Serialize, Deserialize}; + +#[serde(untagged)] //~ ERROR cannot find attribute `serde` +enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize` + A, + B, +} + +enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize` + A, + #[serde(untagged)] //~ ERROR cannot find attribute `serde` + B, +} + +enum C { + A, + #[sede(untagged)] //~ ERROR cannot find attribute `sede` + B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute +} + +fn main() {} diff --git a/tests/ui/macros/missing-derive-2.stderr b/tests/ui/macros/missing-derive-2.stderr new file mode 100644 index 0000000000000..7234515bde2cc --- /dev/null +++ b/tests/ui/macros/missing-derive-2.stderr @@ -0,0 +1,47 @@ +error: cannot find attribute `sede` in this scope + --> $DIR/missing-derive-2.rs:22:7 + | +LL | #[sede(untagged)] + | ^^^^ + | +help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute + | +LL | #[serde(untagged)] + | + + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-2.rs:16:7 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-2.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute + | +LL + #[derive(Serialize, Deserialize)] +LL | enum B { + | + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-2.rs:8:3 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-2.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute + | +LL + #[derive(Serialize, Deserialize)] +LL | enum A { + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/missing-derive-3.rs b/tests/ui/macros/missing-derive-3.rs new file mode 100644 index 0000000000000..8add81988901a --- /dev/null +++ b/tests/ui/macros/missing-derive-3.rs @@ -0,0 +1,24 @@ +//@aux-build:serde.rs + +// derive macros not imported, but namespace imported. Not yet handled. +extern crate serde; + +#[serde(untagged)] //~ ERROR cannot find attribute `serde` +enum A { + A, + B, +} + +enum B { + A, + #[serde(untagged)] //~ ERROR cannot find attribute `serde` + B, +} + +enum C { + A, + #[sede(untagged)] //~ ERROR cannot find attribute `sede` + B, +} + +fn main() {} diff --git a/tests/ui/macros/missing-derive-3.stderr b/tests/ui/macros/missing-derive-3.stderr new file mode 100644 index 0000000000000..0a7ed8d08763c --- /dev/null +++ b/tests/ui/macros/missing-derive-3.stderr @@ -0,0 +1,32 @@ +error: cannot find attribute `sede` in this scope + --> $DIR/missing-derive-3.rs:20:7 + | +LL | #[sede(untagged)] + | ^^^^ + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-3.rs:14:7 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-3.rs:4:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-3.rs:6:3 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-3.rs:4:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr index f5cd455435d4a..df3c5c47ddb2d 100644 --- a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr +++ b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr @@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope | LL | #[empty_helper] | ^^^^^^^^^^^^ + | +help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute + | +LL + #[derive(Empty)] +LL | struct S2; + | error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr index f284b1c54dd61..1206778bb2352 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.stderr +++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr @@ -16,6 +16,7 @@ error: cannot find attribute `empty_helper` in this scope LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ | + = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this attribute macro through its public re-export | @@ -31,6 +32,7 @@ LL | #[empty_helper] LL | gen_helper_use!(); | ----------------- in this macro invocation | + = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this attribute macro through its public re-export | diff --git a/tests/ui/proc-macro/disappearing-resolution.stderr b/tests/ui/proc-macro/disappearing-resolution.stderr index 734e0cd2ab6df..6c0f1a52915f6 100644 --- a/tests/ui/proc-macro/disappearing-resolution.stderr +++ b/tests/ui/proc-macro/disappearing-resolution.stderr @@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope | LL | #[empty_helper] | ^^^^^^^^^^^^ + | +help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute + | +LL + #[derive(Empty)] +LL | struct S; + | error[E0603]: derive macro import `Empty` is private --> $DIR/disappearing-resolution.rs:11:8 From 1cdd33ebe2bec7eea928e147c0adc4e36c22a1da Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 5 Jun 2025 19:46:16 -0500 Subject: [PATCH 17/27] core::ptr: deduplicate more method docs --- library/core/src/ptr/const_ptr.rs | 64 +----------------- library/core/src/ptr/docs/as_uninit_slice.md | 44 +++++++++++++ library/core/src/ptr/docs/is_null.md | 18 ++++++ library/core/src/ptr/mut_ptr.rs | 68 ++------------------ 4 files changed, 68 insertions(+), 126 deletions(-) create mode 100644 library/core/src/ptr/docs/as_uninit_slice.md create mode 100644 library/core/src/ptr/docs/is_null.md diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index a1dab23ea7b49..9366cb36c6efa 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -5,24 +5,7 @@ use crate::mem::{self, SizedTypeProperties}; use crate::slice::{self, SliceIndex}; impl *const T { - /// Returns `true` if the pointer is null. - /// - /// Note that unsized types have many possible null pointers, as only the - /// raw data pointer is considered, not their length, vtable, etc. - /// Therefore, two pointers that are null may still not compare equal to - /// each other. - /// - /// # Panics during const evaluation - /// - /// If this method is used during const evaluation, and `self` is a pointer - /// that is offset beyond the bounds of the memory it initially pointed to, - /// then there might not be enough information to determine whether the - /// pointer is null. This is because the absolute address in memory is not - /// known at compile time. If the nullness of the pointer cannot be - /// determined, this method will panic. - /// - /// In-bounds pointers are never null, so the method will never panic for - /// such pointers. + #[doc = include_str!("docs/is_null.md")] /// /// # Examples /// @@ -1550,50 +1533,7 @@ impl *const [T] { unsafe { index.get_unchecked(self) } } - /// Returns `None` if the pointer is null, or else returns a shared slice to - /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require - /// that the value has to be initialized. - /// - /// [`as_ref`]: #method.as_ref - /// - /// # Safety - /// - /// When calling this method, you have to ensure that *either* the pointer is null *or* - /// all of the following is true: - /// - /// * The pointer must be [valid] for reads for `ptr.len() * size_of::()` many bytes, - /// and it must be properly aligned. This means in particular: - /// - /// * The entire memory range of this slice must be contained within a single [allocation]! - /// Slices can never span across multiple allocations. - /// - /// * The pointer must be aligned even for zero-length slices. One - /// reason for this is that enum layout optimizations may rely on references - /// (including slices of any length) being aligned and non-null to distinguish - /// them from other data. You can obtain a pointer that is usable as `data` - /// for zero-length slices using [`NonNull::dangling()`]. - /// - /// * The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. - /// See the safety documentation of [`pointer::offset`]. - /// - /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is - /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. - /// In particular, while this reference exists, the memory the pointer points to must - /// not get mutated (except inside `UnsafeCell`). - /// - /// This applies even if the result of this method is unused! - /// - /// See also [`slice::from_raw_parts`][]. - /// - /// [valid]: crate::ptr#safety - /// [allocation]: crate::ptr#allocation - /// - /// # Panics during const evaluation - /// - /// This method will panic during const evaluation if the pointer cannot be - /// determined to be null or not. See [`is_null`] for more information. - /// - /// [`is_null`]: #method.is_null + #[doc = include_str!("docs/as_uninit_slice.md")] #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit]> { diff --git a/library/core/src/ptr/docs/as_uninit_slice.md b/library/core/src/ptr/docs/as_uninit_slice.md new file mode 100644 index 0000000000000..c80c04058838f --- /dev/null +++ b/library/core/src/ptr/docs/as_uninit_slice.md @@ -0,0 +1,44 @@ +Returns `None` if the pointer is null, or else returns a shared slice to +the value wrapped in `Some`. In contrast to [`as_ref`], this does not require +that the value has to be initialized. + +[`as_ref`]: #method.as_ref + +# Safety + +When calling this method, you have to ensure that *either* the pointer is null *or* +all of the following is true: + +* The pointer must be [valid] for reads for `ptr.len() * size_of::()` many bytes, +and it must be properly aligned. This means in particular: + +* The entire memory range of this slice must be contained within a single [allocation]! +Slices can never span across multiple allocations. + +* The pointer must be aligned even for zero-length slices. One +reason for this is that enum layout optimizations may rely on references +(including slices of any length) being aligned and non-null to distinguish +them from other data. You can obtain a pointer that is usable as `data` +for zero-length slices using [`NonNull::dangling()`]. + +* The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. +See the safety documentation of [`pointer::offset`]. + +* You must enforce Rust's aliasing rules, since the returned lifetime `'a` is +arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. +In particular, while this reference exists, the memory the pointer points to must +not get mutated (except inside `UnsafeCell`). + +This applies even if the result of this method is unused! + +See also [`slice::from_raw_parts`][]. + +[valid]: crate::ptr#safety +[allocation]: crate::ptr#allocation + +# Panics during const evaluation + +This method will panic during const evaluation if the pointer cannot be +determined to be null or not. See [`is_null`] for more information. + +[`is_null`]: #method.is_null diff --git a/library/core/src/ptr/docs/is_null.md b/library/core/src/ptr/docs/is_null.md new file mode 100644 index 0000000000000..7368ab9b57630 --- /dev/null +++ b/library/core/src/ptr/docs/is_null.md @@ -0,0 +1,18 @@ +Returns `true` if the pointer is null. + +Note that unsized types have many possible null pointers, as only the +raw data pointer is considered, not their length, vtable, etc. +Therefore, two pointers that are null may still not compare equal to +each other. + +# Panics during const evaluation + +If this method is used during const evaluation, and `self` is a pointer +that is offset beyond the bounds of the memory it initially pointed to, +then there might not be enough information to determine whether the +pointer is null. This is because the absolute address in memory is not +known at compile time. If the nullness of the pointer cannot be +determined, this method will panic. + +In-bounds pointers are never null, so the method will never panic for +such pointers. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 968f033bf5983..efe1031b79cac 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -5,24 +5,7 @@ use crate::mem::{self, SizedTypeProperties}; use crate::slice::{self, SliceIndex}; impl *mut T { - /// Returns `true` if the pointer is null. - /// - /// Note that unsized types have many possible null pointers, as only the - /// raw data pointer is considered, not their length, vtable, etc. - /// Therefore, two pointers that are null may still not compare equal to - /// each other. - /// - /// # Panics during const evaluation - /// - /// If this method is used during const evaluation, and `self` is a pointer - /// that is offset beyond the bounds of the memory it initially pointed to, - /// then there might not be enough information to determine whether the - /// pointer is null. This is because the absolute address in memory is not - /// known at compile time. If the nullness of the pointer cannot be - /// determined, this method will panic. - /// - /// In-bounds pointers are never null, so the method will never panic for - /// such pointers. + #[doc = include_str!("docs/is_null.md")] /// /// # Examples /// @@ -1906,53 +1889,10 @@ impl *mut [T] { unsafe { index.get_unchecked_mut(self) } } - /// Returns `None` if the pointer is null, or else returns a shared slice to - /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require - /// that the value has to be initialized. - /// - /// For the mutable counterpart see [`as_uninit_slice_mut`]. - /// - /// [`as_ref`]: pointer#method.as_ref-1 - /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut - /// - /// # Safety - /// - /// When calling this method, you have to ensure that *either* the pointer is null *or* - /// all of the following is true: - /// - /// * The pointer must be [valid] for reads for `ptr.len() * size_of::()` many bytes, - /// and it must be properly aligned. This means in particular: - /// - /// * The entire memory range of this slice must be contained within a single [allocation]! - /// Slices can never span across multiple allocations. - /// - /// * The pointer must be aligned even for zero-length slices. One - /// reason for this is that enum layout optimizations may rely on references - /// (including slices of any length) being aligned and non-null to distinguish - /// them from other data. You can obtain a pointer that is usable as `data` - /// for zero-length slices using [`NonNull::dangling()`]. - /// - /// * The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. - /// See the safety documentation of [`pointer::offset`]. - /// - /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is - /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. - /// In particular, while this reference exists, the memory the pointer points to must - /// not get mutated (except inside `UnsafeCell`). - /// - /// This applies even if the result of this method is unused! - /// - /// See also [`slice::from_raw_parts`][]. - /// - /// [valid]: crate::ptr#safety - /// [allocation]: crate::ptr#allocation + #[doc = include_str!("docs/as_uninit_slice.md")] /// - /// # Panics during const evaluation - /// - /// This method will panic during const evaluation if the pointer cannot be - /// determined to be null or not. See [`is_null`] for more information. - /// - /// [`is_null`]: #method.is_null-1 + /// # See Also + /// For the mutable counterpart see [`as_uninit_slice_mut`](pointer::as_uninit_slice_mut). #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit]> { From a9401ea657d24878ebee7511d6a51a5df8ed3071 Mon Sep 17 00:00:00 2001 From: Teoh Han Hui Date: Tue, 10 Jun 2025 02:24:04 +0800 Subject: [PATCH 18/27] platform-support.md: Mention specific Linux kernel version or later --- src/doc/rustc/src/platform-support.md | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e2e2ad9ac3b5b..559e4867bbb10 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -33,7 +33,7 @@ All tier 1 targets with host tools support the full standard library. target | notes -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) -`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+) +`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+) `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+) @@ -91,20 +91,20 @@ target | notes `aarch64-pc-windows-msvc` | ARM64 Windows MSVC `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony -`arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17) -`arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17) -`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) +`arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17) +`arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2+, glibc 2.17) +`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17) [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony -[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) -[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) +[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36) +[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5) [`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] -`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) -`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17) -[`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10, glibc 2.17) -[`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19, musl 1.2.3) -[`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29) -[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3) -[`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2, glibc 2.17) +`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2+, glibc 2.17) +`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2+, glibc 2.17) +[`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10+, glibc 2.17) +[`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19+, musl 1.2.3) +[`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20+, glibc 2.29) +[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20+, musl 1.2.3) +[`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2+, glibc 2.17) [`x86_64-unknown-freebsd`](platform-support/freebsd.md) | 64-bit x86 FreeBSD [`x86_64-unknown-illumos`](platform-support/illumos.md) | illumos `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 @@ -158,16 +158,16 @@ target | std | notes [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC [`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian [`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat -[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23) +[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android -`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15, glibc 2.27) +`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27) `armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3 `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat -`i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87] +`i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2+, glibc 2.17, original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] [`i686-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI] @@ -184,13 +184,13 @@ target | std | notes [`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA) `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) -`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) +`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4+, glibc 2.23) [`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M [`thumbv7em-none-eabi`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M [`thumbv7em-none-eabihf`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M, hardfloat [`thumbv7m-none-eabi`](platform-support/thumbv7m-none-eabi.md) | * | Bare Armv7-M [`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode Armv7-A Android with NEON -`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode Armv7-A Linux with NEON (kernel 4.4, glibc 2.23) +`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode Armv7-A Linux with NEON (kernel 4.4+, glibc 2.23) [`thumbv8m.base-none-eabi`](platform-support/thumbv8m.base-none-eabi.md) | * | Bare Armv8-M Baseline [`thumbv8m.main-none-eabi`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline [`thumbv8m.main-none-eabihf`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline, hardfloat @@ -206,7 +206,7 @@ target | std | notes [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android [`x86_64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 64-bit x86 MinGW (Windows 10+), LLVM ABI [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia -`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) +`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15+, glibc 2.27) [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat [`x86_64-unknown-redox`](platform-support/redox.md) | ✓ | Redox OS [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 64-bit UEFI From eb420d1dbfa86b11c83ecd95337e5cac8c87353c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Jun 2025 21:47:37 +0200 Subject: [PATCH 19/27] update lockfile --- Cargo.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 164617c909fea..3d9d7492af758 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2326,7 +2326,6 @@ dependencies = [ "tempfile", "tikv-jemalloc-sys", "ui_test", - "windows-sys 0.59.0", ] [[package]] From 3fce086d79afd9bc5b52a13e051934694cf196c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 4 Jun 2025 21:10:27 +0000 Subject: [PATCH 20/27] Make E0621 missing lifetime suggestion verbose ``` error[E0621]: explicit lifetime required in the type of `x` --> $DIR/42701_one_named_and_one_anonymous.rs:10:9 | LL | &*x | ^^^ lifetime `'a` required | help: add explicit lifetime `'a` to the type of `x` | LL | fn foo2<'a>(a: &'a Foo, x: &'a i32) -> &'a i32 { | ++ ``` --- compiler/rustc_trait_selection/src/errors.rs | 12 ++++++++---- ...hout-precise-captures-we-are-powerless.stderr | 16 ++++++++++------ tests/ui/async-await/issues/issue-63388-1.stderr | 9 ++++++--- .../must_outlive_least_region_or_bound.stderr | 9 ++++++--- tests/ui/issues/issue-13058.stderr | 8 +++++--- tests/ui/issues/issue-14285.stderr | 8 ++++++-- tests/ui/issues/issue-15034.stderr | 7 +++++-- tests/ui/issues/issue-3154.stderr | 7 +++++-- tests/ui/issues/issue-40288-2.stderr | 16 ++++++++++------ .../42701_one_named_and_one_anonymous.stderr | 8 +++++--- ...ne-existing-name-early-bound-in-struct.stderr | 8 +++++--- ...ex1-return-one-existing-name-if-else-2.stderr | 7 +++++-- ...ex1-return-one-existing-name-if-else-3.stderr | 7 +++++-- ...one-existing-name-if-else-using-impl-2.stderr | 7 +++++-- ...one-existing-name-if-else-using-impl-3.stderr | 7 +++++-- .../ex1-return-one-existing-name-if-else.stderr | 7 +++++-- .../ex2a-push-one-existing-name-2.stderr | 7 +++++-- ...x2a-push-one-existing-name-early-bound.stderr | 8 +++++--- .../ex2a-push-one-existing-name.stderr | 7 +++++-- tests/ui/lifetimes/noisy-follow-up-erro.stderr | 9 ++++++--- ...object-lifetime-default-from-box-error.stderr | 8 +++++--- tests/ui/regions/regions-glb-free-free.stderr | 7 +++++-- .../regions/regions-infer-at-fn-not-param.stderr | 9 ++++++--- .../missing-lifetimes-in-signature.stderr | 8 +++++--- tests/ui/variance/variance-trait-matching.stderr | 8 +++++--- 25 files changed, 143 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 06f81ac554e62..7bf49056e2991 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -759,7 +759,8 @@ pub enum ExplicitLifetimeRequired<'a> { #[suggestion( trait_selection_explicit_lifetime_required_sugg_with_ident, code = "{new_ty}", - applicability = "unspecified" + applicability = "unspecified", + style = "verbose" )] new_ty_span: Span, #[skip_arg] @@ -774,7 +775,8 @@ pub enum ExplicitLifetimeRequired<'a> { #[suggestion( trait_selection_explicit_lifetime_required_sugg_with_param_type, code = "{new_ty}", - applicability = "unspecified" + applicability = "unspecified", + style = "verbose" )] new_ty_span: Span, #[skip_arg] @@ -1462,7 +1464,8 @@ pub enum SuggestAccessingField<'a> { #[suggestion( trait_selection_suggest_accessing_field, code = "{snippet}.{name}", - applicability = "maybe-incorrect" + applicability = "maybe-incorrect", + style = "verbose" )] Safe { #[primary_span] @@ -1474,7 +1477,8 @@ pub enum SuggestAccessingField<'a> { #[suggestion( trait_selection_suggest_accessing_field, code = "unsafe {{ {snippet}.{name} }}", - applicability = "maybe-incorrect" + applicability = "maybe-incorrect", + style = "verbose" )] Unsafe { #[primary_span] diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr index 329cec6dad3a3..b7259074bf64b 100644 --- a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr @@ -106,11 +106,13 @@ LL | } error[E0621]: explicit lifetime required in the type of `x` --> $DIR/without-precise-captures-we-are-powerless.rs:38:5 | -LL | fn through_field_and_ref<'a>(x: &S<'a>) { - | ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>` -... LL | outlives::<'a>(call_once(c)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn through_field_and_ref<'a>(x: &'a S<'a>) { + | ++ error[E0597]: `c` does not live long enough --> $DIR/without-precise-captures-we-are-powerless.rs:43:20 @@ -131,11 +133,13 @@ LL | } error[E0621]: explicit lifetime required in the type of `x` --> $DIR/without-precise-captures-we-are-powerless.rs:44:5 | -LL | fn through_field_and_ref_move<'a>(x: &S<'a>) { - | ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>` -... LL | outlives::<'a>(call_once(c)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn through_field_and_ref_move<'a>(x: &'a S<'a>) { + | ++ error: aborting due to 10 previous errors diff --git a/tests/ui/async-await/issues/issue-63388-1.stderr b/tests/ui/async-await/issues/issue-63388-1.stderr index 277f7fa6f63ed..a59fe7dbc20e6 100644 --- a/tests/ui/async-await/issues/issue-63388-1.stderr +++ b/tests/ui/async-await/issues/issue-63388-1.stderr @@ -1,11 +1,14 @@ error[E0621]: explicit lifetime required in the type of `foo` --> $DIR/issue-63388-1.rs:14:9 | -LL | &'a self, foo: &dyn Foo - | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` -... LL | foo | ^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `foo` + | +LL - &'a self, foo: &dyn Foo +LL + &'a self, foo: &'a (dyn Foo + 'a) + | error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr index ba7d7770e5038..53c5568660417 100644 --- a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -65,9 +65,12 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/must_outlive_least_region_or_bound.rs:15:41 | LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } - | ---- ^ lifetime `'a` required - | | - | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` + | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(x: &'a i32) -> impl Copy + 'a { x } + | ++ error: lifetime may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:30:55 diff --git a/tests/ui/issues/issue-13058.stderr b/tests/ui/issues/issue-13058.stderr index 7cc2860eb5086..4f4108fa18254 100644 --- a/tests/ui/issues/issue-13058.stderr +++ b/tests/ui/issues/issue-13058.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `cont` --> $DIR/issue-13058.rs:14:21 | -LL | fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool - | -- help: add explicit lifetime `'r` to the type of `cont`: `&'r T` -LL | { LL | let cont_iter = cont.iter(); | ^^^^^^^^^^^ lifetime `'r` required + | +help: add explicit lifetime `'r` to the type of `cont` + | +LL | fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &'r T) -> bool + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-14285.stderr b/tests/ui/issues/issue-14285.stderr index 4f89ae51157b8..edd139eecba4d 100644 --- a/tests/ui/issues/issue-14285.stderr +++ b/tests/ui/issues/issue-14285.stderr @@ -1,10 +1,14 @@ error[E0621]: explicit lifetime required in the type of `a` --> $DIR/issue-14285.rs:12:5 | -LL | fn foo<'a>(a: &dyn Foo) -> B<'a> { - | -------- help: add explicit lifetime `'a` to the type of `a`: `&'a (dyn Foo + 'a)` LL | B(a) | ^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `a` + | +LL - fn foo<'a>(a: &dyn Foo) -> B<'a> { +LL + fn foo<'a>(a: &'a (dyn Foo + 'a)) -> B<'a> { + | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-15034.stderr b/tests/ui/issues/issue-15034.stderr index 587a5c85e924a..7db8ade2e482c 100644 --- a/tests/ui/issues/issue-15034.stderr +++ b/tests/ui/issues/issue-15034.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `lexer` --> $DIR/issue-15034.rs:17:9 | -LL | pub fn new(lexer: &'a mut Lexer) -> Parser<'a> { - | ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>` LL | Parser { lexer: lexer } | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `lexer` + | +LL | pub fn new(lexer: &'a mut Lexer<'a>) -> Parser<'a> { + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3154.stderr b/tests/ui/issues/issue-3154.stderr index 3106aaddc4a1c..c17e59f7fc3d6 100644 --- a/tests/ui/issues/issue-3154.stderr +++ b/tests/ui/issues/issue-3154.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/issue-3154.rs:6:5 | -LL | fn thing<'a,Q>(x: &Q) -> Thing<'a,Q> { - | -- help: add explicit lifetime `'a` to the type of `x`: `&'a Q` LL | Thing { x: x } | ^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn thing<'a,Q>(x: &'a Q) -> Thing<'a,Q> { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-40288-2.stderr b/tests/ui/issues/issue-40288-2.stderr index 2c64856b08f8d..81cb7cdd51ff6 100644 --- a/tests/ui/issues/issue-40288-2.stderr +++ b/tests/ui/issues/issue-40288-2.stderr @@ -1,20 +1,24 @@ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/issue-40288-2.rs:9:5 | -LL | fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { - | -- help: add explicit lifetime `'a` to the type of `y`: `&'a T` -... LL | out[0] | ^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &'a T) -> &'a T { + | ++ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/issue-40288-2.rs:24:5 | -LL | fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { - | -- help: add explicit lifetime `'a` to the type of `y`: `&'a T` -... LL | out.head | ^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &'a T) -> &'a T { + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr b/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr index af22078aff590..c524aabfacb86 100644 --- a/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr +++ b/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/42701_one_named_and_one_anonymous.rs:10:9 | -LL | fn foo2<'a>(a: &'a Foo, x: &i32) -> &'a i32 { - | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -... LL | &*x | ^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo2<'a>(a: &'a Foo, x: &'a i32) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr index e202c31214d37..44a542eeeeb6a 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `other` --> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:11:21 | -LL | fn bar(&self, other: Foo) -> Foo<'a> { - | --- help: add explicit lifetime `'a` to the type of `other`: `Foo<'a>` -... LL | other | ^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `other` + | +LL | fn bar(&self, other: Foo<'a>) -> Foo<'a> { + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr index 5518ded0106d9..52cf8595448d9 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/ex1-return-one-existing-name-if-else-2.rs:2:16 | -LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { - | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` LL | if x > y { x } else { y } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr index c689fa9884a76..fbd9695e85fab 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in parameter type --> $DIR/ex1-return-one-existing-name-if-else-3.rs:2:27 | -LL | fn foo<'a>((x, y): (&'a i32, &i32)) -> &'a i32 { - | --------------- help: add explicit lifetime `'a` to type: `(&'a i32, &'a i32)` LL | if x > y { x } else { y } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to type + | +LL | fn foo<'a>((x, y): (&'a i32, &'a i32)) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr index 3da50cfbb1d08..c875381c615fc 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:4:15 | -LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { - | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` LL | if x > y { x } else { y } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr index 071bda24ef8de..83cd11baf3916 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:7:36 | -LL | fn foo<'a>(&'a self, x: &i32) -> &i32 { - | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` LL | if true { &self.field } else { x } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(&'a self, x: &'a i32) -> &i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr index 1df0776a51b58..bf09bd26359c5 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/ex1-return-one-existing-name-if-else.rs:2:27 | -LL | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { - | ---- help: add explicit lifetime `'a` to the type of `y`: `&'a i32` LL | if x > y { x } else { y } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr index 25a2f4b96f40d..f37e1ba00e7e7 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/ex2a-push-one-existing-name-2.rs:6:5 | -LL | fn foo<'a>(x: Ref, y: &mut Vec>) { - | -------- help: add explicit lifetime `'a` to the type of `x`: `Ref<'a, i32>` LL | y.push(x); | ^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(x: Ref<'a, i32>, y: &mut Vec>) { + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr index e2725977d8370..c25b4c9921f8e 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/ex2a-push-one-existing-name-early-bound.rs:8:5 | -LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T) - | -- help: add explicit lifetime `'a` to the type of `y`: `&'a T` -... LL | x.push(y); | ^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &'a T) + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr index 1025581d5acf5..8c7bee4bfc400 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/ex2a-push-one-existing-name.rs:6:5 | -LL | fn foo<'a>(x: &mut Vec>, y: Ref) { - | -------- help: add explicit lifetime `'a` to the type of `y`: `Ref<'a, i32>` LL | x.push(y); | ^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn foo<'a>(x: &mut Vec>, y: Ref<'a, i32>) { + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/noisy-follow-up-erro.stderr b/tests/ui/lifetimes/noisy-follow-up-erro.stderr index 04863badbd1ef..eb52147dba4bb 100644 --- a/tests/ui/lifetimes/noisy-follow-up-erro.stderr +++ b/tests/ui/lifetimes/noisy-follow-up-erro.stderr @@ -15,11 +15,14 @@ LL | struct Foo<'c, 'd>(&'c (), &'d ()); error[E0621]: explicit lifetime required in the type of `foo` --> $DIR/noisy-follow-up-erro.rs:14:9 | -LL | fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> { - | -------------------- help: add explicit lifetime `'a` to the type of `foo`: `&mut Foo<'_, 'a>` -LL | LL | self.bar().map_err(|()| foo.acc(self))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `foo` + | +LL - fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> { +LL + fn boom(&self, foo: &mut Foo<'_, 'a>) -> Result<(), &'a ()> { + | error: aborting due to 2 previous errors diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 15b36925c47b5..05eb611081a41 100644 --- a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -21,11 +21,13 @@ LL | ss.r error[E0621]: explicit lifetime required in the type of `ss` --> $DIR/object-lifetime-default-from-box-error.rs:33:5 | -LL | fn store1<'b>(ss: &mut SomeStruct, b: Box) { - | --------------- help: add explicit lifetime `'b` to the type of `ss`: `&mut SomeStruct<'b>` -... LL | ss.r = b; | ^^^^ lifetime `'b` required + | +help: add explicit lifetime `'b` to the type of `ss` + | +LL | fn store1<'b>(ss: &mut SomeStruct<'b>, b: Box) { + | ++++ error: aborting due to 3 previous errors diff --git a/tests/ui/regions/regions-glb-free-free.stderr b/tests/ui/regions/regions-glb-free-free.stderr index 727669f26835e..6ea09e3e1d76d 100644 --- a/tests/ui/regions/regions-glb-free-free.stderr +++ b/tests/ui/regions/regions-glb-free-free.stderr @@ -1,8 +1,6 @@ error[E0621]: explicit lifetime required in the type of `s` --> $DIR/regions-glb-free-free.rs:15:13 | -LL | pub fn set_desc(self, s: &str) -> Flag<'a> { - | ---- help: add explicit lifetime `'a` to the type of `s`: `&'a str` LL | / Flag { LL | | name: self.name, LL | | desc: s, @@ -10,6 +8,11 @@ LL | | max_count: self.max_count, LL | | value: self.value LL | | } | |_____________^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `s` + | +LL | pub fn set_desc(self, s: &'a str) -> Flag<'a> { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/regions/regions-infer-at-fn-not-param.stderr b/tests/ui/regions/regions-infer-at-fn-not-param.stderr index 4c7660276f2dd..58ff2586a82c1 100644 --- a/tests/ui/regions/regions-infer-at-fn-not-param.stderr +++ b/tests/ui/regions/regions-infer-at-fn-not-param.stderr @@ -2,9 +2,12 @@ error[E0621]: explicit lifetime required in the type of `p` --> $DIR/regions-infer-at-fn-not-param.rs:13:57 | LL | fn take1<'a>(p: Parameterized1) -> Parameterized1<'a> { p } - | -------------- ^ lifetime `'a` required - | | - | help: add explicit lifetime `'a` to the type of `p`: `Parameterized1<'a>` + | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `p` + | +LL | fn take1<'a>(p: Parameterized1<'a>) -> Parameterized1<'a> { p } + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 41cb2ee46bb5a..0aa33d3b6fb17 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -101,15 +101,17 @@ LL + fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + 'b error[E0621]: explicit lifetime required in the type of `dest` --> $DIR/missing-lifetimes-in-signature.rs:73:5 | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` -... LL | / move || { LL | | LL | | LL | | *dest = g.get(); LL | | } | |_____^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `dest` + | +LL | fn bat<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a + | ++ error[E0309]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:85:5 diff --git a/tests/ui/variance/variance-trait-matching.stderr b/tests/ui/variance/variance-trait-matching.stderr index 9c72fe239dde9..495669668c552 100644 --- a/tests/ui/variance/variance-trait-matching.stderr +++ b/tests/ui/variance/variance-trait-matching.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `get` --> $DIR/variance-trait-matching.rs:24:5 | -LL | fn get<'a, G>(get: &G) -> i32 - | -- help: add explicit lifetime `'a` to the type of `get`: `&'a G` -... LL | pick(get, &22) | ^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `get` + | +LL | fn get<'a, G>(get: &'a G) -> i32 + | ++ error: aborting due to 1 previous error From 1b9d7eab7af9567e9d4289586be4c15da7f56ec9 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Mon, 9 Jun 2025 20:03:21 +0000 Subject: [PATCH 21/27] Mark `core::slice::memchr` as `#[doc(hidden)]` It's purely internal, and not intended to be a public API, even on nightly. This stops it showing up and being misleading in rustdoc search. It also mirrors the (also internal) `core::slice::sort` module. --- library/core/src/slice/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 4f7e144088045..c26bbad087a2d 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -21,6 +21,7 @@ use crate::{fmt, hint, ptr, range, slice}; issue = "none", reason = "exposed from core to be reused in std; use the memchr crate" )] +#[doc(hidden)] /// Pure Rust memchr implementation, taken from rust-memchr pub mod memchr; From fea6a2289bd3412da1f61ded1f3825c10a361b53 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 17 Dec 2024 15:42:39 -0600 Subject: [PATCH 22/27] Specify the behavior of `file!` This takes the current behavior of `file!` and documents it so it is safe to make assumptions about. For example, Cargo could provide a `CARGO_RUSTC_CURRENT_DIR` as a base path for `file!`. Example use cases - Being able to look up test assets relative to the current file ([example](https://github.com/rust-lang/cargo/blob/b9026bf654d7fac283465e58b8b76742244ef07d/tests/testsuite/cargo_add/add_basic/mod.rs#L34)) - Inline snapshotting libraries being able to update Rust source code ([example](https://github.com/rust-lang/cargo/blob/b9026bf654d7fac283465e58b8b76742244ef07d/tests/testsuite/alt_registry.rs#L36-L45)) T-libs-api discussed two solutions - `file_absolute!`: - Has less meaning in other build tools like buck2 - Bakes in the assumption that a full path is available (e.g. with trim-paths) - Specifying `file!`s behavior (this PR): - Leaves it to the user to deal with trim-paths - Even though `file!` is currently unspecified, changing it would likely have too large of an impact on the ecosystem at this time. A future possibility is that rustc could have a flag that controls modifies the base path used for `file!`. That seems purely additive with specifying the behavior and we do not want to block on it. It would also likely be too disruptive for Cargo users (as mentioned). However, we tried to keep this in mind when specifying the behavior. --- library/core/src/macros/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index d5efb03cfbcbf..b21845a1c169c 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1273,6 +1273,19 @@ pub(crate) mod builtin { /// first macro invocation leading up to the invocation of the `file!` /// macro. /// + /// The file name is derived from the crate root's source path passed to the Rust compiler + /// and the sequence the compiler takes to get from the crate root to the + /// module containing `file!`, modified by any flags passed to the Rust compiler (e.g. + /// `--remap-path-prefix`). If the crate's source path is relative, the initial base + /// directory will be the working directory of the Rust compiler. For example, if the source + /// path passed to the compiler is `./src/lib.rs` which has a `mod foo;` with a source path of + /// `src/foo/mod.rs`, then calling `file!` inside `mod foo;` will return `./src/foo/mod.rs`. + /// + /// Future compiler options might make further changes to the behavior of `file!`, + /// including potentially making it entirely empty. Code (e.g. test libraries) + /// relying on `file!` producing an openable file path would be incompatible + /// with such options, and might wish to recommend not using those options. + /// /// # Examples /// /// ``` From 643a9d233b4f1547220134daea4bcca809302d40 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 6 Jun 2025 15:19:08 -0700 Subject: [PATCH 23/27] tests: Change "fastcall" to "system" in some tests Lets the test still work on different architectures. --- tests/debuginfo/type-names.rs | 4 ++-- tests/incremental/hashes/trait_defs.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/debuginfo/type-names.rs b/tests/debuginfo/type-names.rs index 3c7eab7e8d718..ac61fef48fe16 100644 --- a/tests/debuginfo/type-names.rs +++ b/tests/debuginfo/type-names.rs @@ -19,7 +19,7 @@ // gdb-check:type = type_names::GenericStruct // gdb-command:whatis generic_struct2 -// gdb-check:type = type_names::GenericStruct usize> +// gdb-check:type = type_names::GenericStruct usize> // gdb-command:whatis mod_struct // gdb-check:type = type_names::mod1::Struct2 @@ -379,7 +379,7 @@ fn main() { let simple_struct = Struct1; let generic_struct1: GenericStruct = GenericStruct(PhantomData); - let generic_struct2: GenericStruct usize> = + let generic_struct2: GenericStruct usize> = GenericStruct(PhantomData); let mod_struct = mod1::Struct2; diff --git a/tests/incremental/hashes/trait_defs.rs b/tests/incremental/hashes/trait_defs.rs index cb8716d90b07f..7141ddb0d7ed8 100644 --- a/tests/incremental/hashes/trait_defs.rs +++ b/tests/incremental/hashes/trait_defs.rs @@ -440,7 +440,7 @@ trait TraitAddExternModifier { // Change extern "C" to extern "stdcall" #[cfg(any(cfail1,cfail4))] -trait TraitChangeExternCToRustIntrinsic { +trait TraitChangeExternCToExternSystem { // -------------------------------------------------------------- // ------------------------- // -------------------------------------------------------------- @@ -458,7 +458,7 @@ trait TraitChangeExternCToRustIntrinsic { #[rustc_clean(cfg="cfail3")] #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] - extern "stdcall" fn method(); + extern "system" fn method(); } From 518eb0d5dd9ba822795fc5bc8e434e7139b0acbd Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 2 Jun 2025 07:20:42 -0700 Subject: [PATCH 24/27] rustdoc-json: Rearrange deck chairs in ABI testing We move the vectorcall ABI tests into their own file which is now only run on x86-64, while replacing them with rust-cold ABI tests so that aarch64 hosts continue to test an unstable ABI. A better solution might be cross-compiling or something but I really don't have time for that right now. --- tests/rustdoc-json/fn_pointer/abi.rs | 9 +++------ tests/rustdoc-json/fns/abi.rs | 9 +++------ tests/rustdoc-json/methods/abi.rs | 17 +++++------------ tests/rustdoc-json/vectorcall.rs | 27 +++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 tests/rustdoc-json/vectorcall.rs diff --git a/tests/rustdoc-json/fn_pointer/abi.rs b/tests/rustdoc-json/fn_pointer/abi.rs index 34150c0fe89e0..ec76e0f66362a 100644 --- a/tests/rustdoc-json/fn_pointer/abi.rs +++ b/tests/rustdoc-json/fn_pointer/abi.rs @@ -1,4 +1,4 @@ -#![feature(abi_vectorcall)] +#![feature(rust_cold_cc)] //@ is "$.index[?(@.name=='AbiRust')].inner.type_alias.type.function_pointer.header.abi" \"Rust\" pub type AbiRust = fn(); @@ -15,8 +15,5 @@ pub type AbiCUnwind = extern "C-unwind" fn(); //@ is "$.index[?(@.name=='AbiSystemUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": true}}' pub type AbiSystemUnwind = extern "system-unwind" fn(); -//@ is "$.index[?(@.name=='AbiVecorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""' -pub type AbiVecorcall = extern "vectorcall" fn(); - -//@ is "$.index[?(@.name=='AbiVecorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""' -pub type AbiVecorcallUnwind = extern "vectorcall-unwind" fn(); +//@ is "$.index[?(@.name=='AbiRustCold')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"rust-cold\""' +pub type AbiRustCold = extern "rust-cold" fn(); diff --git a/tests/rustdoc-json/fns/abi.rs b/tests/rustdoc-json/fns/abi.rs index 7277bb1f59a40..3373d135c89d6 100644 --- a/tests/rustdoc-json/fns/abi.rs +++ b/tests/rustdoc-json/fns/abi.rs @@ -1,4 +1,4 @@ -#![feature(abi_vectorcall)] +#![feature(rust_cold_cc)] //@ is "$.index[?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" pub fn abi_rust() {} @@ -15,8 +15,5 @@ pub extern "C-unwind" fn abi_c_unwind() {} //@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} -//@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' -pub extern "vectorcall" fn abi_vectorcall() {} - -//@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' -pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} +//@ is "$.index[?(@.name=='abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""' +pub extern "rust-cold" fn abi_rust_cold() {} diff --git a/tests/rustdoc-json/methods/abi.rs b/tests/rustdoc-json/methods/abi.rs index fa2387ddf67a8..be6a11784f55d 100644 --- a/tests/rustdoc-json/methods/abi.rs +++ b/tests/rustdoc-json/methods/abi.rs @@ -1,5 +1,4 @@ -#![feature(abi_vectorcall)] - +#![feature(rust_cold_cc)] //@ has "$.index[?(@.name=='Foo')]" pub struct Foo; @@ -19,11 +18,8 @@ impl Foo { //@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} - //@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' - pub extern "vectorcall" fn abi_vectorcall() {} - - //@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' - pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} + //@ is "$.index[?(@.name=='abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""' + pub extern "rust-cold" fn abi_rust_cold() {} } pub trait Bar { @@ -42,9 +38,6 @@ pub trait Bar { //@ is "$.index[?(@.name=='trait_abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' extern "system-unwind" fn trait_abi_system_unwind() {} - //@ is "$.index[?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' - extern "vectorcall" fn trait_abi_vectorcall() {} - - //@ is "$.index[?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' - extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {} + //@ is "$.index[?(@.name=='trait_abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""' + extern "rust-cold" fn trait_abi_rust_cold() {} } diff --git a/tests/rustdoc-json/vectorcall.rs b/tests/rustdoc-json/vectorcall.rs new file mode 100644 index 0000000000000..19cac244f422f --- /dev/null +++ b/tests/rustdoc-json/vectorcall.rs @@ -0,0 +1,27 @@ +#![feature(abi_vectorcall)] +//@ only-x86_64 + +//@ is "$.index[?(@.name=='AbiVectorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""' +pub type AbiVectorcall = extern "vectorcall" fn(); + +//@ is "$.index[?(@.name=='AbiVectorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""' +pub type AbiVectorcallUnwind = extern "vectorcall-unwind" fn(); + +//@ has "$.index[?(@.name=='Foo')]" +pub struct Foo; + +impl Foo { + //@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' + pub extern "vectorcall" fn abi_vectorcall() {} + + //@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' + pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} +} + +pub trait Bar { + //@ is "$.index[?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' + extern "vectorcall" fn trait_abi_vectorcall() {} + + //@ is "$.index[?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' + extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {} +} From 856c9971fd374afef057257f086814997c72a9b3 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Tue, 10 Jun 2025 00:39:07 +0000 Subject: [PATCH 25/27] rustdoc: Refractor `clean_ty_generics` --- src/librustdoc/clean/auto_trait.rs | 4 +- src/librustdoc/clean/blanket_impl.rs | 6 +-- src/librustdoc/clean/inline.rs | 69 ++++------------------------ src/librustdoc/clean/mod.rs | 14 +++--- 4 files changed, 19 insertions(+), 74 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 138ac3c97f7b6..a91ea55bcae68 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -11,7 +11,7 @@ use tracing::{debug, instrument}; use crate::clean::{ self, Lifetime, clean_generic_param_def, clean_middle_ty, clean_predicate, - clean_trait_ref_with_constraints, clean_ty_generics, simplify, + clean_trait_ref_with_constraints, clean_ty_generics_inner, simplify, }; use crate::core::DocContext; @@ -101,7 +101,7 @@ fn synthesize_auto_trait_impl<'tcx>( // Instead, we generate `impl !Send for Foo`, which better // expresses the fact that `Foo` never implements `Send`, // regardless of the choice of `T`. - let mut generics = clean_ty_generics( + let mut generics = clean_ty_generics_inner( cx, tcx.generics_of(item_def_id), ty::GenericPredicates::default(), diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 89245fee51551..c889f52b789a4 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -90,11 +90,7 @@ pub(crate) fn synthesize_blanket_impls( stability: None, kind: clean::ImplItem(Box::new(clean::Impl { safety: hir::Safety::Safe, - generics: clean_ty_generics( - cx, - tcx.generics_of(impl_def_id), - tcx.explicit_predicates_of(impl_def_id), - ), + generics: clean_ty_generics(cx, impl_def_id), // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. trait_: Some(clean_trait_ref_with_constraints( diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 55a116a018a8a..9b5491310b422 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -264,16 +264,13 @@ pub(crate) fn build_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait { .map(|item| clean_middle_assoc_item(item, cx)) .collect(); - let predicates = cx.tcx.predicates_of(did); - let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); - let generics = filter_non_trait_generics(did, generics); + let generics = clean_ty_generics(cx, did); let (generics, supertrait_bounds) = separate_self_bounds(generics); clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds } } fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias { - let predicates = cx.tcx.predicates_of(did); - let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); + let generics = clean_ty_generics(cx, did); let (generics, bounds) = separate_self_bounds(generics); clean::TraitAlias { generics, bounds } } @@ -281,8 +278,7 @@ fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias { pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box { let sig = cx.tcx.fn_sig(def_id).instantiate_identity(); // The generics need to be cleaned before the signature. - let mut generics = - clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)); + let mut generics = clean_ty_generics(cx, def_id); let bound_vars = clean_bound_vars(sig.bound_vars()); // At the time of writing early & late-bound params are stored separately in rustc, @@ -311,30 +307,26 @@ pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box, did: DefId) -> clean::Enum { - let predicates = cx.tcx.explicit_predicates_of(did); - clean::Enum { - generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), + generics: clean_ty_generics(cx, did), variants: cx.tcx.adt_def(did).variants().iter().map(|v| clean_variant_def(v, cx)).collect(), } } fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct { - let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Struct { ctor_kind: variant.ctor_kind(), - generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), + generics: clean_ty_generics(cx, did), fields: variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(), } } fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { - let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); - let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); + let generics = clean_ty_generics(cx, did); let fields = variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(); clean::Union { generics, fields } } @@ -344,14 +336,13 @@ fn build_type_alias( did: DefId, ret: &mut Vec, ) -> Box { - let predicates = cx.tcx.explicit_predicates_of(did); let ty = cx.tcx.type_of(did).instantiate_identity(); let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None); let inner_type = clean_ty_alias_inner_type(ty, cx, ret); Box::new(clean::TypeAlias { type_, - generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), + generics: clean_ty_generics(cx, did), inner_type, item_type: None, }) @@ -483,7 +474,6 @@ pub(crate) fn build_impl( } let document_hidden = cx.render_options.document_hidden; - let predicates = tcx.explicit_predicates_of(did); let (trait_items, generics) = match impl_item { Some(impl_) => ( impl_ @@ -549,9 +539,7 @@ pub(crate) fn build_impl( }) .map(|item| clean_middle_assoc_item(item, cx)) .collect::>(), - clean::enter_impl_trait(cx, |cx| { - clean_ty_generics(cx, tcx.generics_of(did), predicates) - }), + clean::enter_impl_trait(cx, |cx| clean_ty_generics(cx, did)), ), }; let polarity = tcx.impl_polarity(did); @@ -713,8 +701,7 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { } fn build_const_item(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { - let mut generics = - clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)); + let mut generics = clean_ty_generics(cx, def_id); clean::simplify::move_bounds_to_generic_parameters(&mut generics); let ty = clean_middle_ty( ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()), @@ -761,44 +748,6 @@ fn build_macro( } } -/// A trait's generics clause actually contains all of the predicates for all of -/// its associated types as well. We specifically move these clauses to the -/// associated types instead when displaying, so when we're generating the -/// generics for the trait itself we need to be sure to remove them. -/// We also need to remove the implied "recursive" Self: Trait bound. -/// -/// The inverse of this filtering logic can be found in the `Clean` -/// implementation for `AssociatedType` -fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics { - for pred in &mut g.where_predicates { - if let clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } = - *pred - { - bounds.retain(|bound| match bound { - clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => { - trait_.def_id() != trait_did - } - _ => true, - }); - } - } - - g.where_predicates.retain(|pred| match pred { - clean::WherePredicate::BoundPredicate { - ty: - clean::QPath(box clean::QPathData { - self_type: clean::Generic(_), - trait_: Some(trait_), - .. - }), - bounds, - .. - } => !bounds.is_empty() && trait_.def_id() != trait_did, - _ => true, - }); - g -} - fn separate_self_bounds(mut g: clean::Generics) -> (clean::Generics, Vec) { let mut ty_bounds = Vec::new(); g.where_predicates.retain(|pred| match *pred { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7658e7ad35f3a..db4bcdaeb6c1a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -793,7 +793,11 @@ pub(crate) fn clean_generics<'tcx>( } } -fn clean_ty_generics<'tcx>( +fn clean_ty_generics<'tcx>(cx: &mut DocContext<'tcx>, def_id: DefId) -> Generics { + clean_ty_generics_inner(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)) +} + +fn clean_ty_generics_inner<'tcx>( cx: &mut DocContext<'tcx>, gens: &ty::Generics, preds: ty::GenericPredicates<'tcx>, @@ -1297,11 +1301,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo None, ); - let mut generics = clean_ty_generics( - cx, - tcx.generics_of(assoc_item.def_id), - tcx.explicit_predicates_of(assoc_item.def_id), - ); + let mut generics = clean_ty_generics(cx, assoc_item.def_id); simplify::move_bounds_to_generic_parameters(&mut generics); match assoc_item.container { @@ -1389,7 +1389,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo let bounds = tcx.explicit_item_bounds(assoc_item.def_id).iter_identity_copied(); predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); } - let mut generics = clean_ty_generics( + let mut generics = clean_ty_generics_inner( cx, tcx.generics_of(assoc_item.def_id), ty::GenericPredicates { parent: None, predicates }, From 59069986e7446123556630a32adce7f101eeaf8d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 7 Jun 2025 11:04:40 -0700 Subject: [PATCH 26/27] tests: Copy dont-shuffle-bswaps per tested opt level --- .../autovec/dont-shuffle-bswaps-opt2.rs | 29 +++++++++++++++++++ .../dont-shuffle-bswaps-opt3.rs} | 3 +- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs rename tests/codegen/{dont-shuffle-bswaps.rs => autovec/dont-shuffle-bswaps-opt3.rs} (94%) diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs new file mode 100644 index 0000000000000..391cf1c639ca3 --- /dev/null +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs @@ -0,0 +1,29 @@ +//@ compile-flags: -Copt-level=2 + +#![crate_type = "lib"] +#![no_std] + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. + +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector +#[no_mangle] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + #[cfg(target_endian = "little")] + let bswap = u16::to_be; + #[cfg(target_endian = "big")] + let bswap = u16::to_le; + let addr16 = [ + bswap(value[0]), + bswap(value[1]), + bswap(value[2]), + bswap(value[3]), + bswap(value[4]), + bswap(value[5]), + bswap(value[6]), + bswap(value[7]), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +} diff --git a/tests/codegen/dont-shuffle-bswaps.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs similarity index 94% rename from tests/codegen/dont-shuffle-bswaps.rs rename to tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs index c1dab2bc29536..e105487cccab2 100644 --- a/tests/codegen/dont-shuffle-bswaps.rs +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs @@ -1,5 +1,4 @@ -//@ revisions: OPT2 OPT3 OPT3_S390X -//@[OPT2] compile-flags: -Copt-level=2 +//@ revisions: OPT3 OPT3_S390X //@[OPT3] compile-flags: -C opt-level=3 // some targets don't do the opt we are looking for //@[OPT3] only-64bit From c7fd742f72b6b2552c18b2cc632bacfa478baee0 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 7 Jun 2025 11:12:38 -0700 Subject: [PATCH 27/27] tests: Revise dont-shuffle-bswaps-opt3 per tested arch Some architectures gain target-cpu minimums in doing so. --- .../autovec/dont-shuffle-bswaps-opt2.rs | 2 ++ .../autovec/dont-shuffle-bswaps-opt3.rs | 29 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs index 391cf1c639ca3..c354228acc50a 100644 --- a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs @@ -3,6 +3,8 @@ #![crate_type = "lib"] #![no_std] +// This test is paired with the arch-specific -opt3.rs test. + // The code is from https://github.com/rust-lang/rust/issues/122805. // Ensure we do not generate the shufflevector instruction // to avoid complicating the code. diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs index e105487cccab2..4d585314b9385 100644 --- a/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs @@ -1,28 +1,27 @@ -//@ revisions: OPT3 OPT3_S390X -//@[OPT3] compile-flags: -C opt-level=3 -// some targets don't do the opt we are looking for -//@[OPT3] only-64bit -//@[OPT3] ignore-s390x -//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13 -//@[OPT3_S390X] only-s390x +//@ revisions: AARCH64 POWER9 X86_64 Z13 +//@ compile-flags: -Copt-level=3 +//@[AARCH64] only-aarch64 +//@[X86_64] only-x86_64 +//@[Z13] only-s390x +//@[Z13] compile-flags: -Ctarget-cpu=z13 #![crate_type = "lib"] #![no_std] +// This test is paired with the arch-neutral -opt2.rs test + // The code is from https://github.com/rust-lang/rust/issues/122805. // Ensure we do not generate the shufflevector instruction // to avoid complicating the code. + // CHECK-LABEL: define{{.*}}void @convert( // CHECK-NOT: shufflevector + // On higher opt levels, this should just be a bswap: -// OPT3: load <8 x i16> -// OPT3-NEXT: call <8 x i16> @llvm.bswap -// OPT3-NEXT: store <8 x i16> -// OPT3-NEXT: ret void -// OPT3_S390X: load <8 x i16> -// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap -// OPT3_S390X-NEXT: store <8 x i16> -// OPT3_S390X-NEXT: ret void +// CHECK: load <8 x i16> +// CHECK-NEXT: call <8 x i16> @llvm.bswap +// CHECK-NEXT: store <8 x i16> +// CHECK-NEXT: ret void #[no_mangle] pub fn convert(value: [u16; 8]) -> [u8; 16] { #[cfg(target_endian = "little")]