From 54ee0eec44b99d32ad4c7aa164d3aaa3748c472b Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 13 May 2026 14:11:04 +0800 Subject: [PATCH 01/11] Force copy `rustc-dev` artifacts for rustfmt/clippy under download-rustc `compile::Rustc`'s sysroot copying logic intentionally does not implicitly copy `rustc-dev` artifacts unless explicitly requested through `builder.ensure(compile::Rustc)`, due to a previous issue RUST-108767: ```text // NOTE(#108767): We intentionally don't copy `rustc-dev` artifacts until they're // requested with `builder.ensure(Rustc)`. This fixes an issue where we'd have multiple // copies of libc in the sysroot with no way to tell which to load. There are a few // quirks of bootstrap that interact to make this reliable: // 1. The order `Step`s are run is hard-coded in `builder.rs` and not configurable. This // avoids e.g. reordering `test::UiFulldeps` before `test::Ui` and causing the latter // to fail because of duplicate metadata. // 2. The sysroot is deleted and recreated between each invocation, so running `x test // ui-fulldeps && x test ui` can't cause failures. ``` So, for rustfmt/clippy, we insert intentionally explicit `builder.ensure(compile::Rustc)` as a short-term band-aid, leaving FIXMEs pointing to RUST-156525 to investigate if the multiple libc copies is still a problem and if that can be fixed properly. This is by no means a proper fix, but it should unblock local tool profile workflows trying to use `download-rustc` with {rustfmt,clippy}. --- src/bootstrap/src/core/build_steps/compile.rs | 14 +++++++++----- src/bootstrap/src/core/build_steps/test.rs | 10 ++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 68a4f928464f1..3b497e1db923c 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1999,12 +1999,16 @@ impl Step for Sysroot { } // Copy the compiler into the correct sysroot. - // NOTE(#108767): We intentionally don't copy `rustc-dev` artifacts until they're requested with `builder.ensure(Rustc)`. - // This fixes an issue where we'd have multiple copies of libc in the sysroot with no way to tell which to load. - // There are a few quirks of bootstrap that interact to make this reliable: + // + // FIXME(#156525): investigate if this is still needed. + // + // NOTE(#108767): We intentionally don't copy `rustc-dev` artifacts until they're + // requested with `builder.ensure(Rustc)`. This fixes an issue where we'd have multiple + // copies of libc in the sysroot with no way to tell which to load. There are a few + // quirks of bootstrap that interact to make this reliable: // 1. The order `Step`s are run is hard-coded in `builder.rs` and not configurable. This - // avoids e.g. reordering `test::UiFulldeps` before `test::Ui` and causing the latter to - // fail because of duplicate metadata. + // avoids e.g. reordering `test::UiFulldeps` before `test::Ui` and causing the latter + // to fail because of duplicate metadata. // 2. The sysroot is deleted and recreated between each invocation, so running `x test // ui-fulldeps && x test ui` can't cause failures. let mut filtered_files = Vec::new(); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index c28fe4ad832d3..fb45fcf5dcc42 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -579,6 +579,11 @@ impl Step for Rustfmt { let build_compiler = self.compilers.build_compiler(); let target = self.compilers.target(); + // FIXME(#156525): `compile::Sysroot::run` intentionally do not copy `rustc-dev` artifacts + // until they're requested with `builder.ensure(Rustc)`, relevant for `download-rustc` + // flows. + builder.ensure(compile::Rustc::new(build_compiler, target)); + let mut cargo = tool::prepare_tool_cargo( builder, build_compiler, @@ -941,6 +946,11 @@ impl Step for Clippy { let target_compiler = self.compilers.target_compiler(); let build_compiler = self.compilers.build_compiler(); + // FIXME(#156525): `compile::Sysroot::run` intentionally do not copy `rustc-dev` artifacts + // until they're requested with `builder.ensure(Rustc)`, relevant for `download-rustc` + // flows. + builder.ensure(compile::Rustc::new(build_compiler, target)); + let mut cargo = tool::prepare_tool_cargo( builder, build_compiler, From 9e3e1ca9abbeb3bc46f132a90ee307c9705ae213 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 24 May 2026 14:23:13 +0200 Subject: [PATCH 02/11] Rename a confusing local --- src/bootstrap/src/core/build_steps/run.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 2329bb93b4d3d..935844daa9d7c 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -510,7 +510,7 @@ impl Step for Rustfmt { let compilers = RustcPrivateCompilers::new(builder, stage, host); let rustfmt_build = builder.ensure(tool::Rustfmt::from_compilers(compilers)); - let mut rustfmt = tool::prepare_tool_cargo( + let mut cargo = tool::prepare_tool_cargo( builder, rustfmt_build.build_compiler, Mode::ToolRustcPrivate, @@ -521,10 +521,10 @@ impl Step for Rustfmt { &[], ); - rustfmt.args(["--bin", "rustfmt", "--"]); - rustfmt.args(builder.config.args()); + cargo.args(["--bin", "rustfmt", "--"]); + cargo.args(builder.config.args()); - rustfmt.into_cmd().run(builder); + cargo.into_cmd().run(builder); } } From 71487e8d2199a765b7460c6bfc5ffe41b59f57a8 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 24 May 2026 14:23:53 +0200 Subject: [PATCH 03/11] Explicitly add rustc libs to path for `RustcPrivate` tools Centrally in `tool::prepare_tool_cargo`. So that `./x run rustfmt` + `download-rustc` can find the correct rustc libs. --- src/bootstrap/src/core/build_steps/tool.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index ed5c2586a5ed6..a75d5e4db8998 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -224,6 +224,12 @@ pub fn prepare_tool_cargo( // avoid rebuilding when running tests. cargo.env("SYSROOT", builder.sysroot(compiler)); + // Make sure we explicitly add rustc_private libs to path centrally here so that + // RustcPrivate tools can pick them up. + if mode == Mode::ToolRustcPrivate { + cargo.add_rustc_lib_path(builder); + } + // if tools are using lzma we want to force the build script to build its // own copy cargo.env("LZMA_API_STATIC", "1"); From fed6279325de02dfa753b9e9a6d968f5a4ef428f Mon Sep 17 00:00:00 2001 From: Hanna Kruppe Date: Fri, 22 May 2026 14:45:46 +0200 Subject: [PATCH 04/11] library: use strict provenance lints consistently The `fuzzy_provenance_casts` lint is enabled in most of the standard library, but its identical twin `lossy_provenance_casts` was not. As discussed in the tracking issue for those lints, there doesn't seem to be any good reason to enable one without the other. This PR applies this principle and as a result removes some unnecessary ptr->int `as` casts. It's also preparation for merging the two lints, which removes the option of only enabling `fuzzy_provenance_casts`. --- library/alloc/src/lib.rs | 1 + library/alloctests/benches/lib.rs | 1 + library/alloctests/tests/boxed.rs | 4 ++-- library/alloctests/tests/heap.rs | 2 +- library/alloctests/tests/lib.rs | 1 + library/alloctests/tests/sort/tests.rs | 2 +- library/alloctests/tests/vec.rs | 8 ++++---- library/core/src/lib.rs | 1 + library/core/src/ptr/const_ptr.rs | 1 + library/core/src/ptr/mod.rs | 6 +++--- library/core/src/ptr/mut_ptr.rs | 1 + library/coretests/tests/char.rs | 4 ++-- library/coretests/tests/lib.rs | 1 + library/coretests/tests/ptr.rs | 2 +- library/coretests/tests/slice.rs | 2 +- library/coretests/tests/waker.rs | 6 +++--- library/std/src/lib.rs | 9 ++++++++- library/std/src/sync/mpmc/select.rs | 2 +- library/std/src/sync/mpmc/zero.rs | 2 +- library/std/src/sys/args/sgx.rs | 3 ++- library/std/src/sys/env/sgx.rs | 3 ++- library/std/src/sys/pal/sgx/mod.rs | 3 ++- library/std/src/sys/thread_local/key/tests.rs | 4 ++-- library/std/src/thread/tests.rs | 6 +++--- 24 files changed, 46 insertions(+), 29 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 5fe5464ab2cdd..e93c1336a7b53 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -73,6 +73,7 @@ // Lints: #![deny(unsafe_op_in_unsafe_fn)] #![deny(fuzzy_provenance_casts)] +#![deny(lossy_provenance_casts)] #![warn(deprecated_in_future)] #![warn(missing_debug_implementations)] #![warn(missing_docs)] diff --git a/library/alloctests/benches/lib.rs b/library/alloctests/benches/lib.rs index b7e09fc2e162b..2be7a24d2de7b 100644 --- a/library/alloctests/benches/lib.rs +++ b/library/alloctests/benches/lib.rs @@ -7,6 +7,7 @@ #![feature(strict_provenance_lints)] #![feature(test)] #![deny(fuzzy_provenance_casts)] +#![deny(lossy_provenance_casts)] extern crate test; diff --git a/library/alloctests/tests/boxed.rs b/library/alloctests/tests/boxed.rs index 83fd1ef7449a3..41722155f864b 100644 --- a/library/alloctests/tests/boxed.rs +++ b/library/alloctests/tests/boxed.rs @@ -47,9 +47,9 @@ fn box_clone_from_ptr_stability() { for size in (0..8).map(|i| 2usize.pow(i)) { let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); - let copy_raw = copy.as_ptr() as usize; + let copy_raw = copy.as_ptr(); copy.clone_from(&control); - assert_eq!(copy.as_ptr() as usize, copy_raw); + assert_eq!(copy.as_ptr(), copy_raw); } } diff --git a/library/alloctests/tests/heap.rs b/library/alloctests/tests/heap.rs index 246b341eeb387..8eb562622c0a4 100644 --- a/library/alloctests/tests/heap.rs +++ b/library/alloctests/tests/heap.rs @@ -25,7 +25,7 @@ fn check_overalign_requests(allocator: T) { .collect(); for &ptr in &pointers { assert_eq!( - (ptr.as_non_null_ptr().as_ptr() as usize) % align, + ptr.as_non_null_ptr().as_ptr().addr() % align, 0, "Got a pointer less aligned than requested" ) diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 699a5010282b0..01dd7a6e3f48d 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -43,6 +43,7 @@ #![feature(vec_try_remove)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] +#![deny(lossy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] extern crate alloc; diff --git a/library/alloctests/tests/sort/tests.rs b/library/alloctests/tests/sort/tests.rs index 09b76773d6b24..ec4c4fa619ddf 100644 --- a/library/alloctests/tests/sort/tests.rs +++ b/library/alloctests/tests/sort/tests.rs @@ -746,7 +746,7 @@ fn self_cmp( pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::>(); let comparison_fn = |a: &T, b: &T| { - assert_ne!(a as *const T as usize, b as *const T as usize); + assert_ne!(a as *const T, b as *const T); a.cmp(b) }; diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index d85d2e44cd2ba..7ae8c80963319 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -1110,7 +1110,7 @@ fn test_into_iter_zst() { struct AlignedZstWithDrop([u64; 0]); impl Drop for AlignedZstWithDrop { fn drop(&mut self) { - let addr = self as *mut _ as usize; + let addr = (self as *mut Self).addr(); assert!(hint::black_box(addr) % align_of::() == 0); } } @@ -1356,10 +1356,10 @@ fn overaligned_allocations() { for i in 0..0x1000 { v.reserve_exact(i); assert!(v[0].0 == 273); - assert!(v.as_ptr() as usize & 0xff == 0); + assert!(v.as_ptr().addr() & 0xff == 0); v.shrink_to_fit(); assert!(v[0].0 == 273); - assert!(v.as_ptr() as usize & 0xff == 0); + assert!(v.as_ptr().addr() & 0xff == 0); } } @@ -2574,7 +2574,7 @@ fn test_box_zero_allocator() { unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { if layout.size() == 0 { - let addr = ptr.as_ptr() as usize; + let addr = ptr.as_ptr().addr(); let mut state = self.state.borrow_mut(); std::println!("freeing {addr}"); assert!(state.0.remove(&addr), "ZST free that wasn't allocated"); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index acc758a75e77b..9d9837c846de3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -80,6 +80,7 @@ #![deny(rust_2021_incompatible_or_patterns)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(fuzzy_provenance_casts)] +#![deny(lossy_provenance_casts)] #![warn(deprecated_in_future)] #![warn(missing_debug_implementations)] #![warn(missing_docs)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 8b7b08bf82317..8504d9b5e217d 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -183,6 +183,7 @@ impl *const T { /// [`with_exposed_provenance`]: with_exposed_provenance #[inline(always)] #[stable(feature = "exposed_provenance", since = "1.84.0")] + #[expect(lossy_provenance_casts, reason = "this *is* the replacement")] pub fn expose_provenance(self) -> usize { self.cast::<()>() as usize } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 15fc36332baca..89a054b7272d8 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2588,21 +2588,21 @@ impl Ord for F { #[stable(feature = "fnptr_impls", since = "1.4.0")] impl hash::Hash for F { fn hash(&self, state: &mut HH) { - state.write_usize(self.addr() as _) + state.write_usize(self.addr().addr()) } } #[stable(feature = "fnptr_impls", since = "1.4.0")] impl fmt::Pointer for F { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::pointer_fmt_inner(self.addr() as _, f) + fmt::pointer_fmt_inner(self.addr().addr(), f) } } #[stable(feature = "fnptr_impls", since = "1.4.0")] impl fmt::Debug for F { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::pointer_fmt_inner(self.addr() as _, f) + fmt::pointer_fmt_inner(self.addr().addr(), f) } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 98b70a77fad7b..b9a1381c4ed8f 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -174,6 +174,7 @@ impl *mut T { /// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut #[inline(always)] #[stable(feature = "exposed_provenance", since = "1.84.0")] + #[expect(lossy_provenance_casts, reason = "this *is* the replacement")] pub fn expose_provenance(self) -> usize { self.cast::<()>() as usize } diff --git a/library/coretests/tests/char.rs b/library/coretests/tests/char.rs index 877017f682c97..43372005ad5f3 100644 --- a/library/coretests/tests/char.rs +++ b/library/coretests/tests/char.rs @@ -318,7 +318,7 @@ fn test_encode_utf8() { let mut buf = [0; char::MAX_LEN_UTF8]; let ptr = buf.as_ptr(); let s = input.encode_utf8(&mut buf); - assert_eq!(s.as_ptr() as usize, ptr as usize); + assert_eq!(s.as_ptr(), ptr); assert!(str::from_utf8(s.as_bytes()).is_ok()); assert_eq!(s.as_bytes(), expect); } @@ -335,7 +335,7 @@ fn test_encode_utf16() { let mut buf = [0; 2]; let ptr = buf.as_mut_ptr(); let b = input.encode_utf16(&mut buf); - assert_eq!(b.as_mut_ptr() as usize, ptr as usize); + assert_eq!(b.as_mut_ptr(), ptr); assert_eq!(b, expect); } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 18e09c707ebad..64c53756acead 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -129,6 +129,7 @@ // tidy-alphabetical-end #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] +#![deny(lossy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] /// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality. diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index 93f9454d71378..9dbaf6690c81c 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs @@ -384,7 +384,7 @@ fn align_offset_stride_one() { #[test] fn align_offset_various_strides() { unsafe fn test_stride(ptr: *const T, align: usize) -> bool { - let numptr = ptr as usize; + let numptr = ptr.addr(); let mut expected = usize::MAX; // Naive but definitely correct way to find the *first* aligned element of stride::. for el in 0..align { diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs index 2bb62f36bb0e6..a4db7304fff90 100644 --- a/library/coretests/tests/slice.rs +++ b/library/coretests/tests/slice.rs @@ -1886,7 +1886,7 @@ fn test_align_to_empty_mid() { type Chunk = u32; for offset in 0..4 { let (_, mid, _) = unsafe { bytes[offset..offset + 1].align_to::() }; - assert_eq!(mid.as_ptr() as usize % align_of::(), 0); + assert_eq!(mid.as_ptr().addr() % align_of::(), 0); } } diff --git a/library/coretests/tests/waker.rs b/library/coretests/tests/waker.rs index 4889b8959ece4..be8b07b8ad009 100644 --- a/library/coretests/tests/waker.rs +++ b/library/coretests/tests/waker.rs @@ -5,16 +5,16 @@ use std::task::{RawWaker, RawWakerVTable, Waker}; fn test_waker_getters() { let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE); let waker = unsafe { Waker::from_raw(raw_waker) }; - assert_eq!(waker.data() as usize, 42); + assert_eq!(waker.data().addr(), 42); assert!(ptr::eq(waker.vtable(), &WAKER_VTABLE)); let waker2 = waker.clone(); - assert_eq!(waker2.data() as usize, 43); + assert_eq!(waker2.data().addr(), 43); assert!(ptr::eq(waker2.vtable(), &WAKER_VTABLE)); } static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( - |data| RawWaker::new(ptr::without_provenance_mut(data as usize + 1), &WAKER_VTABLE), + |data| RawWaker::new(ptr::without_provenance_mut(data.addr() + 1), &WAKER_VTABLE), |_| {}, |_| {}, |_| {}, diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index cb0f8edb7b852..e2fe7d4aa5448 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -246,6 +246,7 @@ #![allow(unused_lifetimes)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] +#![deny(lossy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] #![allow(rustdoc::redundant_explicit_links)] #![warn(rustdoc::unescaped_backticks)] @@ -714,7 +715,13 @@ pub mod alloc; mod panicking; #[path = "../../backtrace/src/lib.rs"] -#[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)] +#[allow( + dead_code, + unused_attributes, + fuzzy_provenance_casts, + lossy_provenance_casts, + unsafe_op_in_unsafe_fn +)] mod backtrace_rs; #[stable(feature = "cfg_select", since = "1.95.0")] diff --git a/library/std/src/sync/mpmc/select.rs b/library/std/src/sync/mpmc/select.rs index 56a83fee2e119..ff537aa686157 100644 --- a/library/std/src/sync/mpmc/select.rs +++ b/library/std/src/sync/mpmc/select.rs @@ -22,7 +22,7 @@ impl Operation { /// and is alive for the entire duration of a blocking operation. #[inline] pub fn hook(r: &mut T) -> Operation { - let val = r as *mut T as usize; + let val = (r as *mut T).addr(); // Make sure that the pointer address doesn't equal the numerical representation of // `Selected::{Waiting, Aborted, Disconnected}`. assert!(val > 2); diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index c743462501922..4f645e16fbb6f 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -25,7 +25,7 @@ impl Default for ZeroToken { impl fmt::Debug for ZeroToken { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&(self.0 as usize), f) + fmt::Debug::fmt(&self.0.addr(), f) } } diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs index 6ff94f5681b6f..9403059e7c607 100644 --- a/library/std/src/sys/args/sgx.rs +++ b/library/std/src/sys/args/sgx.rs @@ -1,4 +1,5 @@ -#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers +// FIXME: this module systematically confuses pointers and integers +#![allow(fuzzy_provenance_casts, lossy_provenance_casts)] use crate::ffi::OsString; use crate::num::NonZero; diff --git a/library/std/src/sys/env/sgx.rs b/library/std/src/sys/env/sgx.rs index 09090ec7cf0dd..0c19fcc848f4d 100644 --- a/library/std/src/sys/env/sgx.rs +++ b/library/std/src/sys/env/sgx.rs @@ -1,4 +1,5 @@ -#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers +// FIXME: this module systematically confuses pointers and integers +#![allow(fuzzy_provenance_casts, lossy_provenance_casts)] pub use super::common::Env; use crate::collections::HashMap; diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 2b284cc40b94b..7b2c8e5a8024a 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -3,7 +3,8 @@ //! This module contains the facade (aka platform-specific) implementations of //! OS level functionality for Fortanix SGX. #![deny(unsafe_op_in_unsafe_fn)] -#![allow(fuzzy_provenance_casts)] // FIXME: this entire module systematically confuses pointers and integers +// FIXME: this entire module systematically confuses pointers and integers +#![allow(fuzzy_provenance_casts, lossy_provenance_casts)] use crate::io; use crate::sync::atomic::{Atomic, AtomicBool, Ordering}; diff --git a/library/std/src/sys/thread_local/key/tests.rs b/library/std/src/sys/thread_local/key/tests.rs index c7d2c8e6301ef..5e5243d9835ed 100644 --- a/library/std/src/sys/thread_local/key/tests.rs +++ b/library/std/src/sys/thread_local/key/tests.rs @@ -18,8 +18,8 @@ fn smoke() { assert!(get(k2).is_null()); set(k1, ptr::without_provenance_mut(1)); set(k2, ptr::without_provenance_mut(2)); - assert_eq!(get(k1) as usize, 1); - assert_eq!(get(k2) as usize, 2); + assert_eq!(get(k1).addr(), 1); + assert_eq!(get(k2).addr(), 2); } } diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 4b934c039a36f..78b6f7c35e8db 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -152,11 +152,11 @@ where { let (tx, rx) = channel(); - let x: Box<_> = Box::new(1); - let x_in_parent = (&*x) as *const i32 as usize; + let x: Box = Box::new(1); + let x_in_parent = (&raw const *x).addr(); spawnfn(Box::new(move || { - let x_in_child = (&*x) as *const i32 as usize; + let x_in_child = (&raw const *x).addr(); tx.send(x_in_child).unwrap(); })); From ecdf68305bd9b2e0b9cdd9c92e3df344910e85f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 May 2026 14:07:42 +0200 Subject: [PATCH 05/11] update TargetFeature::Forbidden docs --- compiler/rustc_target/src/target_features.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b009c42eb2302..cafc914cfe51c 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -32,9 +32,12 @@ pub enum Stability { Symbol, ), /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be - /// set in the target spec. It is never set in `cfg(target_feature)`. Used in - /// particular for features are actually ABI configuration flags (not all targets are as nice as - /// RISC-V and have an explicit way to set the ABI separate from target features). + /// set in the target spec. It is never set in `cfg(target_feature)`. Used in particular for + /// features are actually ABI configuration flags (such as "soft-float" on many targets). + /// However, "forbidden" target features can still sometimes be enabled via `-Ctarget-cpu` or + /// target feature implications (on the Rust/LLVM level). To prevent that, ABI-relevant target + /// features are ideally pinned down (required or forbidden) in + /// [`Target::abi_required_features`]. Forbidden { reason: &'static str, /// True if this is always an error, false if this can be reported as a warning when set via @@ -128,9 +131,9 @@ impl Stability { // It is important for soundness to consider the interaction of targets features and the function // call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as // arguments, so letting people toggle that feature would be unsound. To this end, the -// `abi_required_features` function computes which target features must and must not be enabled for -// any given target, and individual features can also be marked as `Forbidden`. -// See https://github.com/rust-lang/rust/issues/116344 for some more context. +// [`Target::abi_required_features`] function computes which target features must and must not be +// enabled for any given target, and individual features can also be marked as `Forbidden`. See +// https://github.com/rust-lang/rust/issues/116344 for some more context. // // The one exception to features that change the ABI is features that enable larger vector // registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store From 375c51c0a0265e9c1ed56ac28dac9381131744ac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 May 2026 22:48:04 +0200 Subject: [PATCH 06/11] move target feature list explanation to module-level doc comment --- compiler/rustc_target/src/target_features.rs | 87 ++++++++++---------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index cafc914cfe51c..bbecb68f20eef 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -1,6 +1,44 @@ //! Declares Rust's target feature names for each target. //! Note that these are similar to but not always identical to LLVM's feature names, //! and Rust adds some features that do not correspond to LLVM features at all. +//! +//! The target features listed here can be used in `#[target_feature]` and `#[cfg(target_feature)]`. +//! They also do not trigger any warnings when used with `-Ctarget-feature`. +//! +//! Note that even unstable (and even entirely unlisted) features can be used with `-Ctarget-feature` +//! on stable. Using a feature not on the list of Rust target features only emits a warning. +//! Only `cfg(target_feature)` and `#[target_feature]` actually do any stability gating. +//! `cfg(target_feature)` for unstable features just works on nightly without any feature gate. +//! `#[target_feature]` requires a feature gate. +//! +//! When adding features to the below lists +//! check whether they're named already elsewhere in rust +//! e.g. in stdarch and whether the given name matches LLVM's +//! if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted. +//! Additionally, if the feature is not available in older version of LLVM supported by the current +//! rust, the same function must be updated to filter out these features to avoid triggering +//! warnings. +//! +//! Also note that all target features listed here must be purely additive: for target_feature 1.1 to +//! be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a +//! per-function level, since we would then allow safe calls from functions with `+soft-float` to +//! functions without that feature! +//! +//! It is important for soundness to consider the interaction of target features and the function +//! call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as +//! arguments, so letting people toggle that feature would be unsound. To this end, the +//! [`Target::abi_required_features`] function computes which target features must and must not be +//! enabled for any given target, and individual features can also be marked as [`Forbidden`]. See +//! for some more context. +//! +//! The one exception to features that change the ABI is features that enable larger vector +//! registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store +//! information about which target feature is ABI-required for which vector size; this is used to +//! ensure that vectors can only be passed via `extern "C"` when the right feature is enabled. (For +//! the "Rust" ABI we generally pass vectors by-ref exactly to avoid these issues.) +//! Also see . +//! +//! Stabilizing a target feature requires t-lang approval. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_macros::StableHash; use rustc_span::{Symbol, sym}; @@ -105,50 +143,11 @@ impl Stability { } } -// Here we list target features that rustc "understands": they can be used in `#[target_feature]` -// and `#[cfg(target_feature)]`. They also do not trigger any warnings when used with -// `-Ctarget-feature`. -// -// Note that even unstable (and even entirely unlisted) features can be used with `-Ctarget-feature` -// on stable. Using a feature not on the list of Rust target features only emits a warning. -// Only `cfg(target_feature)` and `#[target_feature]` actually do any stability gating. -// `cfg(target_feature)` for unstable features just works on nightly without any feature gate. -// `#[target_feature]` requires a feature gate. -// -// When adding features to the below lists -// check whether they're named already elsewhere in rust -// e.g. in stdarch and whether the given name matches LLVM's -// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted. -// Additionally, if the feature is not available in older version of LLVM supported by the current -// rust, the same function must be updated to filter out these features to avoid triggering -// warnings. -// -// Also note that all target features listed here must be purely additive: for target_feature 1.1 to -// be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a -// per-function level, since we would then allow safe calls from functions with `+soft-float` to -// functions without that feature! -// -// It is important for soundness to consider the interaction of targets features and the function -// call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as -// arguments, so letting people toggle that feature would be unsound. To this end, the -// [`Target::abi_required_features`] function computes which target features must and must not be -// enabled for any given target, and individual features can also be marked as `Forbidden`. See -// https://github.com/rust-lang/rust/issues/116344 for some more context. -// -// The one exception to features that change the ABI is features that enable larger vector -// registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store -// information about which target feature is ABI-required for which vector size; this is used to -// ensure that vectors can only be passed via `extern "C"` when the right feature is enabled. (For -// the "Rust" ABI we generally pass vectors by-ref exactly to avoid these issues.) -// Also see https://github.com/rust-lang/rust/issues/116558. -// -// Stabilizing a target feature requires t-lang approval. - -// If feature A "implies" feature B, then: -// - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B -// - when B gets disabled (via `-Ctarget-feature`), we also disable A -// -// Both of these are also applied transitively. +/// If feature A "implies" feature B, then: +/// - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B +/// - when B gets disabled (via `-Ctarget-feature`), we also disable A +/// +/// Both of these are also applied transitively. type ImpliedFeatures = &'static [&'static str]; static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ From 80a8b217a385ac06e8be6cd002326898055e1fa3 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 30 May 2026 07:37:05 -0700 Subject: [PATCH 07/11] Fix CI free-disk-space-linux script Occasionally we've been having jobs running on systems with limited free disk space, triggering this script to run. However, it has recently been failing with the error: E: Failed to fetch mirror+file:/etc/apt/apt-mirrors.txt/pool/main/o/openjdk-21/openjdk-21-jre-headless_21.0.10%2b7-1%7e24.04_amd64.deb 404 Not Found [IP: 52.252.163.49 80] E: Unable to correct problems, you have held broken packages. E: Aborting install. This adds an `apt-get update` to try to repair the index before trying to remove any packages. This seems to work in my testing, but I am far from an expert on apt. --- src/ci/scripts/free-disk-space-linux.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ci/scripts/free-disk-space-linux.sh b/src/ci/scripts/free-disk-space-linux.sh index 590e594e6aef4..167abf01ac880 100755 --- a/src/ci/scripts/free-disk-space-linux.sh +++ b/src/ci/scripts/free-disk-space-linux.sh @@ -277,6 +277,10 @@ cleanPackages() { fi WAIT_DPKG_LOCK="-o DPkg::Lock::Timeout=60" + # This update is intended to fix any broken state of the index and make + # sure it is fresh. Otherwise we've had problems with missing mirror + # entries. + sudo apt-get update -qq sudo apt-get ${WAIT_DPKG_LOCK} -qq remove -y --fix-missing "${packages[@]}" sudo apt-get ${WAIT_DPKG_LOCK} autoremove -y \ From 732998ab95c0179eb2b588acf7b05f68f35c9829 Mon Sep 17 00:00:00 2001 From: Hanna Kruppe Date: Sun, 31 May 2026 09:54:38 +0200 Subject: [PATCH 08/11] allow target-dependent int2ptr cast for pthread_t --- library/std/src/os/unix/thread.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/std/src/os/unix/thread.rs b/library/std/src/os/unix/thread.rs index 32085e525942e..efb349b18d6b5 100644 --- a/library/std/src/os/unix/thread.rs +++ b/library/std/src/os/unix/thread.rs @@ -31,10 +31,15 @@ pub trait JoinHandleExt { #[stable(feature = "thread_extensions", since = "1.9.0")] impl JoinHandleExt for JoinHandle { + // This is an int2ptr cast on some platforms (e.g., *-musl) where RawPthread + // is an integer but libc::pthread_t is a pointer. Exposed provenance is the + // safe choice here, but `as` also works when it's int2int or ptr2ptr. + #[allow(lossy_provenance_casts)] fn as_pthread_t(&self) -> RawPthread { self.as_inner().id() as RawPthread } + #[allow(lossy_provenance_casts)] // see above for why fn into_pthread_t(self) -> RawPthread { self.into_inner().into_id() as RawPthread } From 9c25035440c31a32f52a794412e154448a192cc3 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 31 May 2026 13:54:23 -0700 Subject: [PATCH 09/11] Mention how to fill a buffer with random bytes --- library/std/src/random.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/random.rs b/library/std/src/random.rs index a18dcf98ec7fc..5daedf42a3591 100644 --- a/library/std/src/random.rs +++ b/library/std/src/random.rs @@ -16,6 +16,8 @@ use crate::sys::random as sys; /// security is not a concern, consider using an alternative random number /// generator (potentially seeded from this one). /// +/// If you need to fill a buffer with random bytes, use `DefaultRandomSource.fill_bytes(&mut buf)`. +/// /// # Underlying sources /// /// Platform | Source From f65c5656ff068ec5dcbfa26bce42e91b20c4f604 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 31 May 2026 13:54:35 -0700 Subject: [PATCH 10/11] Add doc aliases for `DefaultRandomSource`, for people looking for randomness `getrandom` is both a crate for this and the name of the underlying syscall on various OSes. `getentropy` and `arc4random` are common library calls on various OSes. --- library/std/src/random.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/random.rs b/library/std/src/random.rs index 5daedf42a3591..8274060e5cedf 100644 --- a/library/std/src/random.rs +++ b/library/std/src/random.rs @@ -56,6 +56,7 @@ use crate::sys::random as sys; /// /// [`getrandom`]: https://www.man7.org/linux/man-pages/man2/getrandom.2.html /// [`/dev/urandom`]: https://www.man7.org/linux/man-pages/man4/random.4.html +#[doc(alias = "getrandom", alias = "getentropy", alias = "arc4random")] #[derive(Default, Debug, Clone, Copy)] #[unstable(feature = "random", issue = "130703")] pub struct DefaultRandomSource; From 3467b6fc2039d983bce762032717c8730b934510 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sun, 31 May 2026 18:08:27 -0300 Subject: [PATCH 11/11] Clean resolved signature for delegated functions in rustdoc A delegation item (`reuse path::method`) has an unresolved HIR signature: its inputs and return type are `InferDelegation` nodes that clean to `_`. When the delegated function is async, the `async` header over that inferred return type made `clean_fn_decl_with_params` call `sugared_async_return_type` on a non-`impl Future` type, panicking with "unexpected async fn return type". Clean the resolved ty-side signature for delegation items instead, the same way inlined items are cleaned. This avoids the ICE and renders the real return type and `self` parameter rather than `-> _` / `self: _`. --- src/librustdoc/clean/mod.rs | 49 ++++++++++++++----- .../rustdoc-html/async/async-fn-delegation.rs | 42 ++++++++++++++++ 2 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 tests/rustdoc-html/async/async-fn-delegation.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cf6deebe8e1d7..236d959b7e190 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1089,7 +1089,13 @@ fn clean_fn_or_proc_macro<'tcx>( match macro_kind { Some(kind) => clean_proc_macro(item, name, kind, cx.tcx), None => { - let mut func = clean_function(cx, sig, generics, ParamsSrc::Body(body_id)); + let mut func = clean_function( + cx, + sig, + generics, + ParamsSrc::Body(body_id), + item.owner_id.to_def_id(), + ); clean_fn_decl_legacy_const_generics(&mut func, attrs); FunctionItem(func) } @@ -1127,18 +1133,30 @@ fn clean_function<'tcx>( sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'tcx>, params: ParamsSrc<'tcx>, + def_id: DefId, ) -> Box { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: Generics must be cleaned before params. let generics = clean_generics(generics, cx); - let params = match params { - ParamsSrc::Body(body_id) => clean_params_via_body(cx, sig.decl.inputs, body_id), - // Let's not perpetuate anon params from Rust 2015; use `_` for them. - ParamsSrc::Idents(idents) => clean_params(cx, sig.decl.inputs, idents, |ident| { - Some(ident.map_or(kw::Underscore, |ident| ident.name)) - }), + let decl = if sig.decl.opt_delegation_sig_id().is_some() { + // A delegation item (`reuse path::method`) has no resolved signature in the + // HIR: its inputs and return type are `InferDelegation` nodes that clean to + // `_`, and an `async` header over that inferred return type would panic in + // `sugared_async_return_type`. The resolved signature only exists on the ty + // side, so clean that instead, exactly like an inlined item. This both fixes + // the rendered `-> _` / `self: _` and makes the async sugaring well-defined. + let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); + clean_poly_fn_sig(cx, Some(def_id), sig) + } else { + let params = match params { + ParamsSrc::Body(body_id) => clean_params_via_body(cx, sig.decl.inputs, body_id), + // Let's not perpetuate anon params from Rust 2015; use `_` for them. + ParamsSrc::Idents(idents) => clean_params(cx, sig.decl.inputs, idents, |ident| { + Some(ident.map_or(kw::Underscore, |ident| ident.name)) + }), + }; + clean_fn_decl_with_params(cx, sig.decl, Some(&sig.header), params) }; - let decl = clean_fn_decl_with_params(cx, sig.decl, Some(&sig.header), params); (generics, decl) }); Box::new(Function { decl, generics }) @@ -1270,11 +1288,18 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx))) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body)); + let m = + clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body), local_did); MethodItem(m, Defaultness::from_trait_item(trait_item.defaultness)) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => { - let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents)); + let m = clean_function( + cx, + sig, + trait_item.generics, + ParamsSrc::Idents(idents), + local_did, + ); RequiredMethodItem(m, Defaultness::from_trait_item(trait_item.defaultness)) } hir::TraitItemKind::Type(bounds, Some(default)) => { @@ -1315,7 +1340,7 @@ pub(crate) fn clean_impl_item<'tcx>( type_: clean_ty(ty, cx), })), hir::ImplItemKind::Fn(ref sig, body) => { - let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body)); + let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body), local_did); let defaultness = match impl_.impl_kind { hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final, hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness, @@ -3254,7 +3279,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( cx.with_param_env(def_id, |cx| { let kind = match item.kind { hir::ForeignItemKind::Fn(sig, idents, generics) => ForeignFunctionItem( - clean_function(cx, &sig, generics, ParamsSrc::Idents(idents)), + clean_function(cx, &sig, generics, ParamsSrc::Idents(idents), def_id), sig.header.safety(), ), hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem( diff --git a/tests/rustdoc-html/async/async-fn-delegation.rs b/tests/rustdoc-html/async/async-fn-delegation.rs new file mode 100644 index 0000000000000..7d891ac8be637 --- /dev/null +++ b/tests/rustdoc-html/async/async-fn-delegation.rs @@ -0,0 +1,42 @@ +//@ edition: 2021 + +// Regression test for . +// +// rustdoc used to ICE with "unexpected async fn return type" when cleaning a +// delegated (`reuse`) async fn: the delegation's HIR signature is unresolved +// (`InferDelegation`), so its return type cleaned to `_` even though the header +// is `async`, and unconditionally sugaring that inferred type panicked. +// +// We now clean the resolved (ty-side) signature for delegation items, like we +// already do for inlined items. That both avoids the ICE and renders the real +// return type and `self` parameter instead of `-> _` / `self: _`. +// +// Note: the `` generic on the free-function variants is a pre-existing +// quirk of how delegation generics are rendered (plain sync delegation prints it +// too); it is tracked separately and is not what this test is about. + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![crate_name = "async_delegation"] + +pub trait Trait { + async fn unit(&self) {} + async fn nonunit(&self) -> i32 { + 0 + } +} + +//@ has async_delegation/fn.unit.html '//pre[@class="rust item-decl"]' 'pub async fn unit(&self)' +pub reuse Trait::unit; +//@ has async_delegation/fn.nonunit.html '//pre[@class="rust item-decl"]' 'pub async fn nonunit(&self) -> i32' +pub reuse Trait::nonunit; + +pub struct S; +impl Trait for S {} + +//@ has async_delegation/struct.S.html '//*[@class="code-header"]' 'pub async fn unit(self: &S)' +//@ has async_delegation/struct.S.html '//*[@class="code-header"]' 'pub async fn nonunit(self: &S) -> i32' +impl S { + pub reuse Trait::unit { self } + pub reuse Trait::nonunit { self } +}