From d33b74b7bd4820703e192093a1fd9d18b318be3c Mon Sep 17 00:00:00 2001 From: Axel Rousselot Date: Mon, 6 Jul 2026 13:37:03 +0200 Subject: [PATCH 01/32] Add `desktop` method to `CommandExt` Adds the `desktop` method to the Windows `CommandExt` trait to enable setting the `lpDesktop` field of the STARTUPINFO passed to the Windows `CreateProcess` API call. --- library/std/src/os/windows/process.rs | 14 +++ library/std/src/sys/process/windows.rs | 11 +++ tests/ui/process/win-desktop.rs | 129 +++++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 tests/ui/process/win-desktop.rs diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 3332714ae4bb7..ad22dd4820955 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -174,6 +174,15 @@ pub impl(self) trait CommandExt { #[stable(feature = "windows_process_extensions", since = "1.16.0")] fn creation_flags(&mut self, flags: u32) -> &mut process::Command; + /// Places the child process on the desktop named `desktop` by setting the + /// `lpDesktop` field of the [STARTUPINFO][1] passed to `CreateProcess`. + /// + /// The name may be a desktop or a `window-station\desktop` path. + /// + /// [1]: + #[unstable(feature = "windows_process_extensions_desktop", issue = "158852")] + fn desktop>(&mut self, desktop: S) -> &mut process::Command; + /// Sets the field `wShowWindow` of [STARTUPINFO][1] that is passed to `CreateProcess`. /// Allowed values are the ones listed in /// @@ -381,6 +390,11 @@ impl CommandExt for process::Command { self } + fn desktop>(&mut self, desktop: S) -> &mut process::Command { + self.as_inner_mut().desktop(desktop.as_ref()); + self + } + fn show_window(&mut self, cmd_show: u16) -> &mut process::Command { self.as_inner_mut().show_window(Some(cmd_show)); self diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index a747ef048d901..b6ecbc71cba85 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -162,6 +162,7 @@ pub struct Command { startupinfo_untrusted_source: bool, startupinfo_force_feedback: Option, inherit_handles: bool, + desktop: Option>, } pub enum Stdio { @@ -191,6 +192,7 @@ impl Command { startupinfo_untrusted_source: false, startupinfo_force_feedback: None, inherit_handles: true, + desktop: None, } } @@ -215,6 +217,7 @@ impl Command { pub fn creation_flags(&mut self, flags: u32) { self.flags = flags; } + pub fn show_window(&mut self, cmd_show: Option) { self.show_window = cmd_show; } @@ -239,6 +242,10 @@ impl Command { self.startupinfo_force_feedback = enabled; } + pub fn desktop(&mut self, desktop: &OsStr) { + self.desktop = Some(desktop.encode_wide().chain([0]).collect()); + } + pub fn get_program(&self) -> &OsStr { &self.program } @@ -391,6 +398,10 @@ impl Command { None => {} } + if let Some(desktop) = &mut self.desktop { + si.lpDesktop = desktop.as_mut_ptr(); + } + let si_ptr: *mut c::STARTUPINFOW; let mut si_ex; diff --git a/tests/ui/process/win-desktop.rs b/tests/ui/process/win-desktop.rs new file mode 100644 index 0000000000000..f5ffed42212c7 --- /dev/null +++ b/tests/ui/process/win-desktop.rs @@ -0,0 +1,129 @@ +// Tests `desktop` by creating a new desktop, spawning a child process onto it +// and checking that the child reports back the expected desktop name. + +//@ run-pass +//@ only-windows +//@ needs-subprocess +//@ edition: 2024 + +#![feature(windows_process_extensions_desktop)] + +use std::os::windows::process::CommandExt; +use std::process::{Command, Stdio}; +use std::{env, io, process}; + +fn main() { + if env::args().skip(1).any(|s| s == "--child") { + child(); + } else { + parent(); + } +} + +fn parent() { + let exe = env::current_exe().unwrap(); + + // Create a uniquely named desktop on the current window station and keep the + // handle alive so the desktop is not destroyed while the child runs. + let desktop_name = format!("rust-test-desktop-{}", process::id()); + let desktop_name_wide: Vec = desktop_name.encode_utf16().chain([0]).collect(); + let hdesk = unsafe { + CreateDesktopW( + desktop_name_wide.as_ptr(), + core::ptr::null(), + core::ptr::null(), + 0, + GENERIC_ALL, + core::ptr::null(), + ) + }; + assert!(!hdesk.is_null(), "CreateDesktopW failed: {:?}", io::Error::last_os_error()); + + // Spawning with `.desktop` should place the child on our new desktop. + let output = Command::new(&exe) + .arg("--child") + .desktop(&desktop_name) + .stdout(Stdio::piped()) + .output() + .unwrap(); + assert!(output.status.success(), "child failed: {:?}", output); + let reported = String::from_utf8(output.stdout).unwrap(); + assert!( + reported.trim().eq_ignore_ascii_case(&desktop_name), + "child ran on unexpected desktop: expected {:?}, got {:?}", + desktop_name, + reported.trim(), + ); + + // Without `.desktop` the child inherits the parent's desktop, which is + // not the one we just created. + let output = Command::new(&exe).arg("--child").stdout(Stdio::piped()).output().unwrap(); + assert!(output.status.success(), "child failed: {:?}", output); + let reported = String::from_utf8(output.stdout).unwrap(); + assert!( + !reported.trim().eq_ignore_ascii_case(&desktop_name), + "child unexpectedly ran on the created desktop {:?} without being asked to", + desktop_name, + ); + + unsafe { CloseDesktop(hdesk) }; +} + +/// Prints the name of the desktop the current process is running on. +fn child() { + let hdesk = unsafe { GetThreadDesktop(GetCurrentThreadId()) }; + assert!(!hdesk.is_null(), "GetThreadDesktop failed: {:?}", io::Error::last_os_error()); + + let mut buffer = [0u16; 256]; + let mut needed = 0u32; + let ret = unsafe { + GetUserObjectInformationW( + hdesk, + UOI_NAME, + buffer.as_mut_ptr().cast(), + size_of_val(&buffer) as u32, + &raw mut needed, + ) + }; + assert_ne!(ret, 0, "GetUserObjectInformationW failed: {:?}", io::Error::last_os_error()); + + let len = buffer.iter().position(|&c| c == 0).unwrap_or(buffer.len()); + let name = String::from_utf16(&buffer[..len]).unwrap(); + print!("{name}"); +} + +// Windows API +mod winapi { + use std::ffi::c_void; + use std::os::windows::raw::HANDLE; + + pub const GENERIC_ALL: u32 = 0x10000000; + pub const UOI_NAME: i32 = 2; + + #[link(name = "user32")] + unsafe extern "system" { + pub fn CreateDesktopW( + lpszDesktop: *const u16, + lpszDevice: *const u16, + pDevmode: *const c_void, + dwFlags: u32, + dwDesiredAccess: u32, + lpsa: *const c_void, + ) -> HANDLE; + pub fn CloseDesktop(hDesktop: HANDLE) -> i32; + pub fn GetThreadDesktop(dwThreadId: u32) -> HANDLE; + pub fn GetUserObjectInformationW( + hObj: HANDLE, + nIndex: i32, + pvInfo: *mut c_void, + nLength: u32, + lpnLengthNeeded: *mut u32, + ) -> i32; + } + + #[link(name = "kernel32")] + unsafe extern "system" { + pub fn GetCurrentThreadId() -> u32; + } +} +use winapi::*; From c266bb2f5307864efd38eea45343e0c650bc4470 Mon Sep 17 00:00:00 2001 From: Sa4dUs Date: Wed, 17 Jun 2026 16:19:15 +0200 Subject: [PATCH 02/32] get number of devices intrinisc --- compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs | 10 ++++++++++ compiler/rustc_codegen_llvm/src/intrinsic.rs | 9 ++++++++- compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 1 + compiler/rustc_hir_analysis/src/check/intrinsic.rs | 7 +++++++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/mod.rs | 5 +++++ 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index 3d0bb6fcc48fd..5fc4f71f951ad 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -197,6 +197,16 @@ fn generate_launcher<'ll>(cx: &CodegenCx<'ll, '_>) -> (&'ll llvm::Value, &'ll ll (tgt_decl, tgt_fn_ty) } +pub(crate) fn generate_decl<'ll>(cx: &CodegenCx<'ll, '_>) -> (&'ll llvm::Value, &'ll llvm::Type) { + let ti32 = cx.type_i32(); + let tgt_fn_ty = cx.type_func(&[], ti32); + let name = "omp_get_num_devices"; + let tgt_decl = declare_offload_fn(&cx, name, tgt_fn_ty); + let nounwind = llvm::AttributeKind::NoUnwind.create_attr(cx.llcx); + attributes::apply_to_llfn(tgt_decl, Function, &[nounwind]); + (tgt_decl, tgt_fn_ty) +} + // What is our @1 here? A magic global, used in our data_{begin/update/end}_mapper: // @0 = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1 // @1 = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 22, ptr @0 }, align 8 diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index ba11ef29fb536..da230a6da9ac2 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -37,7 +37,7 @@ use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call}; use crate::builder::gpu_offload::{ - OffloadKernelDims, gen_call_handling, gen_define_handling, register_offload, + OffloadKernelDims, gen_call_handling, gen_define_handling, register_offload, generate_decl, }; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; @@ -241,6 +241,13 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // offload *has* a return type, but somehow works without mentioning the place return IntrinsicResult::WroteIntoPlace; } + sym::offload_get_num_devices => { + let (fn_decl, fn_ty) = generate_decl(self.cx); + + let llval = self.call(fn_ty, None, None, fn_decl, &[], None, None); + + return IntrinsicResult::Operand(OperandValue::Immediate(llval)); + }, sym::is_val_statically_known => { if let OperandValue::Immediate(imm) = args[0].val { self.call_intrinsic( diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 77ab3bdce4689..23285a043af70 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -135,6 +135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | sym::atomic_fence | sym::atomic_singlethreadfence | sym::caller_location + | sym::offload_get_num_devices | sym::return_address => {} _ => { span_bug!( diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 11d21744bd7ae..c96cd0a8c8a5f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -168,6 +168,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::needs_drop | sym::non_exhaustive | sym::offload + | sym::offload_get_num_devices | sym::offset_of | sym::overflow_checks | sym::powf16 @@ -384,6 +385,12 @@ pub(crate) fn check_intrinsic_type( ], param(2), ), + sym::offload_get_num_devices => ( + 0, + 0, + vec![], + tcx.types.i32, + ), sym::offset => (2, 0, vec![param(0), param(1)], param(0)), sym::arith_offset => ( 1, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 45df107bf7469..b678f63495b82 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1468,6 +1468,7 @@ symbols! { of, off, offload, + offload_get_num_devices, offload_kernel, offset, offset_of, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 4e67199bba8c9..eefb1b9ed7bd8 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3814,6 +3814,11 @@ pub const fn offload( args: T, ) -> R; +// TODO(Sa4dUs): add docs +#[rustc_nounwind] +#[rustc_intrinsic] +pub const fn offload_get_num_devices() -> i32; + /// Inform Miri that a given pointer definitely has a certain alignment. #[cfg(miri)] #[rustc_allow_const_fn_unstable(const_eval_select)] From efbb356b50c0d7e8c743ad1fbb9f4227b050b6fb Mon Sep 17 00:00:00 2001 From: Marcelo Dominguez Date: Thu, 13 Aug 2026 12:35:46 +0300 Subject: [PATCH 03/32] Add device arg to offload intrinisc --- .../src/builder/gpu_offload.rs | 12 +++-------- compiler/rustc_codegen_llvm/src/intrinsic.rs | 9 ++++++-- .../rustc_hir_analysis/src/check/intrinsic.rs | 8 ++----- library/core/src/intrinsics/mod.rs | 12 +++++++++-- .../codegen-llvm/gpu_offload/control_flow.rs | 1 + tests/codegen-llvm/gpu_offload/gpu_host.rs | 16 +++++++------- tests/codegen-llvm/gpu_offload/scalar_host.rs | 9 +++++++- .../codegen-llvm/gpu_offload/slice_device.rs | 2 +- tests/codegen-llvm/gpu_offload/slice_host.rs | 9 +++++++- tests/ui/offload/check_config.rs | 2 +- tests/ui/offload/duplicate_kernel.rs | 2 +- tests/ui/offload/non_tuple_args.rs | 2 +- tests/ui/offload/non_tuple_args.stderr | 2 +- tests/ui/offload/type_mismatch.rs | 21 ++++++++++++------- tests/ui/offload/type_mismatch.stderr | 12 +++++------ 15 files changed, 73 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index 5fc4f71f951ad..4f8d918c72b51 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -601,6 +601,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( offload_globals: &OffloadGlobals<'ll>, offload_dims: &OffloadKernelDims<'ll>, dyn_cache: &'ll Value, + device_id: &'ll Value, ) { let cx = builder.cx; let OffloadKernelGlobals { @@ -785,15 +786,8 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( builder.store(value.2, ptr, value.0); } - let args = vec![ - s_ident_t, - // FIXME(offload) give users a way to select which GPU to use. - cx.get_const_i64(u64::MAX), // MAX == -1. - num_workgroups, - threads_per_block, - region_id, - a5, - ]; + let device_id = builder.sext(device_id, cx.type_i64()); + let args = vec![s_ident_t, device_id, num_workgroups, threads_per_block, region_id, a5]; builder.call(tgt_target_kernel_ty, None, None, tgt_decl, &args, None, None); // %41 = call i32 @__tgt_target_kernel(ptr @1, i64 -1, i32 2097152, i32 256, ptr @.kernel_1.region_id, ptr %kernel_args) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index da230a6da9ac2..fbd9a04ab2687 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -37,7 +37,7 @@ use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call}; use crate::builder::gpu_offload::{ - OffloadKernelDims, gen_call_handling, gen_define_handling, register_offload, generate_decl, + OffloadKernelDims, gen_call_handling, gen_define_handling, generate_decl, register_offload, }; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; @@ -1858,7 +1858,11 @@ fn codegen_offload<'ll, 'tcx>( OperandValue::Immediate(val) => val, _ => panic!("unparsable"), }; - let args = get_args_from_tuple(bx, args[4], fn_target); + let device_id = match args[4].val { + OperandValue::Immediate(val) => val, + _ => panic!("unparsable"), + }; + let args = get_args_from_tuple(bx, args[5], fn_target); let target_symbol = mangle_offload_export(tcx, fn_target); let sig = tcx.fn_sig(fn_target.def_id()).instantiate(tcx, fn_target.args).skip_norm_wip(); @@ -1899,6 +1903,7 @@ fn codegen_offload<'ll, 'tcx>( offload_globals, &offload_dims, &dyn_cache, + &device_id, ); } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index c96cd0a8c8a5f..39e68b7541d08 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -381,16 +381,12 @@ pub(crate) fn check_intrinsic_type( Ty::new_array_with_const_len(tcx, tcx.types.u32, Const::from_target_usize(tcx, 3)), Ty::new_array_with_const_len(tcx, tcx.types.u32, Const::from_target_usize(tcx, 3)), tcx.types.u32, + tcx.types.i32, param(1), ], param(2), ), - sym::offload_get_num_devices => ( - 0, - 0, - vec![], - tcx.types.i32, - ), + sym::offload_get_num_devices => (0, 0, vec![], tcx.types.i32), sym::offset => (2, 0, vec![param(0), param(1)], param(0)), sym::arith_offset => ( 1, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index eefb1b9ed7bd8..c26c007a254e5 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3781,13 +3781,15 @@ pub const fn autodiff(f: F, df: G, args: T) -> /// - `f`: The kernel function to offload. /// - `workgroup_dim`: A 3D size specifying the number of workgroups to launch. /// - `thread_dim`: A 3D size specifying the number of threads per workgroup. +/// - `dyn_cache`: The amount of dynamic shared memory to request for the kernel. +/// - `device_id`: The device to offload to. Use `-1` to select the default device. /// - `args`: A tuple of arguments forwarded to `f`. /// /// Example usage (pseudocode): /// /// ```rust,ignore (pseudocode) /// fn kernel(x: *mut [f64; 128]) { -/// core::intrinsics::offload(kernel_1, [256, 1, 1], [32, 1, 1], (x,)) +/// core::intrinsics::offload(kernel_1, [256, 1, 1], [32, 1, 1], 0, -1, (x,)) /// } /// /// #[cfg(target_os = "linux")] @@ -3811,10 +3813,16 @@ pub const fn offload( workgroup_dim: [u32; 3], thread_dim: [u32; 3], dyn_cache: u32, + device_id: i32, args: T, ) -> R; -// TODO(Sa4dUs): add docs +/// Returns the number of offload devices available on the system. +/// +/// Use this to discover which `device_id` values are valid to pass to +/// [`offload`]. Devices are numbered from `0` to the returned value minus one. +/// +/// Returns `0` if no offloading devices are present. #[rustc_nounwind] #[rustc_intrinsic] pub const fn offload_get_num_devices() -> i32; diff --git a/tests/codegen-llvm/gpu_offload/control_flow.rs b/tests/codegen-llvm/gpu_offload/control_flow.rs index da997de53a428..ef4881147e63b 100644 --- a/tests/codegen-llvm/gpu_offload/control_flow.rs +++ b/tests/codegen-llvm/gpu_offload/control_flow.rs @@ -33,6 +33,7 @@ unsafe fn main() { [256, 1, 1], [32, 1, 1], 0, + -1, (A.as_ptr() as *const [f32; 6],), ); } diff --git a/tests/codegen-llvm/gpu_offload/gpu_host.rs b/tests/codegen-llvm/gpu_offload/gpu_host.rs index 2bfaf89b45590..208417b98bcae 100644 --- a/tests/codegen-llvm/gpu_offload/gpu_host.rs +++ b/tests/codegen-llvm/gpu_offload/gpu_host.rs @@ -21,7 +21,7 @@ fn main() { } pub fn kernel_1(x: &mut [f32; 256], y: &[f32; 256]) { - core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], 0, (x, y)) + core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], 0, -1, (x, y)) } #[inline(never)] @@ -78,8 +78,10 @@ pub fn _kernel_1(x: &mut [f32; 256], y: &[f32; 256]) { // CHECK-NEXT: [[P32:%[^ ]+]] = getelementptr inbounds nuw i8, ptr %kernel_args, i64 32 // CHECK-NEXT: store ptr @.offload_maptypes.[[K]].kernel, ptr [[P32]], align 8 // CHECK-NEXT: [[P40:%[^ ]+]] = getelementptr inbounds nuw i8, ptr %kernel_args, i64 40 +// CHECK-NEXT: [[P64:%[^ ]+]] = getelementptr inbounds nuw i8, ptr %kernel_args, i64 64 +// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 8 dereferenceable(24) [[P40]], i8 0, i64 24, i1 false) +// CHECK-NEXT: store i64 64, ptr [[P64]], align 8 // CHECK-NEXT: [[P72:%[^ ]+]] = getelementptr inbounds nuw i8, ptr %kernel_args, i64 72 -// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 8 dereferenceable(32) [[P40]], i8 0, i64 32, i1 false) // CHECK-NEXT: store <4 x i32> , ptr [[P72]], align 8 // CHECK-NEXT: [[P88:%[^ ]+]] = getelementptr inbounds nuw i8, ptr %kernel_args, i64 88 // CHECK-NEXT: store i32 1, ptr [[P88]], align 8 @@ -95,17 +97,17 @@ pub fn _kernel_1(x: &mut [f32; 256], y: &[f32; 256]) { // CHECK: declare void @__tgt_register_lib(ptr) local_unnamed_addr // CHECK: declare void @__tgt_unregister_lib(ptr) local_unnamed_addr -// CHECK-LABEL: define internal void @.omp_offloading.descriptor_reg() section ".text.startup" { +// CHECK-LABEL: define internal void @.omp_offloading.descriptor_reg() section ".text.startup" !guid !{{[0-9]+}} { // CHECK-NEXT: entry: -// CHECK-NEXT: call void @__tgt_register_lib(ptr nonnull @.omp_offloading.descriptor) -// CHECK-NEXT: call void @__tgt_init_all_rtls() +// CHECK-NEXT: {{tail }}call void @__tgt_register_lib(ptr nonnull @.omp_offloading.descriptor) +// CHECK-NEXT: {{tail }}call void @__tgt_init_all_rtls() // CHECK-NEXT: %0 = {{tail }}call i32 @atexit(ptr nonnull @.omp_offloading.descriptor_unreg) // CHECK-NEXT: ret void // CHECK-NEXT: } -// CHECK-LABEL: define internal void @.omp_offloading.descriptor_unreg() section ".text.startup" { +// CHECK-LABEL: define internal void @.omp_offloading.descriptor_unreg() section ".text.startup" !guid !{{[0-9]+}} { // CHECK-NEXT: entry: -// CHECK-NEXT: call void @__tgt_unregister_lib(ptr nonnull @.omp_offloading.descriptor) +// CHECK-NEXT: {{tail }}call void @__tgt_unregister_lib(ptr nonnull @.omp_offloading.descriptor) // CHECK-NEXT: ret void // CHECK-NEXT: } diff --git a/tests/codegen-llvm/gpu_offload/scalar_host.rs b/tests/codegen-llvm/gpu_offload/scalar_host.rs index 66c910c439e46..950306c83a43f 100644 --- a/tests/codegen-llvm/gpu_offload/scalar_host.rs +++ b/tests/codegen-llvm/gpu_offload/scalar_host.rs @@ -28,7 +28,14 @@ fn main() { let mut x = 0.0f32; let k = core::hint::black_box(42.0f32); - core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, (&mut x as *mut f32, k)); + core::intrinsics::offload::<_, _, ()>( + foo, + [1, 1, 1], + [1, 1, 1], + 0, + -1, + (&mut x as *mut f32, k), + ); } unsafe extern "C" { diff --git a/tests/codegen-llvm/gpu_offload/slice_device.rs b/tests/codegen-llvm/gpu_offload/slice_device.rs index 1abe04f8cc429..6e900c21ca7cb 100644 --- a/tests/codegen-llvm/gpu_offload/slice_device.rs +++ b/tests/codegen-llvm/gpu_offload/slice_device.rs @@ -15,7 +15,7 @@ extern crate minicore; // CHECK: ; Function Attrs // nvptx-NEXT: define ptx_kernel void @foo // amdgpu-NEXT: define amdgpu_kernel void @foo -// CHECK-SAME: ptr readnone captures(none) %dyn_ptr +// CHECK-SAME: ptr nofree readnone captures(none) %dyn_ptr // nvptx-SAME: [2 x i64] %0 // amdgpu-SAME: ptr noalias {{.*}} %0, i64 {{.*}} %1 // CHECK-NEXT: entry: diff --git a/tests/codegen-llvm/gpu_offload/slice_host.rs b/tests/codegen-llvm/gpu_offload/slice_host.rs index dfc7ec545630c..1b314d489612c 100644 --- a/tests/codegen-llvm/gpu_offload/slice_host.rs +++ b/tests/codegen-llvm/gpu_offload/slice_host.rs @@ -27,7 +27,14 @@ #[unsafe(no_mangle)] fn main() { let mut x = [0.0f32, 0.0, 0.0, 0.0]; - core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, ((&mut x) as &mut [f32],)); + core::intrinsics::offload::<_, _, ()>( + foo, + [1, 1, 1], + [1, 1, 1], + 0, + -1, + ((&mut x) as &mut [f32],), + ); } unsafe extern "C" { diff --git a/tests/ui/offload/check_config.rs b/tests/ui/offload/check_config.rs index ff145f420e482..833ba39dffeca 100644 --- a/tests/ui/offload/check_config.rs +++ b/tests/ui/offload/check_config.rs @@ -17,7 +17,7 @@ fn main() { } fn kernel_1(x: &mut [f32; 256]) { - core::intrinsics::offload(_kernel_1, [1, 1, 1], [1, 1, 1], 0, (x,)) + core::intrinsics::offload(_kernel_1, [1, 1, 1], [1, 1, 1], 0, -1, (x,)) } fn _kernel_1(x: &mut [f32; 256]) {} diff --git a/tests/ui/offload/duplicate_kernel.rs b/tests/ui/offload/duplicate_kernel.rs index abde76137a37c..da667a0c0666a 100644 --- a/tests/ui/offload/duplicate_kernel.rs +++ b/tests/ui/offload/duplicate_kernel.rs @@ -18,5 +18,5 @@ fn kernel(_x: f32) {} fn main() { _RNvC19collision_kernels_a6kernel(0.0); - core::intrinsics::offload::<_, _, ()>(kernel, [1, 1, 1], [1, 1, 1], 0, (0.0f32,)); + core::intrinsics::offload::<_, _, ()>(kernel, [1, 1, 1], [1, 1, 1], 0, -1, (0.0f32,)); } diff --git a/tests/ui/offload/non_tuple_args.rs b/tests/ui/offload/non_tuple_args.rs index 0a07c99a26d34..14de21b2374a2 100644 --- a/tests/ui/offload/non_tuple_args.rs +++ b/tests/ui/offload/non_tuple_args.rs @@ -4,7 +4,7 @@ fn main() { // args_ty is not a tuple - core::intrinsics::offload::<_, _, ()>(kernel_0, [1, 1, 1], [1, 1, 1], 0, 42); + core::intrinsics::offload::<_, _, ()>(kernel_0, [1, 1, 1], [1, 1, 1], 0, -1, 42); //~^ ERROR `{integer}` is not a tuple } diff --git a/tests/ui/offload/non_tuple_args.stderr b/tests/ui/offload/non_tuple_args.stderr index 8b59d6828c6f2..90b0f16bec53e 100644 --- a/tests/ui/offload/non_tuple_args.stderr +++ b/tests/ui/offload/non_tuple_args.stderr @@ -1,7 +1,7 @@ error[E0277]: `{integer}` is not a tuple --> $DIR/non_tuple_args.rs:7:36 | -LL | core::intrinsics::offload::<_, _, ()>(kernel_0, [1, 1, 1], [1, 1, 1], 0, 42); +LL | core::intrinsics::offload::<_, _, ()>(kernel_0, [1, 1, 1], [1, 1, 1], 0, -1, 42); | ^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `{integer}` | note: required by a bound in `offload` diff --git a/tests/ui/offload/type_mismatch.rs b/tests/ui/offload/type_mismatch.rs index 4079444a0aff1..a75f8358b7359 100644 --- a/tests/ui/offload/type_mismatch.rs +++ b/tests/ui/offload/type_mismatch.rs @@ -5,25 +5,32 @@ fn main() { // kernel_ty is not a function item let not_fn = 42; - core::intrinsics::offload::<_, _, ()>(not_fn, [1, 1, 1], [1, 1, 1], 0, ()); + core::intrinsics::offload::<_, _, ()>(not_fn, [1, 1, 1], [1, 1, 1], 0, -1, ()); //~^ ERROR expected a function item for the offload kernel, found `i32` // argument count mismatch - core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, ()); + core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, -1, ()); //~^ ERROR offload kernel expects 1 arguments, but 0 arguments were provided // argument type mismatch - core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, (42.0f64,)); + core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, -1, (42.0f64,)); //~^ ERROR type mismatch in offload kernel argument 0: expected `f32`, found `f64` // return type mismatch - let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, ()); + let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, -1, ()); //~^ ERROR offload kernel return type mismatch: kernel returns `()`, but offload call expects `f64` // multiple argument type mismatch - core::intrinsics::offload::<_, _, ()>(kernel_2, [1, 1, 1], [1, 1, 1], 0, (42.0f64, 42.0f64)); - //~^ ERROR type mismatch in offload kernel argument 0: expected `f32`, found `f64` - //~| ERROR type mismatch in offload kernel argument 1: expected `f32`, found `f64` + core::intrinsics::offload::<_, _, ()>( + //~^ ERROR type mismatch in offload kernel argument 0: expected `f32`, found `f64` + //~| ERROR type mismatch in offload kernel argument 1: expected `f32`, found `f64` + kernel_2, + [1, 1, 1], + [1, 1, 1], + 0, + -1, + (42.0f64, 42.0f64), + ); } fn kernel_0() {} diff --git a/tests/ui/offload/type_mismatch.stderr b/tests/ui/offload/type_mismatch.stderr index 8cf160ca09486..808768e7cd4f3 100644 --- a/tests/ui/offload/type_mismatch.stderr +++ b/tests/ui/offload/type_mismatch.stderr @@ -1,37 +1,37 @@ error: expected a function item for the offload kernel, found `i32` --> $DIR/type_mismatch.rs:8:5 | -LL | core::intrinsics::offload::<_, _, ()>(not_fn, [1, 1, 1], [1, 1, 1], 0, ()); +LL | core::intrinsics::offload::<_, _, ()>(not_fn, [1, 1, 1], [1, 1, 1], 0, -1, ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: offload kernel expects 1 arguments, but 0 arguments were provided --> $DIR/type_mismatch.rs:12:5 | -LL | core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, ()); +LL | core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, -1, ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type mismatch in offload kernel argument 0: expected `f32`, found `f64` --> $DIR/type_mismatch.rs:16:5 | -LL | core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, (42.0f64,)); +LL | core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, -1, (42.0f64,)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: offload kernel return type mismatch: kernel returns `()`, but offload call expects `f64` --> $DIR/type_mismatch.rs:20:18 | -LL | let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, ()); +LL | let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, -1, ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type mismatch in offload kernel argument 0: expected `f32`, found `f64` --> $DIR/type_mismatch.rs:24:5 | -LL | core::intrinsics::offload::<_, _, ()>(kernel_2, [1, 1, 1], [1, 1, 1], 0, (42.0f64, 42.0f64)); +LL | core::intrinsics::offload::<_, _, ()>( | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type mismatch in offload kernel argument 1: expected `f32`, found `f64` --> $DIR/type_mismatch.rs:24:5 | -LL | core::intrinsics::offload::<_, _, ()>(kernel_2, [1, 1, 1], [1, 1, 1], 0, (42.0f64, 42.0f64)); +LL | core::intrinsics::offload::<_, _, ()>( | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors From ed486fb5181457e5dce84e7d6cb551e31e06e033 Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Sun, 16 Aug 2026 14:40:02 +0100 Subject: [PATCH 04/32] Add a regression test for a panicking proc macro used as an inner attribute --- tests/ui/proc-macro/auxiliary/panicking-attribute.rs | 8 ++++++++ tests/ui/proc-macro/panicking-inner-attribute-macro.rs | 8 ++++++++ .../proc-macro/panicking-inner-attribute-macro.stderr | 10 ++++++++++ 3 files changed, 26 insertions(+) create mode 100644 tests/ui/proc-macro/auxiliary/panicking-attribute.rs create mode 100644 tests/ui/proc-macro/panicking-inner-attribute-macro.rs create mode 100644 tests/ui/proc-macro/panicking-inner-attribute-macro.stderr diff --git a/tests/ui/proc-macro/auxiliary/panicking-attribute.rs b/tests/ui/proc-macro/auxiliary/panicking-attribute.rs new file mode 100644 index 0000000000000..f5544030b8ec5 --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/panicking-attribute.rs @@ -0,0 +1,8 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn tester(_: TokenStream, _: TokenStream) -> TokenStream { + panic!(); +} diff --git a/tests/ui/proc-macro/panicking-inner-attribute-macro.rs b/tests/ui/proc-macro/panicking-inner-attribute-macro.rs new file mode 100644 index 0000000000000..2fef1cb83135a --- /dev/null +++ b/tests/ui/proc-macro/panicking-inner-attribute-macro.rs @@ -0,0 +1,8 @@ +//! Regression test for . + +//@ proc-macro: panicking-attribute.rs +//@ compile-flags: --crate-type=lib + +#![feature(custom_inner_attributes)] +#![panicking_attribute::tester] +//~^ ERROR custom attribute panicked diff --git a/tests/ui/proc-macro/panicking-inner-attribute-macro.stderr b/tests/ui/proc-macro/panicking-inner-attribute-macro.stderr new file mode 100644 index 0000000000000..cbfb29ad1ef89 --- /dev/null +++ b/tests/ui/proc-macro/panicking-inner-attribute-macro.stderr @@ -0,0 +1,10 @@ +error: custom attribute panicked + --> $DIR/panicking-inner-attribute-macro.rs:7:1 + | +LL | #![panicking_attribute::tester] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: message: explicit panic + +error: aborting due to 1 previous error + From 652eb8425c3177c2b4617f08c91fbcfefa42a795 Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Sun, 16 Aug 2026 17:10:01 +0100 Subject: [PATCH 05/32] Add a regression test for a `macro_rules!` generated by another crate's `macro_rules!` --- .../nested-macro-rules-definition.rs | 15 +++++++++++ .../cross-crate-nested-macro-rules-span.rs | 18 +++++++++++++ ...cross-crate-nested-macro-rules-span.stderr | 27 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 tests/ui/macros/auxiliary/nested-macro-rules-definition.rs create mode 100644 tests/ui/macros/cross-crate-nested-macro-rules-span.rs create mode 100644 tests/ui/macros/cross-crate-nested-macro-rules-span.stderr diff --git a/tests/ui/macros/auxiliary/nested-macro-rules-definition.rs b/tests/ui/macros/auxiliary/nested-macro-rules-definition.rs new file mode 100644 index 0000000000000..cb980fd3d9274 --- /dev/null +++ b/tests/ui/macros/auxiliary/nested-macro-rules-definition.rs @@ -0,0 +1,15 @@ +pub struct ProjectileCreated; +pub struct NotificationChannel(std::marker::PhantomData); + +// The inner `macro_rules!` is what later reports a span from this crate while the +// diagnostic is being rendered against the downstream crate's source. +macro_rules! define_trigger_system { + ($(( $field:ident, $ty:ident, $channel:ident )),* $(,)?) => { + #[macro_export] + macro_rules! all_trigger_fields { + ($submacro:ident) => { $submacro!($( ( $field, $ty, $channel ) ),*) } + } + }; +} + +define_trigger_system!((projectile_created, ProjectileCreated, NotificationChannel),); diff --git a/tests/ui/macros/cross-crate-nested-macro-rules-span.rs b/tests/ui/macros/cross-crate-nested-macro-rules-span.rs new file mode 100644 index 0000000000000..9353398093ff8 --- /dev/null +++ b/tests/ui/macros/cross-crate-nested-macro-rules-span.rs @@ -0,0 +1,18 @@ +//! Regression test for . + +//@ aux-build: nested-macro-rules-definition.rs + +extern crate nested_macro_rules_definition; +use nested_macro_rules_definition::*; + +macro_rules! make_event_subscription { + ($(( $field:ident, $ty:ident, $channel:ident )),*) => { + pub struct EventSubscription($($channel::ReaderId),*); + //~^ ERROR ambiguous associated type + }; +} + +all_trigger_fields!(make_event_subscription); +//~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon + +fn main() {} diff --git a/tests/ui/macros/cross-crate-nested-macro-rules-span.stderr b/tests/ui/macros/cross-crate-nested-macro-rules-span.stderr new file mode 100644 index 0000000000000..edf3d575b972d --- /dev/null +++ b/tests/ui/macros/cross-crate-nested-macro-rules-span.stderr @@ -0,0 +1,27 @@ +error: macros that expand to items must be delimited with braces or followed by a semicolon + --> $DIR/cross-crate-nested-macro-rules-span.rs:15:1 + | +LL | all_trigger_fields!(make_event_subscription); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `all_trigger_fields` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0223]: ambiguous associated type + --> $DIR/cross-crate-nested-macro-rules-span.rs:10:40 + | +LL | pub struct EventSubscription($($channel::ReaderId),*); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | all_trigger_fields!(make_event_subscription); + | -------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `make_event_subscription` which comes from the expansion of the macro `all_trigger_fields` (in Nightly builds, run with -Z macro-backtrace for more info) +help: if there were a trait named `Example` with associated type `ReaderId` implemented for `nested_macro_rules_definition::NotificationChannel`, you could use the fully-qualified path + | +LL - pub struct EventSubscription($($channel::ReaderId),*); +LL + pub struct EventSubscription($( as Example>::ReaderId),*); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0223`. From d9d3a215af9af24d4be9d474f9cbed89363f9188 Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Sun, 16 Aug 2026 17:15:19 +0100 Subject: [PATCH 06/32] Add a regression test for full LTO against `rustc_private` --- tests/ui-fulldeps/lto-with-rustc-private.rs | 14 ++++++++++++++ tests/ui-fulldeps/lto-with-rustc-private.stderr | 2 ++ 2 files changed, 16 insertions(+) create mode 100644 tests/ui-fulldeps/lto-with-rustc-private.rs create mode 100644 tests/ui-fulldeps/lto-with-rustc-private.stderr diff --git a/tests/ui-fulldeps/lto-with-rustc-private.rs b/tests/ui-fulldeps/lto-with-rustc-private.rs new file mode 100644 index 0000000000000..7695d5b6ea1cc --- /dev/null +++ b/tests/ui-fulldeps/lto-with-rustc-private.rs @@ -0,0 +1,14 @@ +//! Regression test for . + +//@ build-fail +//@ compile-flags: -Clto +//@ normalize-stderr: "error: crate .* required.*\n( .*\n)*\n" -> "" +//@ normalize-stderr: "aborting due to [0-9]+" -> "aborting due to NUMBER" +//@ dont-require-annotations: ERROR + +#![feature(rustc_private)] + +extern crate rustc_errors; +//~? ERROR crate `rustc_errors` required to be available in rlib format + +fn main() {} diff --git a/tests/ui-fulldeps/lto-with-rustc-private.stderr b/tests/ui-fulldeps/lto-with-rustc-private.stderr new file mode 100644 index 0000000000000..58577ffffb3f6 --- /dev/null +++ b/tests/ui-fulldeps/lto-with-rustc-private.stderr @@ -0,0 +1,2 @@ +error: aborting due to NUMBER previous errors + From f18340b169b91ad11abb55447f464544b2ac4005 Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Sun, 16 Aug 2026 17:38:22 +0100 Subject: [PATCH 07/32] Add a regression test for eliding the middle of a span containing hard tabs --- .../elided-span-with-hard-tabs.rs | 11 +++++++++++ .../elided-span-with-hard-tabs.stderr | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/ui/diagnostic-width/elided-span-with-hard-tabs.rs create mode 100644 tests/ui/diagnostic-width/elided-span-with-hard-tabs.stderr diff --git a/tests/ui/diagnostic-width/elided-span-with-hard-tabs.rs b/tests/ui/diagnostic-width/elided-span-with-hard-tabs.rs new file mode 100644 index 0000000000000..d455da13fef83 --- /dev/null +++ b/tests/ui/diagnostic-width/elided-span-with-hard-tabs.rs @@ -0,0 +1,11 @@ +//! Regression test for . + +// The panic happens while the JSON emitter fills in its `rendered` field, which is the +// path `cargo` takes, so this has to be checked with the default JSON error format. +//@ compile-flags: --diagnostic-width=30 +// ignore-tidy-file-tab + +fn main() { + let _: &[u8] = [0, 0]; + //~^ ERROR mismatched types +} diff --git a/tests/ui/diagnostic-width/elided-span-with-hard-tabs.stderr b/tests/ui/diagnostic-width/elided-span-with-hard-tabs.stderr new file mode 100644 index 0000000000000..6415675e5a69d --- /dev/null +++ b/tests/ui/diagnostic-width/elided-span-with-hard-tabs.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/elided-span-with-hard-tabs.rs:9:20 + | +LL | ..._: &[u8] = [0, ... 0]; + | ----- ^^^^^^^^...^^^^^^^^ expected `&[u8]`, found `[{integer}; 2]` + | | + | expected due to this + | +help: consider borrowing here + | +LL | let _: &[u8] = &[0, 0]; + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From dd69e6bd7cbe5c4ad6ab85f131f8724c9275d95e Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 18 Aug 2026 14:27:44 +0200 Subject: [PATCH 08/32] std: don't panic on long-elapsed deadlines for `sleep_until` --- library/std/src/sys/thread/unix.rs | 24 ++++++++++++++++++++++-- library/std/src/thread/tests.rs | 9 +++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 2dbb0314cb271..831c4e0787841 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -650,6 +650,26 @@ pub fn sleep(dur: Duration) { pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; + let timespec = deadline.into_inner().into_timespec(); + if timespec.tv_sec < 0 { + // `clock_nanosleep` fails with EINVAL if + // > The tp argument to clock_settime() is outside the range for the + // > given clock ID. + // + // This specification allows *any* clock range, which means we'd + // theoretically have to detect whether the time point is in the + // future (and block indefinitely) or the past (and return immediately) + // when encountering `EINVAL`. But since all existing implementations + // interpret this as saying that negative `tv_sec` values are unsupported, + // we can just test that and return – given that POSIX specifies that + // `CLOCK_MONOTONIC` measures the time "since an unspecified amount + // in the past" negative values are definitely in the past. If you + // observe any platform returning `EINVAL` for more cases, please + // file a bug; we'd need to add logic handling `EINVAL` when it + // occurs. + return; + } + #[cfg(all( target_os = "linux", target_env = "gnu", @@ -672,7 +692,7 @@ pub fn sleep_until(deadline: crate::time::Instant) { } if let Some(clock_nanosleep) = __clock_nanosleep_time64.get() { - let ts = deadline.into_inner().into_timespec().to_timespec64(); + let ts = timespec.to_timespec64(); loop { let r = unsafe { clock_nanosleep( @@ -700,7 +720,7 @@ pub fn sleep_until(deadline: crate::time::Instant) { } } - let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else { + let Some(ts) = timespec.to_timespec() else { // The deadline is further in the future then can be passed to // clock_nanosleep. We have to use Self::sleep instead. This might // happen on 32 bit platforms, especially closer to 2038. diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 78b6f7c35e8db..e88ca92218dc8 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -333,6 +333,15 @@ fn sleep_ms_smoke() { thread::sleep(Duration::from_millis(2)); } +#[test] +fn sleep_until_elapsed() { + // UNIX's `clock_nanosleep` doesn't like timeouts that are too far back. + // Test that `sleep_until` returns immediately instead of panicking. + // Going 10 years back should be enough to trigger any errors. + let earlier = Instant::now() - Duration::from_secs(10 * 365 * 24 * 3600); + thread::sleep_until(earlier); +} + #[test] fn test_size_of_option_thread_id() { assert_eq!(size_of::>(), size_of::()); From 167587263c6b117ffba5bb0f4e4ffcf8c78fef83 Mon Sep 17 00:00:00 2001 From: "Bang, Ly {MMSL~BASEL}" Date: Tue, 18 Aug 2026 21:03:17 +0700 Subject: [PATCH 09/32] Add regression test for inconsistent import resolution from issue 147208 --- ...ion-with-import-separators-issue-147208.rs | 18 +++++++++++ ...with-import-separators-issue-147208.stderr | 32 +++++++++++++++++++ ...istent-resolution-with-mod-issue-147208.rs | 13 ++++++++ ...nt-resolution-with-mod-issue-147208.stderr | 19 +++++++++++ 4 files changed, 82 insertions(+) create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-with-import-separators-issue-147208.rs create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-with-import-separators-issue-147208.stderr create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-with-mod-issue-147208.rs create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-with-mod-issue-147208.stderr diff --git a/tests/ui/resolve/ice-inconsistent-resolution-with-import-separators-issue-147208.rs b/tests/ui/resolve/ice-inconsistent-resolution-with-import-separators-issue-147208.rs new file mode 100644 index 0000000000000..e6c76aaa4f1f2 --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-with-import-separators-issue-147208.rs @@ -0,0 +1,18 @@ +//@ edition: 2024 + +// Regression test for issue https://github.com/rust-lang/rust/issues/147208 +// Fix by https://github.com/rust-lang/rust/pull/149681 + +use foo::bar::E::*; + //~^ ERROR cannot find module or crate `foo` in this scope +use foo::bar::test_use::io as std_io; + //~^ ERROR cannot find module or crate `foo` in this scope + //~| ERROR unresolved import `foo::bar::test_use::io` +fn main() { + Foo(()); + //~^ ERROR cannot find function, tuple struct or tuple variant `Foo` in this scope + { + use ::std::io as std_io; + use std_io::stdout; + } +} diff --git a/tests/ui/resolve/ice-inconsistent-resolution-with-import-separators-issue-147208.stderr b/tests/ui/resolve/ice-inconsistent-resolution-with-import-separators-issue-147208.stderr new file mode 100644 index 0000000000000..a7c6dc95cee70 --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-with-import-separators-issue-147208.stderr @@ -0,0 +1,32 @@ +error[E0433]: cannot find module or crate `foo` in this scope + --> $DIR/ice-inconsistent-resolution-with-import-separators-issue-147208.rs:6:5 + | +LL | use foo::bar::E::*; + | ^^^ use of unresolved module or unlinked crate `foo` + | + = help: you might be missing a crate named `foo` + +error[E0433]: cannot find module or crate `foo` in this scope + --> $DIR/ice-inconsistent-resolution-with-import-separators-issue-147208.rs:8:5 + | +LL | use foo::bar::test_use::io as std_io; + | ^^^ use of unresolved module or unlinked crate `foo` + | + = help: you might be missing a crate named `foo` + +error[E0432]: unresolved import `foo::bar::test_use::io` + --> $DIR/ice-inconsistent-resolution-with-import-separators-issue-147208.rs:8:5 + | +LL | use foo::bar::test_use::io as std_io; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0425]: cannot find function, tuple struct or tuple variant `Foo` in this scope + --> $DIR/ice-inconsistent-resolution-with-import-separators-issue-147208.rs:12:5 + | +LL | Foo(()); + | ^^^ not found in this scope + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0425, E0432, E0433. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/ice-inconsistent-resolution-with-mod-issue-147208.rs b/tests/ui/resolve/ice-inconsistent-resolution-with-mod-issue-147208.rs new file mode 100644 index 0000000000000..2797497da80c0 --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-with-mod-issue-147208.rs @@ -0,0 +1,13 @@ +//@ edition: 2024 + +// Regression test for issue https://github.com/rust-lang/rust/issues/147208 +// Fix by https://github.com/rust-lang/rust/pull/149681 + +use bar::foo; + //~^ ERROR unresolved import `bar` +use foo::bar; +fn main() { + mod bar; + //~^ ERROR cannot declare a file module inside a block unless it has a path attribute + use bar::foo; +} diff --git a/tests/ui/resolve/ice-inconsistent-resolution-with-mod-issue-147208.stderr b/tests/ui/resolve/ice-inconsistent-resolution-with-mod-issue-147208.stderr new file mode 100644 index 0000000000000..e5d293630cdfa --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-with-mod-issue-147208.stderr @@ -0,0 +1,19 @@ +error: cannot declare a file module inside a block unless it has a path attribute + --> $DIR/ice-inconsistent-resolution-with-mod-issue-147208.rs:10:5 + | +LL | mod bar; + | ^^^^^^^^ + | + = note: file modules are usually placed outside of blocks, at the top level of the file + +error[E0432]: unresolved import `bar` + --> $DIR/ice-inconsistent-resolution-with-mod-issue-147208.rs:6:5 + | +LL | use bar::foo; + | ^^^ use of unresolved module or unlinked crate `bar` + | + = help: you might be missing a crate named `bar` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. From d448db857bab7cb03ca9c82f23acfcfa86f0b6c8 Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Sun, 16 Aug 2026 17:55:07 +0100 Subject: [PATCH 10/32] Add a regression test for wrapping arithmetic under MIR optimisations --- .../numbers-arithmetic/wrapping-ops-under-mir-opts.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/ui/numbers-arithmetic/wrapping-ops-under-mir-opts.rs diff --git a/tests/ui/numbers-arithmetic/wrapping-ops-under-mir-opts.rs b/tests/ui/numbers-arithmetic/wrapping-ops-under-mir-opts.rs new file mode 100644 index 0000000000000..ab0e48f51be6f --- /dev/null +++ b/tests/ui/numbers-arithmetic/wrapping-ops-under-mir-opts.rs @@ -0,0 +1,11 @@ +//! Regression test for . + +//@ run-pass +//@ compile-flags: -Zmir-opt-level=2 -Coverflow-checks=on + +fn main() { + assert_eq!(1_u32.wrapping_sub(2), u32::MAX); + assert_eq!(u32::MAX.wrapping_add(2), 1); + assert_eq!(i32::MIN.wrapping_sub(1), i32::MAX); + assert_eq!(2_u32.wrapping_mul(u32::MAX), u32::MAX - 1); +} From ceeaac0ba45fd7d63e7d3763c2bd36df301be6f9 Mon Sep 17 00:00:00 2001 From: zakrad <49591476+zakrad@users.noreply.github.com> Date: Wed, 19 Aug 2026 01:15:32 +0330 Subject: [PATCH 11/32] Add regression test for nested RPIT not-an-iterator ICE --- .../nested-rpit-not-iterator-ice-159559.rs | 19 +++++++++++++++++++ ...nested-rpit-not-iterator-ice-159559.stderr | 12 ++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/ui/impl-trait/nested-rpit-not-iterator-ice-159559.rs create mode 100644 tests/ui/impl-trait/nested-rpit-not-iterator-ice-159559.stderr diff --git a/tests/ui/impl-trait/nested-rpit-not-iterator-ice-159559.rs b/tests/ui/impl-trait/nested-rpit-not-iterator-ice-159559.rs new file mode 100644 index 0000000000000..03842bc36db7a --- /dev/null +++ b/tests/ui/impl-trait/nested-rpit-not-iterator-ice-159559.rs @@ -0,0 +1,19 @@ +//! Regression test for . +//! Reporting the `E0277` for the unsatisfied `IntoIterator` bound on the +//! nested opaque type used to ICE ("Normalizing ... without wrapping in a +//! `Binder`") in the RPIT method-chain suggestion when the return type +//! captures a lifetime. + +trait Cap<'a> {} + +impl Cap<'_> for T {} + +fn fail_late_bound<'a>( + a: &u8, + _: &'a u8, +) -> impl IntoIterator + IntoIterator>> { + //~^ ERROR `&u8` is not an iterator + [a] +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested-rpit-not-iterator-ice-159559.stderr b/tests/ui/impl-trait/nested-rpit-not-iterator-ice-159559.stderr new file mode 100644 index 0000000000000..4ba03ed69999c --- /dev/null +++ b/tests/ui/impl-trait/nested-rpit-not-iterator-ice-159559.stderr @@ -0,0 +1,12 @@ +error[E0277]: `&u8` is not an iterator + --> $DIR/nested-rpit-not-iterator-ice-159559.rs:14:31 + | +LL | ) -> impl IntoIterator + IntoIterator>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&u8` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&u8` + = note: required for `&u8` to implement `IntoIterator` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 8ac67c56c1a3ecab81dfc4180c4f83bb970f0b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 19 Aug 2026 13:29:51 +0200 Subject: [PATCH 12/32] Cleanup: Move impl of `#[rustc_dump_object_lifetime_defaults]` --- .../rustc_hir_analysis/src/collect/dump.rs | 25 +++++++++++++++++++ compiler/rustc_hir_analysis/src/lib.rs | 11 +++++--- compiler/rustc_passes/src/check_attr.rs | 22 +--------------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index b1b8b513f3b35..772bbe4a6b579 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -3,6 +3,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::{find_attr, intravisit}; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, Unnormalized}; use rustc_span::sym; @@ -25,6 +26,30 @@ pub(crate) fn generics(tcx: TyCtxt<'_>) { } } +pub(crate) fn object_lifetime_defaults(tcx: TyCtxt<'_>) { + for def_id in tcx.hir_crate_items(()).definitions() { + if def_id == hir::def_id::CRATE_DEF_ID { + continue; + } + + if !find_attr!(tcx, def_id, RustcDumpObjectLifetimeDefaults) { + continue; + } + + for param in &tcx.generics_of(def_id).own_params { + let ty::GenericParamDefKind::Type { .. } = param.kind else { continue }; + let default = tcx.object_lifetime_default(param.def_id); + let repr = match default { + ObjectLifetimeDefault::Empty => "Empty".to_owned(), + ObjectLifetimeDefault::Static => "'static".to_owned(), + ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), + ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), + }; + tcx.dcx().span_err(tcx.def_span(param.def_id), repr); + } + } +} + pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { if !find_attr!(tcx, crate, RustcDumpHiddenTypeOfOpaques) { return; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 572200dbd7634..7121b4b654cfe 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -203,13 +203,16 @@ pub fn check_crate(tcx: TyCtxt<'_>) { if tcx.features().rustc_attrs() { tcx.sess.time("dumping_rustc_attr_data", || { - outlives::dump::inferred_outlives(tcx); - variance::dump::variances(tcx); - collect::dump::generics(tcx); - collect::dump::opaque_hidden_types(tcx); + // tidy-alphabetical-start collect::dump::clauses_and_item_bounds(tcx); collect::dump::def_parents(tcx); + collect::dump::generics(tcx); + collect::dump::object_lifetime_defaults(tcx); + collect::dump::opaque_hidden_types(tcx); collect::dump::vtables(tcx); + outlives::dump::inferred_outlives(tcx); + variance::dump::variances(tcx); + // tidy-alphabetical-end }); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d9099cadaece8..1fe16d294433c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -30,7 +30,6 @@ use rustc_hir::{ }; use rustc_macros::Diagnostic; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -195,9 +194,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Deprecated { span: attr_span, .. } => { self.check_deprecated(hir_id, *attr_span, target) } - AttributeKind::RustcDumpObjectLifetimeDefaults => { - self.check_dump_object_lifetime_defaults(hir_id); - } AttributeKind::Naked(..) => self.check_naked(hir_id, target), AttributeKind::NonExhaustive(attr_span) => { self.check_non_exhaustive(*attr_span, span, target, item) @@ -337,6 +333,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcDumpInferredOutlives => (), AttributeKind::RustcDumpItemBounds => (), AttributeKind::RustcDumpLayout(..) => (), + AttributeKind::RustcDumpObjectLifetimeDefaults => (), AttributeKind::RustcDumpSymbolName(..) => (), AttributeKind::RustcDumpUserArgs => (), AttributeKind::RustcDumpVariances => (), @@ -785,23 +782,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Debugging aid for the `object_lifetime_default` query. - fn check_dump_object_lifetime_defaults(&self, hir_id: HirId) { - let tcx = self.tcx; - let Some(owner_id) = hir_id.as_owner() else { return }; - for param in &tcx.generics_of(owner_id.def_id).own_params { - let ty::GenericParamDefKind::Type { .. } = param.kind else { continue }; - let default = tcx.object_lifetime_default(param.def_id); - let repr = match default { - ObjectLifetimeDefault::Empty => "Empty".to_owned(), - ObjectLifetimeDefault::Static => "'static".to_owned(), - ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), - ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), - }; - tcx.dcx().span_err(tcx.def_span(param.def_id), repr); - } - } - /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. fn check_non_exhaustive( &self, From eae69d81bc730cdde441312201d3a00f3b87ef34 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 19 Aug 2026 14:49:31 +0200 Subject: [PATCH 13/32] Add file path to some archive build errors This would have been useful to have while debugging a problem in cg_clif. --- .../rustc_codegen_ssa/src/back/archive.rs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index c4107b4a60f27..6c4575caebd8e 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -623,8 +623,9 @@ impl<'a> ArArchiveBuilder<'a> { io::Error::new( io::ErrorKind::InvalidData, format!( - "archive member at offset {start} with size {} \ + "archive member of {} at offset {start} with size {} \ exceeds archive size {} in `{}`", + src_archive.0.display(), file_range.1, archive_data.len(), src_archive.0.display(), @@ -642,11 +643,18 @@ impl<'a> ArArchiveBuilder<'a> { } } ArchiveEntrySource::File(file) => unsafe { - let mmap = Mmap::map( - File::open(file) - .map_err(|err| io_error_context("failed to open object file", err))?, - ) - .map_err(|err| io_error_context("failed to map object file", err))?; + let mmap = Mmap::map(File::open(&file).map_err(|err| { + io_error_context( + &format!("failed to open object file {}", file.display()), + err, + ) + })?) + .map_err(|err| { + io_error_context( + &format!("failed to map object file {}", file.display()), + err, + ) + })?; if entry.kind == ArchiveEntryKind::RustObj && let Some(sym) = &symbols { From f151cb926f92e4a9de37baa01c167aba4ba50ff5 Mon Sep 17 00:00:00 2001 From: Rohan Singla Date: Wed, 8 Jul 2026 05:09:45 +0530 Subject: [PATCH 14/32] diagnostics: fix `let x: vec![]` suggestion pointing into stdlib When a macro call like `vec![]` appears in type position, the compiler's "use `=` if you meant to assign" suggestion was pointing into the macro definition in stdlib instead of the user's own code. The suggestion span was computed as `stmt.pat.span.between(hir_ty.span)`. After expansion `hir_ty.span` lies inside the macro body, so that span crossed syntax contexts and the renderer displayed the stdlib location. Compute the span via `find_ancestor_in_same_ctxt` instead, so the pattern and the type are compared in a common syntax context. When no common context exists -- e.g. the `let` comes from a macro body while the pattern is a call-site metavariable -- no suggestion is emitted at all. --- .../src/hir_ty_lowering/errors.rs | 18 +++++++++ .../src/hir_ty_lowering/mod.rs | 40 ++++++++++--------- .../let-binding-init-expr-as-ty.rs | 11 +++++ .../let-binding-init-expr-as-ty.stderr | 35 +++++++++++++--- 4 files changed, 79 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index e5dbae16d07d4..7d07139a9077e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -2055,3 +2055,21 @@ fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str { ty::AssocTag::Type => "type", } } + +/// Computes the `pat.between(ty)` span for the "use `=`" suggestion on `let pat: ty`. +/// Returns `None` if `pat` and `ty` are in incompatible macro contexts (e.g. `pat` is a +/// metavariable from the call site while `ty` lives in the macro body), in which case no +/// suggestion is emitted. +pub(crate) fn eq_ctxt_suggestion_span(pat: Span, ty: Span) -> Option { + if let Some(ty2) = ty.find_ancestor_in_same_ctxt(pat) + && pat.hi() <= ty2.lo() + { + return Some(pat.between(ty2)); + } + if let Some(pat2) = pat.find_ancestor_in_same_ctxt(ty) + && pat2.hi() <= ty.lo() + { + return Some(pat2.between(ty)); + } + None +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index c65e9bdbd211e..8256ef6442057 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -56,7 +56,9 @@ use tracing::{debug, instrument}; use crate::check::check_abi; use crate::check_c_variadic_abi; use crate::diagnostics::{self, BadReturnTypeNotation, NoFieldOnType, NoVariantNamed}; -use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; +use crate::hir_ty_lowering::errors::{ + GenericsArgsErrExtend, eq_ctxt_suggestion_span, prohibit_assoc_item_constraint, +}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -3302,18 +3304,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .next() { // `let x: S::new(valid_in_ty_ctxt);` -> `let x = S::new(valid_in_ty_ctxt);` - let err = tcx - .dcx() - .struct_span_err( - hir_ty.span, - "expected type, found associated function call", - ) - .with_span_suggestion_verbose( - stmt.pat.span.between(hir_ty.span), + let mut err = tcx.dcx().struct_span_err( + hir_ty.span, + "expected type, found associated function call", + ); + if let Some(between) = eq_ctxt_suggestion_span(stmt.pat.span, hir_ty.span) { + err.span_suggestion_verbose( + between, "use `=` if you meant to assign", - " = ".to_string(), + " = ", Applicability::MaybeIncorrect, ); + } self.dcx().try_steal_replace_and_emit_err( hir_ty.span, StashKey::ReturnTypeNotation, @@ -3328,18 +3330,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { // `let x: i32::something(valid_in_ty_ctxt);` -> `let x = i32::something(valid_in_ty_ctxt);` // FIXME: Check that `something` is a valid function in `i32`. - let err = tcx - .dcx() - .struct_span_err( - hir_ty.span, - "expected type, found associated function call", - ) - .with_span_suggestion_verbose( - stmt.pat.span.between(hir_ty.span), + let mut err = tcx.dcx().struct_span_err( + hir_ty.span, + "expected type, found associated function call", + ); + if let Some(between) = eq_ctxt_suggestion_span(stmt.pat.span, hir_ty.span) { + err.span_suggestion_verbose( + between, "use `=` if you meant to assign", - " = ".to_string(), + " = ", Applicability::MaybeIncorrect, ); + } self.dcx().try_steal_replace_and_emit_err( hir_ty.span, StashKey::ReturnTypeNotation, diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs index 22240d02d7fd2..b70bf5572a57c 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs @@ -28,6 +28,17 @@ fn main() { //~^ ERROR return type notation is experimental let x: S::new(()); //~ ERROR expected type, found associated function call + // Macros — suggestion must point at user code, not the macro definition (#158492) + let x: vec![]; //~ ERROR expected type, found associated function call + + // When the `let` is inside a macro, no suggestion should be emitted at the call site + macro_rules! make { + ($pat:pat) => { + let $pat: Vec::new(); //~ ERROR expected type, found associated function call + }; + } + make!(_); + // Literals let x: 42; //~ ERROR expected type, found `42` let x: ""; //~ ERROR expected type, found `""` diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr index c096fd8c5556e..35198467409e8 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr @@ -1,5 +1,5 @@ error: expected type, found `42` - --> $DIR/let-binding-init-expr-as-ty.rs:32:12 + --> $DIR/let-binding-init-expr-as-ty.rs:43:12 | LL | let x: 42; | - ^^ expected type @@ -13,7 +13,7 @@ LL + let x = 42; | error: expected type, found `""` - --> $DIR/let-binding-init-expr-as-ty.rs:33:12 + --> $DIR/let-binding-init-expr-as-ty.rs:44:12 | LL | let x: ""; | - ^^ expected type @@ -40,7 +40,7 @@ LL + let foo = i32::from_be(num); | error[E0573]: cannot find type `bar` in this scope - --> $DIR/let-binding-init-expr-as-ty.rs:36:12 + --> $DIR/let-binding-init-expr-as-ty.rs:47:12 | LL | let x: bar(); | ^^^ not found in this scope @@ -53,7 +53,7 @@ LL + let x = bar(); | error[E0573]: cannot find type `bar` in this scope - --> $DIR/let-binding-init-expr-as-ty.rs:37:12 + --> $DIR/let-binding-init-expr-as-ty.rs:48:12 | LL | let x: bar; | ^^^ not found in this scope @@ -61,7 +61,7 @@ LL | let x: bar; = note: a function named `bar` exists in another namespace error[E0573]: cannot find type `x` in this scope - --> $DIR/let-binding-init-expr-as-ty.rs:40:12 + --> $DIR/let-binding-init-expr-as-ty.rs:51:12 | LL | struct K(S::new(())); | --------------------- similarly named struct `K` defined here @@ -158,7 +158,30 @@ LL - let x: S::new(()); LL + let x = S::new(()); | -error: aborting due to 13 previous errors +error: expected type, found associated function call + --> $DIR/let-binding-init-expr-as-ty.rs:32:12 + | +LL | let x: vec![]; + | ^^^^^^ + | +help: use `=` if you meant to assign + | +LL - let x: vec![]; +LL + let x = vec![]; + | + +error: expected type, found associated function call + --> $DIR/let-binding-init-expr-as-ty.rs:37:23 + | +LL | let $pat: Vec::new(); + | ^^^^^^^^^^ +... +LL | make!(_); + | -------- in this macro invocation + | + = note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 15 previous errors Some errors have detailed explanations: E0573, E0658. For more information about an error, try `rustc --explain E0573`. From d827d4476c5b864fd2a65e2fc1842fbabbd80e8a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 19 Aug 2026 18:29:40 +0000 Subject: [PATCH 15/32] Uplift rustfmt macro formatting fix --- src/tools/rustfmt/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index e4c05d58004a7..8bfd99f2f7c9f 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -454,7 +454,7 @@ pub(crate) fn rewrite_macro_def( }; let mut header = if def.macro_rules { - let pos = context.snippet_provider.span_after(span, "macro_rules!"); + let pos = context.snippet_provider.span_after(span, "!"); vec![HeaderPart::new("macro_rules!", span.with_hi(pos))] } else { let macro_lo = context.snippet_provider.span_before(span, "macro"); From 3777642175b402d20d3957ba98ce49b31ed424fb Mon Sep 17 00:00:00 2001 From: Marcelo Dominguez Date: Fri, 14 Aug 2026 18:04:13 +0300 Subject: [PATCH 16/32] Update with macro and some tweaks --- .../src/builder/gpu_offload.rs | 6 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 9 +-- library/core/src/offload.md | 3 +- library/core/src/offload/mod.rs | 62 +++++++++++++------ .../codegen-llvm/gpu_offload/control_flow.rs | 16 +++-- .../codegen-llvm/gpu_offload/device_check.rs | 30 +++++++++ tests/codegen-llvm/gpu_offload/gpu_host.rs | 13 ++-- tests/codegen-llvm/gpu_offload/scalar_host.rs | 14 ++--- tests/codegen-llvm/gpu_offload/slice_host.rs | 14 ++--- .../offload-generic-manifest/generic.rs | 12 +++- tests/ui/offload/check_config.rs | 7 ++- tests/ui/offload/offload_macro.rs | 3 + tests/ui/offload/offload_macro.stderr | 10 ++- tests/ui/offload/offload_negative_device.rs | 12 ++++ .../ui/offload/offload_negative_device.stderr | 19 ++++++ 15 files changed, 168 insertions(+), 62 deletions(-) create mode 100644 tests/codegen-llvm/gpu_offload/device_check.rs create mode 100644 tests/ui/offload/offload_negative_device.rs create mode 100644 tests/ui/offload/offload_negative_device.stderr diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index 4f8d918c72b51..d20a73e8e6825 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -197,7 +197,11 @@ fn generate_launcher<'ll>(cx: &CodegenCx<'ll, '_>) -> (&'ll llvm::Value, &'ll ll (tgt_decl, tgt_fn_ty) } -pub(crate) fn generate_decl<'ll>(cx: &CodegenCx<'ll, '_>) -> (&'ll llvm::Value, &'ll llvm::Type) { +/// Declares the `omp_get_num_devices` runtime function and returns the +/// declaration together with its type. +pub(crate) fn declare_omp_get_num_devices<'ll>( + cx: &CodegenCx<'ll, '_>, +) -> (&'ll llvm::Value, &'ll llvm::Type) { let ti32 = cx.type_i32(); let tgt_fn_ty = cx.type_func(&[], ti32); let name = "omp_get_num_devices"; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index fbd9a04ab2687..a5bb595d9b2c6 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -37,7 +37,7 @@ use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call}; use crate::builder::gpu_offload::{ - OffloadKernelDims, gen_call_handling, gen_define_handling, generate_decl, register_offload, + self, OffloadKernelDims, declare_omp_get_num_devices, register_offload, }; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; @@ -242,7 +242,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { return IntrinsicResult::WroteIntoPlace; } sym::offload_get_num_devices => { - let (fn_decl, fn_ty) = generate_decl(self.cx); + let (fn_decl, fn_ty) = declare_omp_get_num_devices(self.cx); let llval = self.call(fn_ty, None, None, fn_decl, &[], None, None); @@ -1893,8 +1893,9 @@ fn codegen_offload<'ll, 'tcx>( } }; register_offload(cx); - let offload_data = gen_define_handling(&cx, &metadata, target_symbol, offload_globals); - gen_call_handling( + let offload_data = + gpu_offload::gen_define_handling(&cx, &metadata, target_symbol, offload_globals); + gpu_offload::gen_call_handling( bx, &offload_data, &args, diff --git a/library/core/src/offload.md b/library/core/src/offload.md index 985a93a4294fa..726d0c7af1928 100644 --- a/library/core/src/offload.md +++ b/library/core/src/offload.md @@ -21,7 +21,8 @@ fn kernel(x: *mut [f64; 256]) { ``` To launch an offloaded kernel, use the `offload!` macro. It lets you specify the kernel, the -workgroup and thread dimensions, and the arguments to forward to the device. +workgroup and thread dimensions, the device to offload to, and the arguments to forward to the +device. ```rust,ignore (optional component) let mut x = [0.0f64; 256]; diff --git a/library/core/src/offload/mod.rs b/library/core/src/offload/mod.rs index 17ff74f0bbfbb..3d85621361209 100644 --- a/library/core/src/offload/mod.rs +++ b/library/core/src/offload/mod.rs @@ -19,6 +19,9 @@ pub use crate::offload; /// Defaults to `[1, 1, 1]`. /// - `dyn_cache`: The amount of dynamic shared memory, in bytes, to allocate for the kernel. /// Defaults to `0`. +/// - `device`: The index of the device to offload to. Must be `>= 0`. If omitted, the +/// default device is used. Use [`crate::intrinsics::offload_get_num_devices`] to discover +/// which device ids are valid. /// /// Each argument may only be specified once. /// @@ -43,61 +46,82 @@ macro_rules! offload { workgroup_dim = ([1, 1, 1]); thread_dim = ([1, 1, 1]); dyn_cache = (0); + device = NONE; args = NONE ) }; - (@munch [kernel = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = NONE; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; args = $a:tt) => { - $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = (SOME $val); workgroup_dim = $w; thread_dim = $t; dyn_cache = $d; args = $a) + (@munch [kernel = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = NONE; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => { + $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = (SOME $val); workgroup_dim = $w; thread_dim = $t; dyn_cache = $d; device = $device; args = $a) }; - (@munch [kernel = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = (SOME $old:expr); workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; args = $a:tt) => { + (@munch [kernel = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = (SOME $old:expr); workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => { compile_error!("duplicate field `kernel`") }; - (@munch [workgroup_dim = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = ([1, 1, 1]); thread_dim = $t:tt; dyn_cache = $d:tt; args = $a:tt) => { - $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = $k; workgroup_dim = (SOME $val); thread_dim = $t; dyn_cache = $d; args = $a) + (@munch [workgroup_dim = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = ([1, 1, 1]); thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => { + $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = $k; workgroup_dim = (SOME $val); thread_dim = $t; dyn_cache = $d; device = $device; args = $a) }; - (@munch [workgroup_dim = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = (SOME $old:expr); thread_dim = $t:tt; dyn_cache = $d:tt; args = $a:tt) => { + (@munch [workgroup_dim = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = (SOME $old:expr); thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => { compile_error!("duplicate field `workgroup_dim`") }; - (@munch [thread_dim = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = ([1, 1, 1]); dyn_cache = $d:tt; args = $a:tt) => { - $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = $k; workgroup_dim = $w; thread_dim = (SOME $val); dyn_cache = $d; args = $a) + (@munch [thread_dim = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = ([1, 1, 1]); dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => { + $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = $k; workgroup_dim = $w; thread_dim = (SOME $val); dyn_cache = $d; device = $device; args = $a) }; - (@munch [thread_dim = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = (SOME $old:expr); dyn_cache = $d:tt; args = $a:tt) => { + (@munch [thread_dim = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = (SOME $old:expr); dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => { compile_error!("duplicate field `thread_dim`") }; - (@munch [dyn_cache = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = (0); args = $a:tt) => { - $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = $k; workgroup_dim = $w; thread_dim = $t; dyn_cache = (SOME $val); args = $a) + (@munch [dyn_cache = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = (0); device = $device:tt; args = $a:tt) => { + $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = $k; workgroup_dim = $w; thread_dim = $t; dyn_cache = (SOME $val); device = $device; args = $a) }; - (@munch [dyn_cache = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = (SOME $old:expr); args = $a:tt) => { + (@munch [dyn_cache = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = (SOME $old:expr); device = $device:tt; args = $a:tt) => { compile_error!("duplicate field `dyn_cache`") }; - (@munch [args = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; args = NONE) => { - $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = $k; workgroup_dim = $w; thread_dim = $t; dyn_cache = $d; args = (SOME $val)) + (@munch [device = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = NONE; args = $a:tt) => { + $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = $k; workgroup_dim = $w; thread_dim = $t; dyn_cache = $d; device = (SOME $val); args = $a) }; - (@munch [args = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; args = (SOME $old:expr)) => { + (@munch [device = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = (SOME $old:expr); args = $a:tt) => { + compile_error!("duplicate field `device`") + }; + (@munch [args = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = NONE) => { + $crate::offload!(@munch [$($rest_f = $rest_v),*]; kernel = $k; workgroup_dim = $w; thread_dim = $t; dyn_cache = $d; device = $device; args = (SOME $val)) + }; + (@munch [args = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = (SOME $old:expr)) => { compile_error!("duplicate field `args`") }; - (@munch [$invalid:ident = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; args = $a:tt) => { + (@munch [$invalid:ident = $val:expr $(, $rest_f:ident = $rest_v:expr)*]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => { compile_error!(concat!("unknown field `", stringify!($invalid), "`")) }; - (@munch []; kernel = NONE; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; args = $a:tt) => { + (@munch []; kernel = NONE; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => { compile_error!("missing `kernel`") }; - (@munch []; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; args = NONE) => { + (@munch []; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = NONE) => { compile_error!("missing `args`") }; - (@munch []; kernel = (SOME $kernel:expr); workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; args = (SOME $args:expr)) => { + (@munch []; kernel = (SOME $kernel:expr); workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = (SOME $args:expr)) => { $crate::intrinsics::offload::<_, _, ()>( $kernel, $crate::offload!(@value $w), $crate::offload!(@value $t), $crate::offload!(@value $d), + $crate::offload!(@device $device), $args, ) }; (@value (SOME $val:expr)) => { $val }; (@value ($val:expr)) => { $val }; + + // if `device` is omitted (`NONE), we use the OpenMP default device (`-1`) + (@device NONE) => { -1 }; + (@device (SOME $val:expr)) => { { + const { $crate::assert!($val >= 0, "offload device must be non-negative; omit `device` to use the default device") }; + let device: i32 = $val; + $crate::assert!( + device < $crate::intrinsics::offload_get_num_devices(), + "offload device {} is not available", + device, + ); + device + } }; } diff --git a/tests/codegen-llvm/gpu_offload/control_flow.rs b/tests/codegen-llvm/gpu_offload/control_flow.rs index ef4881147e63b..8cafeda3395ce 100644 --- a/tests/codegen-llvm/gpu_offload/control_flow.rs +++ b/tests/codegen-llvm/gpu_offload/control_flow.rs @@ -6,8 +6,8 @@ // contains control flow. #![feature(abi_gpu_kernel)] +#![feature(gpu_offload)] #![feature(rustc_attrs)] -#![feature(core_intrinsics)] #![no_main] // CHECK: @.offload_sizes.[[K:[^ ]*foo]] = private unnamed_addr constant @@ -28,14 +28,12 @@ unsafe fn main() { let A = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]; for i in 0..100 { - core::intrinsics::offload::<_, _, ()>( - foo, - [256, 1, 1], - [32, 1, 1], - 0, - -1, - (A.as_ptr() as *const [f32; 6],), - ); + core::offload::offload! { + kernel = foo, + workgroup_dim = [256, 1, 1], + thread_dim = [32, 1, 1], + args = (A.as_ptr() as *const [f32; 6],), + } } } diff --git a/tests/codegen-llvm/gpu_offload/device_check.rs b/tests/codegen-llvm/gpu_offload/device_check.rs new file mode 100644 index 0000000000000..4eaa324a662a4 --- /dev/null +++ b/tests/codegen-llvm/gpu_offload/device_check.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -Zoffload=Test -Zunstable-options -C opt-level=0 -Clto=fat +//@ no-prefer-dynamic +//@ needs-offload + +// This test verifies that selecting an unavailable `device` in the `offload` macro panics. + +#![feature(gpu_offload)] +#![no_main] + +#[unsafe(no_mangle)] +fn main() { + core::offload::offload! { + kernel = kernel, + device = 99, + args = (), + } +} + +#[unsafe(no_mangle)] +fn kernel() {} + +// CHECK-LABEL: define{{( dso_local)?}} void @main() +// CHECK: store i32 99, ptr %device, align 4 +// CHECK-NEXT: %{{[0-9_]+}} = call i32 @omp_get_num_devices() +// CHECK-NEXT: %{{[0-9_]+}} = load i32, ptr %device, align 4 +// CHECK-NEXT: %{{[0-9_]+}} = icmp slt i32 %{{[0-9_]+}}, %{{[0-9_]+}} +// CHECK-NEXT: br i1 %{{[0-9_]+}}, label %bb{{[0-9]+}}, label %bb{{[0-9]+}} +// CHECK: call void @{{.*}}panic_fmt +// CHECK: unreachable +// CHECK: call i32 @__tgt_target_kernel diff --git a/tests/codegen-llvm/gpu_offload/gpu_host.rs b/tests/codegen-llvm/gpu_offload/gpu_host.rs index 208417b98bcae..45fcf6cf5c3ce 100644 --- a/tests/codegen-llvm/gpu_offload/gpu_host.rs +++ b/tests/codegen-llvm/gpu_offload/gpu_host.rs @@ -7,8 +7,8 @@ // Better documentation to what each global or variable means is available in the gpu offload code, // or the LLVM offload documentation. +#![feature(gpu_offload)] #![feature(rustc_attrs)] -#![feature(core_intrinsics)] #![no_main] #[unsafe(no_mangle)] @@ -21,7 +21,12 @@ fn main() { } pub fn kernel_1(x: &mut [f32; 256], y: &[f32; 256]) { - core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], 0, -1, (x, y)) + core::offload::offload! { + kernel = _kernel_1, + workgroup_dim = [256, 1, 1], + thread_dim = [32, 1, 1], + args = (x, y), + } } #[inline(never)] @@ -97,7 +102,7 @@ pub fn _kernel_1(x: &mut [f32; 256], y: &[f32; 256]) { // CHECK: declare void @__tgt_register_lib(ptr) local_unnamed_addr // CHECK: declare void @__tgt_unregister_lib(ptr) local_unnamed_addr -// CHECK-LABEL: define internal void @.omp_offloading.descriptor_reg() section ".text.startup" !guid !{{[0-9]+}} { +// CHECK-LABEL: define internal void @.omp_offloading.descriptor_reg() section ".text.startup" // CHECK-NEXT: entry: // CHECK-NEXT: {{tail }}call void @__tgt_register_lib(ptr nonnull @.omp_offloading.descriptor) // CHECK-NEXT: {{tail }}call void @__tgt_init_all_rtls() @@ -105,7 +110,7 @@ pub fn _kernel_1(x: &mut [f32; 256], y: &[f32; 256]) { // CHECK-NEXT: ret void // CHECK-NEXT: } -// CHECK-LABEL: define internal void @.omp_offloading.descriptor_unreg() section ".text.startup" !guid !{{[0-9]+}} { +// CHECK-LABEL: define internal void @.omp_offloading.descriptor_unreg() section ".text.startup" // CHECK-NEXT: entry: // CHECK-NEXT: {{tail }}call void @__tgt_unregister_lib(ptr nonnull @.omp_offloading.descriptor) // CHECK-NEXT: ret void diff --git a/tests/codegen-llvm/gpu_offload/scalar_host.rs b/tests/codegen-llvm/gpu_offload/scalar_host.rs index 950306c83a43f..807d08ddf1893 100644 --- a/tests/codegen-llvm/gpu_offload/scalar_host.rs +++ b/tests/codegen-llvm/gpu_offload/scalar_host.rs @@ -6,8 +6,8 @@ // the kernel as i64 #![feature(abi_gpu_kernel)] +#![feature(gpu_offload)] #![feature(rustc_attrs)] -#![feature(core_intrinsics)] #![no_main] // CHECK: define{{( dso_local)?}} void @main() @@ -28,14 +28,10 @@ fn main() { let mut x = 0.0f32; let k = core::hint::black_box(42.0f32); - core::intrinsics::offload::<_, _, ()>( - foo, - [1, 1, 1], - [1, 1, 1], - 0, - -1, - (&mut x as *mut f32, k), - ); + core::offload::offload! { + kernel = foo, + args = (&mut x as *mut f32, k), + } } unsafe extern "C" { diff --git a/tests/codegen-llvm/gpu_offload/slice_host.rs b/tests/codegen-llvm/gpu_offload/slice_host.rs index 1b314d489612c..ad47d2e76360a 100644 --- a/tests/codegen-llvm/gpu_offload/slice_host.rs +++ b/tests/codegen-llvm/gpu_offload/slice_host.rs @@ -5,8 +5,8 @@ // This test verifies that offload is properly handling slices passing them properly to the device #![feature(abi_gpu_kernel)] +#![feature(gpu_offload)] #![feature(rustc_attrs)] -#![feature(core_intrinsics)] #![no_main] // CHECK: @anon.[[ID:.*]].0 = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1 @@ -27,14 +27,10 @@ #[unsafe(no_mangle)] fn main() { let mut x = [0.0f32, 0.0, 0.0, 0.0]; - core::intrinsics::offload::<_, _, ()>( - foo, - [1, 1, 1], - [1, 1, 1], - 0, - -1, - ((&mut x) as &mut [f32],), - ); + core::offload::offload! { + kernel = foo, + args = ((&mut x) as &mut [f32],), + } } unsafe extern "C" { diff --git a/tests/run-make/offload-generic-manifest/generic.rs b/tests/run-make/offload-generic-manifest/generic.rs index eb356ad05c574..a6b8a7368858d 100644 --- a/tests/run-make/offload-generic-manifest/generic.rs +++ b/tests/run-make/offload-generic-manifest/generic.rs @@ -1,4 +1,4 @@ -#![feature(core_intrinsics, rustc_attrs)] +#![feature(gpu_offload, rustc_attrs)] #![allow(internal_features)] #![cfg_attr(device, no_main)] @@ -7,6 +7,12 @@ fn kernel(x: T) {} #[cfg(not(device))] fn main() { - core::intrinsics::offload::<_, _, ()>(kernel::, [1, 1, 1], [1, 1, 1], 0, (0.0f32,)); - core::intrinsics::offload::<_, _, ()>(kernel::, [1, 1, 1], [1, 1, 1], 0, (0i32,)); + core::offload::offload! { + kernel = kernel::, + args = (0.0f32,), + } + core::offload::offload! { + kernel = kernel::, + args = (0i32,), + } } diff --git a/tests/ui/offload/check_config.rs b/tests/ui/offload/check_config.rs index 833ba39dffeca..63388ce69ba62 100644 --- a/tests/ui/offload/check_config.rs +++ b/tests/ui/offload/check_config.rs @@ -9,7 +9,7 @@ //[fail]~? ERROR: using the offload feature requires -Z offload= //[fail]~? ERROR: using the offload feature requires -C lto=fat -#![feature(core_intrinsics)] +#![feature(gpu_offload)] fn main() { let mut x = [3.0; 256]; @@ -17,7 +17,10 @@ fn main() { } fn kernel_1(x: &mut [f32; 256]) { - core::intrinsics::offload(_kernel_1, [1, 1, 1], [1, 1, 1], 0, -1, (x,)) + core::offload::offload! { + kernel = _kernel_1, + args = (x,), + } } fn _kernel_1(x: &mut [f32; 256]) {} diff --git a/tests/ui/offload/offload_macro.rs b/tests/ui/offload/offload_macro.rs index 468820f08c291..4480f7dd9c80b 100644 --- a/tests/ui/offload/offload_macro.rs +++ b/tests/ui/offload/offload_macro.rs @@ -26,4 +26,7 @@ fn main() { core::offload::offload! { kernel = kernel, args = (), dyn_cache = 0, dyn_cache = 8 } //~^ ERROR duplicate field `dyn_cache` + + core::offload::offload! { kernel = kernel, args = (), device = 0, device = 1 } + //~^ ERROR duplicate field `device` } diff --git a/tests/ui/offload/offload_macro.stderr b/tests/ui/offload/offload_macro.stderr index cd85afeab373e..e2517a2f8cca1 100644 --- a/tests/ui/offload/offload_macro.stderr +++ b/tests/ui/offload/offload_macro.stderr @@ -62,5 +62,13 @@ LL | core::offload::offload! { kernel = kernel, args = (), dyn_cache = 0, dy | = note: this error originates in the macro `$crate::offload` which comes from the expansion of the macro `core::offload::offload` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 8 previous errors +error: duplicate field `device` + --> $DIR/offload_macro.rs:30:5 + | +LL | core::offload::offload! { kernel = kernel, args = (), device = 0, device = 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `$crate::offload` which comes from the expansion of the macro `core::offload::offload` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 9 previous errors diff --git a/tests/ui/offload/offload_negative_device.rs b/tests/ui/offload/offload_negative_device.rs new file mode 100644 index 0000000000000..b47dc5f085315 --- /dev/null +++ b/tests/ui/offload/offload_negative_device.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Zunstable-options -Zoffload=Test -Clto=fat --emit=llvm-ir -Zdeduplicate-diagnostics=yes +//@ no-prefer-dynamic +//@ needs-offload + +#![feature(gpu_offload)] + +fn kernel() {} + +fn main() { + core::offload::offload! { kernel = kernel, args = (), device = -1 } + //~^ ERROR evaluation panicked: offload device must be non-negative; omit `device` to use the default device +} diff --git a/tests/ui/offload/offload_negative_device.stderr b/tests/ui/offload/offload_negative_device.stderr new file mode 100644 index 0000000000000..4be386dd436da --- /dev/null +++ b/tests/ui/offload/offload_negative_device.stderr @@ -0,0 +1,19 @@ +error[E0080]: evaluation panicked: offload device must be non-negative; omit `device` to use the default device + --> $DIR/offload_negative_device.rs:10:5 + | +LL | core::offload::offload! { kernel = kernel, args = (), device = -1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#0}` failed here + | + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `core::offload::offload` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant encountered + --> $DIR/offload_negative_device.rs:10:5 + | +LL | core::offload::offload! { kernel = kernel, args = (), device = -1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this note originates in the macro `$crate::offload` which comes from the expansion of the macro `core::offload::offload` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From f11d76f5e6f98ef03cd7b3237d2f34a6a8b05150 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 19 Aug 2026 21:56:11 +0200 Subject: [PATCH 17/32] Allow running EC2 jobs locally --- src/ci/citool/src/jobs.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index 8b4f66c85761a..9800f14d8fa39 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -44,7 +44,7 @@ impl Job { } fn is_linux(&self) -> bool { - self.os.contains("ubuntu") + self.os.contains("ubuntu") || self.os.contains("linux") } } @@ -414,7 +414,10 @@ pub fn find_linux_job<'a>(jobs: &'a [Job], name: &str) -> anyhow::Result<&'a Job )); }; if !job.is_linux() { - return Err(anyhow::anyhow!("Only Linux jobs can be executed locally")); + return Err(anyhow::anyhow!( + "Only Linux jobs can be executed locally, os `{}` is not linux", + job.os + )); } Ok(job) From 6c99f69a2838ede0bdb24d9a90a4b586328e4939 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 19 Aug 2026 21:39:48 +1000 Subject: [PATCH 18/32] Fix obvious copy/paste bug in `State::fmt_diff_with` --- compiler/rustc_const_eval/src/check_consts/resolver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 29b6e26d950d5..fa2ff057f64f2 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -309,7 +309,7 @@ impl DebugWithContext for State { if self.borrow != old.borrow { f.write_str("borrow: ")?; - self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?; + self.borrow.fmt_diff_with(&old.borrow, ctxt, f)?; f.write_str("\n")?; } From dffe2777a0963d1fb01fb3c67e85068f1510b2fa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 19 Aug 2026 21:49:16 +1000 Subject: [PATCH 19/32] Remove unnecessary arg from `FlowSensitiveAnalysis::new` --- compiler/rustc_const_eval/src/check_consts/check.rs | 6 +++--- compiler/rustc_const_eval/src/check_consts/resolver.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 7648bf4eb241d..b79286f030be5 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -69,7 +69,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let needs_drop = self.needs_drop.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; - FlowSensitiveAnalysis::new(NeedsDrop, ccx) + FlowSensitiveAnalysis::new(ccx) .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -98,7 +98,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; - FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) + FlowSensitiveAnalysis::new(ccx) .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -127,7 +127,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; - FlowSensitiveAnalysis::new(HasMutInterior, ccx) + FlowSensitiveAnalysis::new(ccx) .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index fa2ff057f64f2..4fc8c62ccf80a 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -247,7 +247,7 @@ impl<'mir, 'tcx, Q> FlowSensitiveAnalysis<'mir, 'tcx, Q> where Q: Qualif, { - pub(super) fn new(_: Q, ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { + pub(super) fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { FlowSensitiveAnalysis { ccx, _qualif: PhantomData } } From c7ead52dcd58af93a3daac4ba2af452fd0795a2b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 19 Aug 2026 22:08:31 +1000 Subject: [PATCH 20/32] Factor out duplicated code in `Qualifs` --- .../src/check_consts/check.rs | 103 ++++++------------ 1 file changed, 31 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index b79286f030be5..b1efe62e57a04 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -49,69 +49,11 @@ pub(crate) struct Qualifs<'mir, 'tcx> { } impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { - /// Returns `true` if `local` is `NeedsDrop` at the given `Location`. - /// - /// Only updates the cursor if absolutely necessary - pub(crate) fn needs_drop( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let ty = ccx.body.local_decls[local].ty; - // Peeking into opaque types causes cycles if the current function declares said opaque - // type. Thus we avoid short circuiting on the type and instead run the more expensive - // analysis that looks at the actual usage within this function - if !ty.has_opaque_types() && !NeedsDrop::in_any_value_of_ty(ccx, ty) { - return false; - } - - let needs_drop = self.needs_drop.get_or_insert_with(|| { - let ConstCx { tcx, body, .. } = *ccx; - - FlowSensitiveAnalysis::new(ccx) - .iterate_to_fixpoint(tcx, body, None) - .into_results_cursor(body) - }); - - needs_drop.seek_before_primary_effect(location); - needs_drop.get().contains(local) - } - - /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`. - /// - /// Only updates the cursor if absolutely necessary - pub(crate) fn needs_non_const_drop( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let ty = ccx.body.local_decls[local].ty; - // Peeking into opaque types causes cycles if the current function declares said opaque - // type. Thus we avoid short circuiting on the type and instead run the more expensive - // analysis that looks at the actual usage within this function - if !ty.has_opaque_types() && !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) { - return false; - } - - let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| { - let ConstCx { tcx, body, .. } = *ccx; - - FlowSensitiveAnalysis::new(ccx) - .iterate_to_fixpoint(tcx, body, None) - .into_results_cursor(body) - }); - - needs_non_const_drop.seek_before_primary_effect(location); - needs_non_const_drop.get().contains(local) - } - - /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. + /// Does `Q` hold for the `local` at the given `Location`? /// /// Only updates the cursor if absolutely necessary. - fn has_mut_interior( - &mut self, + fn in_local( + qualif_results: &mut Option>, ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, location: Location, @@ -119,12 +61,12 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ty = ccx.body.local_decls[local].ty; // Peeking into opaque types causes cycles if the current function declares said opaque // type. Thus we avoid short circuiting on the type and instead run the more expensive - // analysis that looks at the actual usage within this function - if !ty.has_opaque_types() && !HasMutInterior::in_any_value_of_ty(ccx, ty) { + // analysis that looks at the actual usage within this function. + if !ty.has_opaque_types() && !Q::in_any_value_of_ty(ccx, ty) { return false; } - let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| { + let qualif_results = qualif_results.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(ccx) @@ -132,8 +74,8 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { .into_results_cursor(body) }); - has_mut_interior.seek_before_primary_effect(location); - has_mut_interior.get().contains(local) + qualif_results.seek_before_primary_effect(location); + qualif_results.get().contains(local) } fn in_return_place( @@ -161,9 +103,19 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let return_loc = ccx.body.terminator_loc(return_block); ConstQualifs { - needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), - needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc), - has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), + needs_drop: Self::in_local(&mut self.needs_drop, ccx, RETURN_PLACE, return_loc), + needs_non_const_drop: Self::in_local( + &mut self.needs_non_const_drop, + ccx, + RETURN_PLACE, + return_loc, + ), + has_mut_interior: Self::in_local( + &mut self.has_mut_interior, + ccx, + RETURN_PLACE, + return_loc, + ), tainted_by_errors, } } @@ -435,7 +387,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty; let needs_drop = if let Some(local) = dropped_place.as_local() { - self.qualifs.needs_drop(self.ccx, local, location) + Qualifs::in_local(&mut self.qualifs.needs_drop, self.ccx, local, location) } else { qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place) }; @@ -448,7 +400,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let needs_non_const_drop = if let Some(local) = dropped_place.as_local() { // Use the span where the local was declared as the span of the drop error. err_span = self.body.local_decls[local].source_info.span; - self.qualifs.needs_non_const_drop(self.ccx, local, location) + Qualifs::in_local(&mut self.qualifs.needs_non_const_drop, self.ccx, local, location) } else { qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place) }; @@ -602,7 +554,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | Rvalue::RawPtr(RawPtrKind::Const, place) => { let borrowed_place_has_mut_interior = qualifs::in_place::( self.ccx, - &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location), + &mut |local| { + Qualifs::in_local( + &mut self.qualifs.has_mut_interior, + self.ccx, + local, + location, + ) + }, place.as_ref(), ); From 6229d6d70ef5d4d220f7db9b8d2cdab08b369253 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 20 Aug 2026 08:49:34 +1000 Subject: [PATCH 21/32] Remove defaults for `Qualif` assoc consts There are only three impls of `Qualif`, and the extra explicitness is clearer. --- compiler/rustc_const_eval/src/check_consts/qualifs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index b2b8a567860e0..daac2d5176258 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -45,10 +45,10 @@ pub trait Qualif { const ANALYSIS_NAME: &'static str; /// Whether this `Qualif` is cleared when a local is moved from. - const IS_CLEARED_ON_MOVE: bool = false; + const IS_CLEARED_ON_MOVE: bool; /// Whether this `Qualif` might be evaluated after the promotion and can encounter a promoted. - const ALLOW_PROMOTED: bool = false; + const ALLOW_PROMOTED: bool; /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`. fn in_qualifs(qualifs: &ConstQualifs) -> bool; @@ -79,6 +79,8 @@ pub struct HasMutInterior; impl Qualif for HasMutInterior { const ANALYSIS_NAME: &'static str = "flow_has_mut_interior"; + const IS_CLEARED_ON_MOVE: bool = false; + const ALLOW_PROMOTED: bool = false; fn in_qualifs(qualifs: &ConstQualifs) -> bool { qualifs.has_mut_interior From bb9cd32e38d137738e880a958f5048df228e285f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 18 Aug 2026 16:23:09 +1000 Subject: [PATCH 22/32] Pre-adjust visibility of pub items in `lib.rs` --- src/bootstrap/src/core/builder/mod.rs | 2 +- src/bootstrap/src/lib.rs | 42 ++++++++++++++------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 6f30f3b56f8b8..3d581fe1e1061 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -40,7 +40,7 @@ mod tests; /// Builds and performs different [`Self::kind`]s of stuff and actions, taking /// into account build configuration from e.g. bootstrap.toml. -pub struct Builder<'a> { +pub(crate) struct Builder<'a> { /// Build configuration from e.g. bootstrap.toml. pub build: &'a Build, diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 92e36155ffa22..b24ffe0740089 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -53,7 +53,7 @@ pub mod cli_main; mod core; mod utils; -pub enum GitRepo { +pub(crate) enum GitRepo { Rustc, Llvm, } @@ -68,7 +68,7 @@ pub enum GitRepo { /// although most functions are implemented as free functions rather than /// methods specifically on this structure itself (to make it easier to /// organize). -pub struct Build { +pub(crate) struct Build { /// User-specified configuration from `bootstrap.toml`. config: Config, @@ -130,7 +130,7 @@ pub struct Build { /// When building Rust various objects are handled differently. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum DependencyType { +pub(crate) enum DependencyType { /// Libraries originating from proc-macros. Host, /// Typical Rust libraries. @@ -144,7 +144,7 @@ pub enum DependencyType { /// These entries currently correspond to the various output directories of the /// build system, with each mod generating output in a different directory. #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] -pub enum Mode { +pub(crate) enum Mode { /// Build the standard library, placing output in the "stageN-std" directory. Std, @@ -193,7 +193,7 @@ pub enum Mode { } impl Mode { - pub fn must_support_dlopen(&self) -> bool { + pub(crate) fn must_support_dlopen(&self) -> bool { match self { Mode::Std | Mode::Codegen => true, Mode::ToolBootstrap @@ -208,7 +208,7 @@ impl Mode { /// When `rust.rust_remap_debuginfo` is requested, the compiler needs to know how to /// opportunistically unremap compiler vs non-compiler sources. We use two schemes, /// [`RemapScheme::Compiler`] and [`RemapScheme::NonCompiler`]. -pub enum RemapScheme { +pub(crate) enum RemapScheme { /// The [`RemapScheme::Compiler`] scheme will remap to `/rustc-dev/{hash}`. Compiler, /// The [`RemapScheme::NonCompiler`] scheme will remap to `/rustc/{hash}`. @@ -216,13 +216,13 @@ pub enum RemapScheme { } #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] -pub enum CLang { +pub(crate) enum CLang { C, Cxx, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FileType { +pub(crate) enum FileType { /// An executable binary file (like a `.exe`). Executable, /// A native, binary library file (like a `.so`, `.dll`, `.a`, `.lib` or `.o`). @@ -235,14 +235,14 @@ pub enum FileType { impl FileType { /// Get Unix permissions appropriate for this file type. - pub fn perms(self) -> u32 { + pub(crate) fn perms(self) -> u32 { match self { FileType::Executable | FileType::Script => 0o755, FileType::Regular | FileType::NativeLibrary => 0o644, } } - pub fn could_have_split_debuginfo(self) -> bool { + pub(crate) fn could_have_split_debuginfo(self) -> bool { match self { FileType::Executable | FileType::NativeLibrary => true, FileType::Script | FileType::Regular => false, @@ -515,7 +515,7 @@ impl Build { fields(submodule = submodule), ), )] - pub fn require_submodule(&self, submodule: &str, err_hint: Option<&str>) { + pub(crate) fn require_submodule(&self, submodule: &str, err_hint: Option<&str>) { if self.rust_info().is_from_tarball() { return; } @@ -589,7 +589,7 @@ impl Build { /// Executes the entire build, as configured by the flags and configuration. #[cfg_attr(feature = "tracing", instrument(level = "debug", name = "Build::build", skip_all))] - pub fn build(&mut self) { + pub(crate) fn build(&mut self) { trace!("setting up job management"); unsafe { crate::utils::job::setup(self); @@ -1558,7 +1558,7 @@ impl Build { /// If `src` is a symlink, `src` will be resolved to the actual path /// and copied to `dst` instead of the symlink itself. #[track_caller] - pub fn resolve_symlink_and_copy(&self, src: &Path, dst: &Path) { + pub(crate) fn resolve_symlink_and_copy(&self, src: &Path, dst: &Path) { self.copy_link_internal(src, dst, true); } @@ -1567,7 +1567,7 @@ impl Build { /// You can neither rely on this being a copy nor it being a link, /// so do not write to dst. #[track_caller] - pub fn copy_link(&self, src: &Path, dst: &Path, file_type: FileType) { + pub(crate) fn copy_link(&self, src: &Path, dst: &Path, file_type: FileType) { self.copy_link_internal(src, dst, false); if file_type.could_have_split_debuginfo() @@ -1636,7 +1636,7 @@ impl Build { /// when this function is called. /// Will attempt to use hard links if possible and fall back to copying. #[track_caller] - pub fn cp_link_r(&self, src: &Path, dst: &Path) { + pub(crate) fn cp_link_r(&self, src: &Path, dst: &Path) { if self.config.dry_run() { return; } @@ -1659,7 +1659,7 @@ impl Build { /// Unwanted files or directories can be skipped /// by returning `false` from the filter function. #[track_caller] - pub fn cp_link_filtered(&self, src: &Path, dst: &Path, filter: &dyn Fn(&Path) -> bool) { + pub(crate) fn cp_link_filtered(&self, src: &Path, dst: &Path, filter: &dyn Fn(&Path) -> bool) { // Immediately recurse with an empty relative path self.cp_link_filtered_recurse(src, dst, Path::new(""), filter) } @@ -1826,11 +1826,12 @@ to download LLVM rather than building it. self.config.ninja_in_file } - pub fn colored_stdout R>(&self, f: F) -> R { + pub(crate) fn colored_stdout R>(&self, f: F) -> R { self.colored_stream_inner(StandardStream::stdout, self.config.stdout_is_tty, f) } - pub fn colored_stderr R>(&self, f: F) -> R { + #[expect(dead_code, reason = "symmetric with `colored_stdout`")] + pub(crate) fn colored_stderr R>(&self, f: F) -> R { self.colored_stream_inner(StandardStream::stderr, self.config.stderr_is_tty, f) } @@ -1851,12 +1852,13 @@ to download LLVM rather than building it. result } - pub fn report_summary(&self, path: &Path, start_time: Instant) { + #[cfg_attr(not(feature = "tracing"), expect(dead_code))] + pub(crate) fn report_summary(&self, path: &Path, start_time: Instant) { self.config.exec_ctx.profiler().report_summary(path, start_time); } #[cfg(feature = "tracing")] - pub fn report_step_graph(self, directory: &Path) { + pub(crate) fn report_step_graph(self, directory: &Path) { self.step_graph.into_inner().store_to_dot_files(directory); } } From 651d501b45e06ac966537763a983e3ea6ac576cd Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 17 Aug 2026 13:56:38 +1000 Subject: [PATCH 23/32] Pre-adjust visibility of default-visibility items in `lib.rs` Items with implicit `pub(self)` visibility in the crate root are effectively `pub(crate)`, which causes friction when trying to move them elsewhere. --- src/bootstrap/src/lib.rs | 238 +++++++++++++++++++++------------------ 1 file changed, 131 insertions(+), 107 deletions(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index b24ffe0740089..1fe73fb78f819 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -70,62 +70,62 @@ pub(crate) enum GitRepo { /// organize). pub(crate) struct Build { /// User-specified configuration from `bootstrap.toml`. - config: Config, + pub(crate) config: Config, // Version information - version: String, + pub(crate) version: String, // Properties derived from the above configuration - src: PathBuf, - out: PathBuf, - bootstrap_out: PathBuf, - cargo_info: GitInfo, - rust_analyzer_info: GitInfo, - clippy_info: GitInfo, - miri_info: GitInfo, - rustfmt_info: GitInfo, - enzyme_info: GitInfo, - in_tree_llvm_info: GitInfo, - in_tree_gcc_info: GitInfo, - local_rebuild: bool, - fail_fast: bool, - test_target: TestTarget, - verbosity: usize, + pub(crate) src: PathBuf, + pub(crate) out: PathBuf, + pub(crate) bootstrap_out: PathBuf, + pub(crate) cargo_info: GitInfo, + pub(crate) rust_analyzer_info: GitInfo, + pub(crate) clippy_info: GitInfo, + pub(crate) miri_info: GitInfo, + pub(crate) rustfmt_info: GitInfo, + pub(crate) enzyme_info: GitInfo, + pub(crate) in_tree_llvm_info: GitInfo, + pub(crate) in_tree_gcc_info: GitInfo, + pub(crate) local_rebuild: bool, + pub(crate) fail_fast: bool, + pub(crate) test_target: TestTarget, + pub(crate) verbosity: usize, /// Build triple for the pre-compiled snapshot compiler. - host_target: TargetSelection, + pub(crate) host_target: TargetSelection, /// Which triples to produce a compiler toolchain for. - hosts: Vec, + pub(crate) hosts: Vec, /// Which triples to build libraries (core/alloc/std/test/proc_macro) for. - targets: Vec, + pub(crate) targets: Vec, - initial_rustc: PathBuf, - initial_rustdoc: PathBuf, - initial_cargo: PathBuf, - initial_lld: PathBuf, - initial_relative_libdir: PathBuf, - initial_sysroot: PathBuf, + pub(crate) initial_rustc: PathBuf, + pub(crate) initial_rustdoc: PathBuf, + pub(crate) initial_cargo: PathBuf, + pub(crate) initial_lld: PathBuf, + pub(crate) initial_relative_libdir: PathBuf, + pub(crate) initial_sysroot: PathBuf, // Runtime state filled in later on // C/C++ compilers and archiver for all targets - cc: HashMap, - cxx: HashMap, - ar: HashMap, - ranlib: HashMap, - wasi_sdk_path: Option, + pub(crate) cc: HashMap, + pub(crate) cxx: HashMap, + pub(crate) ar: HashMap, + pub(crate) ranlib: HashMap, + pub(crate) wasi_sdk_path: Option, // Miscellaneous // allow bidirectional lookups: both name -> path and path -> name - crates: HashMap, - crate_paths: HashMap, - is_sudo: bool, - prerelease_version: Cell>, + pub(crate) crates: HashMap, + pub(crate) crate_paths: HashMap, + pub(crate) is_sudo: bool, + pub(crate) prerelease_version: Cell>, #[cfg(feature = "build-metrics")] - metrics: crate::utils::metrics::BuildMetrics, + pub(crate) metrics: crate::utils::metrics::BuildMetrics, #[cfg(feature = "tracing")] - step_graph: std::cell::RefCell, + pub(crate) step_graph: std::cell::RefCell, } /// When building Rust various objects are handled differently. @@ -253,9 +253,11 @@ impl FileType { macro_rules! forward { ( $( $fn:ident( $($param:ident: $ty:ty),* ) $( -> $ret:ty)? ),+ $(,)? ) => { impl Build { - $( fn $fn(&self, $($param: $ty),* ) $( -> $ret)? { - self.config.$fn( $($param),* ) - } )+ + $( + pub(crate) fn $fn(&self, $($param: $ty),* ) $( -> $ret)? { + self.config.$fn( $($param),* ) + } + )+ } } } @@ -271,7 +273,7 @@ forward! { /// An alternative way of specifying what target and stage is involved in some bootstrap activity. /// Ideally using a `Compiler` directly should be preferred. -struct TargetAndStage { +pub(crate) struct TargetAndStage { target: TargetSelection, stage: u32, } @@ -550,7 +552,7 @@ impl Build { /// If any submodule has been initialized already, sync it unconditionally. /// This avoids contributors checking in a submodule change by accident. - fn update_existing_submodules(&self) { + pub(crate) fn update_existing_submodules(&self) { // Avoid running git when there isn't a git checkout, or the user has // explicitly disabled submodules in `bootstrap.toml`. if !self.config.submodules() { @@ -670,13 +672,13 @@ impl Build { self.metrics.persist(self); } - fn rust_info(&self) -> &GitInfo { + pub(crate) fn rust_info(&self) -> &GitInfo { &self.config.rust_info } /// Gets the space-separated set of activated features for the standard library. /// This can be configured with the `std-features` key in bootstrap.toml. - fn std_features(&self, target: TargetSelection) -> String { + pub(crate) fn std_features(&self, target: TargetSelection) -> String { let mut features: BTreeSet<&str> = self.config.rust_std_features.iter().map(|s| s.as_str()).collect(); @@ -703,7 +705,12 @@ impl Build { } /// Gets the space-separated set of activated features for the compiler. - fn rustc_features(&self, kind: Kind, target: TargetSelection, crates: &[String]) -> String { + pub(crate) fn rustc_features( + &self, + kind: Kind, + target: TargetSelection, + crates: &[String], + ) -> String { let possible_features_by_crates: HashSet<_> = crates .iter() .flat_map(|krate| &self.crates[krate].features) @@ -753,7 +760,7 @@ impl Build { /// Component directory that Cargo will produce output into (e.g. /// release/debug) - fn cargo_dir(&self, mode: Mode) -> &'static str { + pub(crate) fn cargo_dir(&self, mode: Mode) -> &'static str { match (mode, self.config.rust_optimize.is_release()) { (Mode::Std, _) => "dist", (_, true) => "release", @@ -761,7 +768,7 @@ impl Build { } } - fn tools_dir(&self, build_compiler: Compiler) -> PathBuf { + pub(crate) fn tools_dir(&self, build_compiler: Compiler) -> PathBuf { let out = self .out .join(build_compiler.host) @@ -774,7 +781,7 @@ impl Build { /// stage when being built with a particular build compiler. /// /// The mode indicates what the root directory is for. - fn stage_out(&self, build_compiler: Compiler, mode: Mode) -> PathBuf { + pub(crate) fn stage_out(&self, build_compiler: Compiler, mode: Mode) -> PathBuf { use std::fmt::Write; fn bootstrap_tool() -> (Option, &'static str) { @@ -814,64 +821,69 @@ impl Build { /// Returns the root output directory for all Cargo output in a given stage, /// running a particular compiler, whether or not we're building the /// standard library, and targeting the specified architecture. - fn cargo_out(&self, build_compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf { + pub(crate) fn cargo_out( + &self, + build_compiler: Compiler, + mode: Mode, + target: TargetSelection, + ) -> PathBuf { self.stage_out(build_compiler, mode).join(target).join(self.cargo_dir(mode)) } /// Output directory for all documentation for a target - fn doc_out(&self, target: TargetSelection) -> PathBuf { + pub(crate) fn doc_out(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("doc") } /// Output directory for all JSON-formatted documentation for a target - fn json_doc_out(&self, target: TargetSelection) -> PathBuf { + pub(crate) fn json_doc_out(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("json-doc") } - fn test_out(&self, target: TargetSelection) -> PathBuf { + pub(crate) fn test_out(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("test") } /// Output directory for all documentation for a target - fn compiler_doc_out(&self, target: TargetSelection) -> PathBuf { + pub(crate) fn compiler_doc_out(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("compiler-doc") } /// Output directory for some generated md crate documentation for a target (temporary) - fn md_doc_out(&self, target: TargetSelection) -> PathBuf { + pub(crate) fn md_doc_out(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("md-doc") } /// Path to the vendored Rust crates. - fn vendored_crates_path(&self) -> Option { + pub(crate) fn vendored_crates_path(&self) -> Option { if self.config.vendor { Some(self.src.join(VENDOR_DIR)) } else { None } } /// Directory for libraries built from C/C++ code and shared between stages. - fn native_dir(&self, target: TargetSelection) -> PathBuf { + pub(crate) fn native_dir(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("native") } /// Root output directory for rust_test_helpers library compiled for /// `target` - fn test_helpers_out(&self, target: TargetSelection) -> PathBuf { + pub(crate) fn test_helpers_out(&self, target: TargetSelection) -> PathBuf { self.native_dir(target).join("rust-test-helpers") } /// Adds the `RUST_TEST_THREADS` env var if necessary - fn add_rust_test_threads(&self, cmd: &mut BootstrapCommand) { + pub(crate) fn add_rust_test_threads(&self, cmd: &mut BootstrapCommand) { if env::var_os("RUST_TEST_THREADS").is_none() { cmd.env("RUST_TEST_THREADS", self.jobs().to_string()); } } /// Returns the libdir of the snapshot compiler. - fn rustc_snapshot_libdir(&self) -> PathBuf { + pub(crate) fn rustc_snapshot_libdir(&self) -> PathBuf { self.rustc_snapshot_sysroot().join(libdir(self.config.host_target)) } /// Returns the sysroot of the snapshot compiler. - fn rustc_snapshot_sysroot(&self) -> &Path { + pub(crate) fn rustc_snapshot_sysroot(&self) -> &Path { static SYSROOT_CACHE: OnceLock = OnceLock::new(); SYSROOT_CACHE.get_or_init(|| { command(&self.initial_rustc) @@ -885,7 +897,7 @@ impl Build { }) } - fn info(&self, msg: &str) { + pub(crate) fn info(&self, msg: &str) { match self.config.get_dry_run() { DryRun::SelfCheck => (), DryRun::Disabled | DryRun::UserSelected => { @@ -907,7 +919,7 @@ impl Build { /// [`Step`]: crate::core::builder::Step #[must_use = "Groups should not be dropped until the Step finishes running"] #[track_caller] - fn msg( + pub(crate) fn msg( &self, action: impl Into, what: impl Display, @@ -964,7 +976,7 @@ impl Build { /// [`Step`]: crate::core::builder::Step #[must_use = "Groups should not be dropped until the Step finishes running"] #[track_caller] - fn msg_test( + pub(crate) fn msg_test( &self, what: impl Display, target: TargetSelection, @@ -980,7 +992,7 @@ impl Build { /// [`Step`]: crate::core::builder::Step #[must_use = "Groups should not be dropped until the Step finishes running"] #[track_caller] - fn msg_unstaged( + pub(crate) fn msg_unstaged( &self, action: impl Into, what: impl Display, @@ -992,7 +1004,7 @@ impl Build { } #[track_caller] - fn group(&self, msg: &str) -> Option { + pub(crate) fn group(&self, msg: &str) -> Option { match self.config.get_dry_run() { DryRun::SelfCheck => None, DryRun::Disabled | DryRun::UserSelected => Some(gha::group(msg)), @@ -1001,13 +1013,17 @@ impl Build { /// Returns the number of parallel jobs that have been configured for this /// build. - fn jobs(&self) -> u32 { + pub(crate) fn jobs(&self) -> u32 { self.config.jobs.unwrap_or_else(|| { std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32 }) } - fn debuginfo_map_to(&self, which: GitRepo, remap_scheme: RemapScheme) -> Option { + pub(crate) fn debuginfo_map_to( + &self, + which: GitRepo, + remap_scheme: RemapScheme, + ) -> Option { if !self.config.rust_remap_debuginfo { return None; } @@ -1039,7 +1055,7 @@ impl Build { } /// Returns the path to the C compiler for the target specified. - fn cc(&self, target: TargetSelection) -> PathBuf { + pub(crate) fn cc(&self, target: TargetSelection) -> PathBuf { if self.config.dry_run() { return PathBuf::new(); } @@ -1047,18 +1063,18 @@ impl Build { } /// Returns the internal `cc::Tool` for the C compiler. - fn cc_tool(&self, target: TargetSelection) -> cc::Tool { + pub(crate) fn cc_tool(&self, target: TargetSelection) -> cc::Tool { self.cc[&target].clone() } /// Returns the internal `cc::Tool` for the C++ compiler. - fn cxx_tool(&self, target: TargetSelection) -> cc::Tool { + pub(crate) fn cxx_tool(&self, target: TargetSelection) -> cc::Tool { self.cxx[&target].clone() } /// Returns C flags that `cc-rs` thinks should be enabled for the /// specified target by default. - fn cc_handled_cflags(&self, target: TargetSelection, c: CLang) -> Vec { + pub(crate) fn cc_handled_cflags(&self, target: TargetSelection, c: CLang) -> Vec { if self.config.dry_run() { return Vec::new(); } @@ -1077,7 +1093,7 @@ impl Build { } /// Returns extra C flags that `cc-rs` doesn't handle. - fn cc_unhandled_cflags( + pub(crate) fn cc_unhandled_cflags( &self, target: TargetSelection, which: GitRepo, @@ -1113,7 +1129,7 @@ impl Build { } /// Returns the path to the `ar` archive utility for the target specified. - fn ar(&self, target: TargetSelection) -> Option { + pub(crate) fn ar(&self, target: TargetSelection) -> Option { if self.config.dry_run() { return None; } @@ -1121,7 +1137,7 @@ impl Build { } /// Returns the path to the `ranlib` utility for the target specified. - fn ranlib(&self, target: TargetSelection) -> Option { + pub(crate) fn ranlib(&self, target: TargetSelection) -> Option { if self.config.dry_run() { return None; } @@ -1129,7 +1145,7 @@ impl Build { } /// Returns the path to the C++ compiler for the target specified. - fn cxx(&self, target: TargetSelection) -> Result { + pub(crate) fn cxx(&self, target: TargetSelection) -> Result { if self.config.dry_run() { return Ok(PathBuf::new()); } @@ -1140,7 +1156,7 @@ impl Build { } /// Returns the path to the linker for the given target if it needs to be overridden. - fn linker(&self, target: TargetSelection) -> Option { + pub(crate) fn linker(&self, target: TargetSelection) -> Option { if self.config.dry_run() { return Some(PathBuf::new()); } @@ -1172,12 +1188,12 @@ impl Build { // Is LLD configured directly through `-Clinker`? // Only MSVC targets use LLD directly at the moment. - fn is_lld_direct_linker(&self, target: TargetSelection) -> bool { + pub(crate) fn is_lld_direct_linker(&self, target: TargetSelection) -> bool { target.is_msvc() } /// Returns if this target should statically link the C runtime, if specified - fn crt_static(&self, target: TargetSelection) -> Option { + pub(crate) fn crt_static(&self, target: TargetSelection) -> Option { if target.contains("pc-windows-msvc") { Some(true) } else { @@ -1189,7 +1205,7 @@ impl Build { /// /// If this is a native target (host is also musl) and no musl-root is given, /// it falls back to the system toolchain in /usr. - fn musl_root(&self, target: TargetSelection) -> Option<&Path> { + pub(crate) fn musl_root(&self, target: TargetSelection) -> Option<&Path> { let configured_root = self .config .target_config @@ -1206,7 +1222,7 @@ impl Build { } /// Returns the "musl libdir" for this `target`. - fn musl_libdir(&self, target: TargetSelection) -> Option { + pub(crate) fn musl_libdir(&self, target: TargetSelection) -> Option { self.config .target_config .get(&target) @@ -1220,7 +1236,7 @@ impl Build { /// This first consults `wasi-root` as configured in per-target /// configuration, and failing that it assumes that `$WASI_SDK_PATH` is /// set in the environment, and failing that `None` is returned. - fn wasi_libdir(&self, target: TargetSelection) -> Option { + pub(crate) fn wasi_libdir(&self, target: TargetSelection) -> Option { let configured = self.config.target_config.get(&target).and_then(|t| t.wasi_root.as_ref()).map(|p| &**p); if let Some(path) = configured { @@ -1235,13 +1251,13 @@ impl Build { } /// Returns `true` if this is a no-std `target`, if defined - fn no_std(&self, target: TargetSelection) -> Option { + pub(crate) fn no_std(&self, target: TargetSelection) -> Option { self.config.target_config.get(&target).map(|t| t.no_std) } /// Returns `true` if the target will be tested using the `remote-test-client` /// and `remote-test-server` binaries. - fn remote_tested(&self, target: TargetSelection) -> bool { + pub(crate) fn remote_tested(&self, target: TargetSelection) -> bool { self.qemu_rootfs(target).is_some() || target.contains("android") || env::var_os("TEST_DEVICE_ADDR").is_some() @@ -1252,7 +1268,7 @@ impl Build { /// /// An example of this would be a WebAssembly runtime when testing the wasm /// targets. - fn runner(&self, target: TargetSelection) -> Option { + pub(crate) fn runner(&self, target: TargetSelection) -> Option { let configured_runner = self.config.target_config.get(&target).and_then(|t| t.runner.as_ref()).map(|p| &**p); if let Some(runner) = configured_runner { @@ -1301,7 +1317,7 @@ impl Build { /// /// This requires that both the `extended` key is set and the `tools` key is /// either unset or specifically contains the specified tool. - fn tool_enabled(&self, tool: &str) -> bool { + pub(crate) fn tool_enabled(&self, tool: &str) -> bool { if !self.config.extended { return false; } @@ -1316,12 +1332,12 @@ impl Build { /// /// If `Some` is returned then that means that tests for this target are /// emulated with QEMU and binaries will need to be shipped to the emulator. - fn qemu_rootfs(&self, target: TargetSelection) -> Option<&Path> { + pub(crate) fn qemu_rootfs(&self, target: TargetSelection) -> Option<&Path> { self.config.target_config.get(&target).and_then(|t| t.qemu_rootfs.as_ref()).map(|p| &**p) } /// Temporary directory that extended error information is emitted to. - fn extended_error_dir(&self) -> PathBuf { + pub(crate) fn extended_error_dir(&self) -> PathBuf { self.out.join("tmp/extended-error-metadata") } @@ -1343,7 +1359,7 @@ impl Build { /// /// When all of these conditions are met the build will lift artifacts from /// the previous stage forward. - fn force_use_stage1(&self, stage: u32, target: TargetSelection) -> bool { + pub(crate) fn force_use_stage1(&self, stage: u32, target: TargetSelection) -> bool { !self.config.full_bootstrap && !self.config.download_rustc() && stage >= 2 @@ -1355,7 +1371,7 @@ impl Build { /// /// When we download the pre-compiled version of rustc and compiler stage is >= 2, /// it should be forced to use a stage2 compiler. - fn force_use_stage2(&self, stage: u32) -> bool { + pub(crate) fn force_use_stage2(&self, stage: u32) -> bool { self.config.download_rustc() && stage >= 2 } @@ -1364,7 +1380,7 @@ impl Build { /// /// For example on nightly this returns "a.b.c-nightly", on beta it returns /// "a.b.c-beta.1" and on stable it just returns "a.b.c". - fn release(&self, num: &str) -> String { + pub(crate) fn release(&self, num: &str) -> String { match &self.config.channel[..] { "stable" => num.to_string(), "beta" => { @@ -1415,7 +1431,7 @@ impl Build { } /// Returns the value of `release` above for Rust itself. - fn rust_release(&self) -> String { + pub(crate) fn rust_release(&self) -> String { self.release(&self.version) } @@ -1424,7 +1440,7 @@ impl Build { /// The package version is typically what shows up in the names of tarballs. /// For channels like beta/nightly it's just the channel name, otherwise it's the release /// version. - fn rust_package_vers(&self) -> String { + pub(crate) fn rust_package_vers(&self) -> String { match &self.config.channel[..] { "stable" => self.version.to_string(), "beta" => "beta".to_string(), @@ -1438,7 +1454,7 @@ impl Build { /// /// Note that this is a descriptive string which includes the commit date, /// sha, version, etc. - fn rust_version(&self) -> String { + pub(crate) fn rust_version(&self) -> String { let mut version = self.rust_info().version(self, &self.version); if let Some(ref s) = self.config.description && !s.is_empty() @@ -1451,12 +1467,12 @@ impl Build { } /// Returns the full commit hash. - fn rust_sha(&self) -> Option<&str> { + pub(crate) fn rust_sha(&self) -> Option<&str> { self.rust_info().sha() } /// Returns the `a.b.c` version that the given package is at. - fn release_num(&self, package: &str) -> String { + pub(crate) fn release_num(&self, package: &str) -> String { if self.config.dry_run() { return "0.0.0 (dry-run)".into(); } @@ -1475,14 +1491,18 @@ impl Build { /// Returns `true` if unstable features should be enabled for the compiler /// we're building. - fn unstable_features(&self) -> bool { + pub(crate) fn unstable_features(&self) -> bool { !matches!(&self.config.channel[..], "stable" | "beta") } /// Returns a Vec of all the dependencies of the given root crate, /// including transitive dependencies and the root itself. Only includes /// "local" crates (those in the local source tree, not from a registry). - fn in_tree_crates(&self, root: &str, target: Option) -> Vec<&Crate> { + pub(crate) fn in_tree_crates( + &self, + root: &str, + target: Option, + ) -> Vec<&Crate> { let mut ret = Vec::new(); let mut list = vec![root.to_owned()]; let mut visited = HashSet::new(); @@ -1520,7 +1540,7 @@ impl Build { ret } - fn read_stamp_file(&self, stamp: &BuildStamp) -> Vec<(PathBuf, DependencyType)> { + pub(crate) fn read_stamp_file(&self, stamp: &BuildStamp) -> Vec<(PathBuf, DependencyType)> { if self.config.dry_run() { return Vec::new(); } @@ -1691,13 +1711,13 @@ impl Build { } } - fn copy_link_to_folder(&self, src: &Path, dest_folder: &Path) { + pub(crate) fn copy_link_to_folder(&self, src: &Path, dest_folder: &Path) { let file_name = src.file_name().unwrap(); let dest = dest_folder.join(file_name); self.copy_link(src, &dest, FileType::Regular); } - fn install(&self, src: &Path, dstdir: &Path, file_type: FileType) { + pub(crate) fn install(&self, src: &Path, dstdir: &Path, file_type: FileType) { if self.config.dry_run() { return; } @@ -1722,7 +1742,7 @@ impl Build { } } - fn read(&self, path: &Path) -> String { + pub(crate) fn read(&self, path: &Path) -> String { if self.config.dry_run() { return String::new(); } @@ -1730,7 +1750,7 @@ impl Build { } #[track_caller] - fn create_dir(&self, dir: &Path) { + pub(crate) fn create_dir(&self, dir: &Path) { if self.config.dry_run() { return; } @@ -1741,7 +1761,7 @@ impl Build { t!(fs::create_dir_all(dir)) } - fn remove_dir(&self, dir: &Path) { + pub(crate) fn remove_dir(&self, dir: &Path) { if self.config.dry_run() { return; } @@ -1754,7 +1774,7 @@ impl Build { /// Make sure that `dir` will be an empty existing directory after this function ends. /// If it existed before, it will be first deleted. - fn clear_dir(&self, dir: &Path) { + pub(crate) fn clear_dir(&self, dir: &Path) { if self.config.dry_run() { return; } @@ -1766,7 +1786,7 @@ impl Build { self.create_dir(dir); } - fn read_dir(&self, dir: &Path) -> impl Iterator { + pub(crate) fn read_dir(&self, dir: &Path) -> impl Iterator { let iter = match fs::read_dir(dir) { Ok(v) => v, Err(_) if self.config.dry_run() => return vec![].into_iter(), @@ -1775,7 +1795,11 @@ impl Build { iter.map(|e| t!(e)).collect::>().into_iter() } - fn symlink_file, Q: AsRef>(&self, src: P, link: Q) -> io::Result<()> { + pub(crate) fn symlink_file, Q: AsRef>( + &self, + src: P, + link: Q, + ) -> io::Result<()> { #[cfg(unix)] use std::os::unix::fs::symlink as symlink_file; #[cfg(windows)] @@ -1785,7 +1809,7 @@ impl Build { /// Returns if config.ninja is enabled, and checks for ninja existence, /// exiting with a nicer error message if not. - fn ninja(&self) -> bool { + pub(crate) fn ninja(&self) -> bool { let mut cmd_finder = crate::core::sanity::Finder::new(); if self.config.ninja_in_file { From 72e9e0e65a97a587d4a43ab23242e1bca437d517 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 17 Aug 2026 14:03:42 +1000 Subject: [PATCH 24/32] Pre-adjust imports from the crate root --- src/bootstrap/src/cli_main.rs | 3 ++- src/bootstrap/src/core/build_steps/check.rs | 2 +- src/bootstrap/src/core/build_steps/clean.rs | 2 +- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- src/bootstrap/src/core/build_steps/compile.rs | 3 ++- src/bootstrap/src/core/build_steps/dist.rs | 3 ++- src/bootstrap/src/core/build_steps/doc.rs | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 3 ++- src/bootstrap/src/core/build_steps/run.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 2 +- src/bootstrap/src/core/builder/cargo.rs | 2 +- src/bootstrap/src/core/builder/cli_paths/tests.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 3 ++- src/bootstrap/src/core/compiler.rs | 2 +- src/bootstrap/src/core/config/config.rs | 2 +- src/bootstrap/src/core/config/flags.rs | 2 +- src/bootstrap/src/core/metadata.rs | 2 +- src/bootstrap/src/core/mod.rs | 3 +++ src/bootstrap/src/core/sanity.rs | 2 +- src/bootstrap/src/utils/build_stamp.rs | 2 +- src/bootstrap/src/utils/cc_detect.rs | 2 +- src/bootstrap/src/utils/cc_detect/tests.rs | 2 +- src/bootstrap/src/utils/channel.rs | 2 +- src/bootstrap/src/utils/job.rs | 10 +++++----- src/bootstrap/src/utils/metrics.rs | 2 +- src/bootstrap/src/utils/tarball.rs | 2 +- 27 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/bootstrap/src/cli_main.rs b/src/bootstrap/src/cli_main.rs index c11e1478f4d42..8a74b2e598283 100644 --- a/src/bootstrap/src/cli_main.rs +++ b/src/bootstrap/src/cli_main.rs @@ -16,11 +16,12 @@ use std::{env, process}; use crate::core::builder::StepStack; use crate::core::config::flags::{Flags, Subcommand}; use crate::core::config::{ChangeId, Config}; +use crate::core::session::Build; +use crate::debug; use crate::utils::change_tracker::{ CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes, }; use crate::utils::helpers::t; -use crate::{Build, debug}; fn is_tracing_enabled() -> bool { cfg!(feature = "tracing") diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 265999711eb87..4a75cdbb1562f 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -3,7 +3,6 @@ use std::fs; use std::path::{Path, PathBuf}; -use crate::Mode; use crate::core::backend::CodegenBackendKind; use crate::core::build_steps::compile::{ ArtifactKeepMode, add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, @@ -20,6 +19,7 @@ use crate::core::builder::{ }; use crate::core::compiler::Compiler; use crate::core::config::TargetSelection; +use crate::core::session::Mode; use crate::utils::build_stamp::{self, BuildStamp}; use crate::utils::helpers::t; diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index a5c7398d11302..23f12bbb63e72 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -14,9 +14,9 @@ use crate::core::builder::{ }; use crate::core::compiler::Compiler; use crate::core::config::flags::Subcommand; +use crate::core::session::{Build, Mode}; use crate::utils::build_stamp::BuildStamp; use crate::utils::helpers::t; -use crate::{Build, Mode}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CleanAll {} diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 2ca775f92d683..dc3e3efb80ee5 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -14,7 +14,6 @@ //! (as usual) a massive undertaking/refactoring. use super::tool::{SourceType, prepare_tool_cargo}; -use crate::Mode; use crate::core::build_steps::check::{CompilerForCheck, prepare_compiler_for_check}; use crate::core::build_steps::compile::{ ArtifactKeepMode, run_cargo, rustc_cargo, std_cargo, std_crates_for_make_run, @@ -26,6 +25,7 @@ use crate::core::builder::{ use crate::core::compiler::Compiler; use crate::core::config::TargetSelection; use crate::core::config::flags::Subcommand; +use crate::core::session::Mode; use crate::utils::build_stamp::{self, BuildStamp}; use crate::utils::helpers; diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index c008ff5090a9c..fcf8be30c9dd1 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -33,13 +33,14 @@ use crate::core::config::toml::target::DefaultLinuxLinkerOverride; use crate::core::config::{ Allocator, CompilerBuiltins, DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection, }; +use crate::core::session::{CLang, DependencyType, FileType, GitRepo, Mode}; use crate::utils::build_stamp; use crate::utils::build_stamp::BuildStamp; use crate::utils::exec::command; use crate::utils::helpers::{ self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, }; -use crate::{CLang, DependencyType, FileType, GitRepo, Mode, debug, trace}; +use crate::{debug, trace}; /// Build a standard library for the given `target` using the given `build_compiler`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index b5118281fab74..5c86d117767c8 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -38,6 +38,8 @@ use crate::core::builder::{ }; use crate::core::compiler::Compiler; use crate::core::config::{GccCiMode, TargetSelection}; +use crate::core::session::{DependencyType, FileType, Mode}; +use crate::trace; use crate::utils::build_stamp::{self, BuildStamp}; use crate::utils::channel::{self, Info}; use crate::utils::exec::{BootstrapCommand, command}; @@ -45,7 +47,6 @@ use crate::utils::helpers::{ exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit, }; use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball}; -use crate::{DependencyType, FileType, Mode, trace}; pub(crate) const LLVM_TOOLS: &[&str] = &[ "llvm-cov", // used to generate coverage report diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index adff654fe88e8..b80a0b0ba27c8 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -21,8 +21,8 @@ use crate::core::builder::{ }; use crate::core::compiler::Compiler; use crate::core::config::{Config, TargetSelection}; +use crate::core::session::{FileType, Mode}; use crate::utils::helpers::{submodule_path_of, symlink_dir, t, up_to_date}; -use crate::{FileType, Mode}; macro_rules! book { ($($name:ident, $path:expr, $book_name:expr, $lang:expr ;)+) => { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 323cce1da51ab..5d188bcd25570 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -21,12 +21,13 @@ use crate::core::builder::{ Builder, CommandLineStep, Kind, RunConfig, ShouldRun, Step, StepMetadata, }; use crate::core::config::{Config, LlvmCiMode, LlvmPgoGenerationMode, TargetSelection}; +use crate::core::session::{CLang, GitRepo}; +use crate::trace; use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash}; use crate::utils::exec::command; use crate::utils::helpers::{ self, exe, get_clang_cl_resource_dir, libdir, t, unhashed_basename, up_to_date, }; -use crate::{CLang, GitRepo, trace}; /// Path where a file containing the link type (dynamic or static) is stored in the LLVM CI tarball. pub const LLVM_CI_LINK_TYPE_PATH: &str = "link-type.txt"; diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 82a132d0b5288..243b09acaa308 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -8,7 +8,6 @@ use std::path::PathBuf; use build_helper::git::get_git_untracked_files; use clap_complete::{Generator, shells}; -use crate::Mode; use crate::core::build_steps::dist::distdir; use crate::core::build_steps::test; use crate::core::build_steps::tool::{self, RustcPrivateCompilers, SourceType, Tool}; @@ -16,6 +15,7 @@ use crate::core::build_steps::vendor::{VENDOR_DIR, Vendor, default_paths_to_vend use crate::core::builder::{Builder, CommandLineStep, Kind, RunConfig, ShouldRun, StepMetadata}; use crate::core::config::TargetSelection; use crate::core::config::flags::{get_completion, top_level_help}; +use crate::core::session::Mode; use crate::utils::exec::command; use crate::utils::helpers::{self, t}; diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a4eefe51c420e..be3dc2954086c 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -38,6 +38,7 @@ use crate::core::builder::{ use crate::core::compiler::Compiler; use crate::core::config::TargetSelection; use crate::core::config::flags::{Subcommand, get_completion, top_level_help}; +use crate::core::session::{CLang, GitRepo, Mode}; use crate::core::{android, debuggers}; use crate::utils::build_stamp::{self, BuildStamp}; use crate::utils::exec::{BootstrapCommand, command}; @@ -47,7 +48,6 @@ use crate::utils::helpers::{ target_supports_cranelift_backend, up_to_date, }; use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; -use crate::{CLang, GitRepo, Mode}; mod compiletest; pub mod failed_tests; diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index b67d1b1bd49e7..4e94a422fd153 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -23,9 +23,9 @@ use crate::core::builder::{ }; use crate::core::compiler::Compiler; use crate::core::config::{Allocator, DebuginfoLevel, RustcLto, TargetSelection}; +use crate::core::session::{FileType, Mode}; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{self, add_dylib_path, exe, t}; -use crate::{FileType, Mode}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum SourceType { diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index f5c28c8e0445e..7b621a2ecc834 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -11,10 +11,10 @@ use crate::core::compiler::Compiler; use crate::core::config::flags::{Color, Subcommand}; use crate::core::config::toml::pgo::PgoConfig; use crate::core::config::{CompressDebuginfo, Config, DryRun, SplitDebuginfo, TargetSelection}; +use crate::core::session::{CLang, GitRepo, Mode, RemapScheme}; use crate::utils::build_stamp; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{self, LldThreads, check_cfg_arg, envify, linker_flags, t}; -use crate::{CLang, GitRepo, Mode, RemapScheme}; /// Extra `--check-cfg` to add when building the compiler or tools /// (Mode restriction, config name, config values (if any)) diff --git a/src/bootstrap/src/core/builder/cli_paths/tests.rs b/src/bootstrap/src/core/builder/cli_paths/tests.rs index e18a274c75f49..3a92bf37bdf0a 100644 --- a/src/bootstrap/src/core/builder/cli_paths/tests.rs +++ b/src/bootstrap/src/core/builder/cli_paths/tests.rs @@ -2,8 +2,8 @@ use std::collections::{BTreeSet, HashSet}; use std::path::PathBuf; use std::sync::{Arc, Mutex}; -use crate::Build; use crate::core::builder::{Builder, CommandLineStepDescription}; +use crate::core::session::Build; use crate::utils::tests::TestCtx; fn render_steps_for_cli_args(args_str: &str) -> String { diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 3d581fe1e1061..98fceeae9df5c 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -25,12 +25,13 @@ use crate::core::compiler::Compiler; use crate::core::config::flags::Subcommand; use crate::core::config::{DryRun, TargetSelection}; use crate::core::metadata::Crate; +use crate::core::session::Build; +use crate::trace; use crate::utils::build_stamp::BuildStamp; use crate::utils::cache::Cache; use crate::utils::exec::{BootstrapCommand, ExecutionContext, command}; use crate::utils::helpers::{self, LldThreads, add_dylib_path, exe, libdir, linker_args, t}; use crate::utils::tracing::format_location; -use crate::{Build, trace}; mod cargo; mod cli_paths; diff --git a/src/bootstrap/src/core/compiler.rs b/src/bootstrap/src/core/compiler.rs index a57c60465f24c..5602e8ffd1efd 100644 --- a/src/bootstrap/src/core/compiler.rs +++ b/src/bootstrap/src/core/compiler.rs @@ -1,7 +1,7 @@ use std::hash::{Hash, Hasher}; -use crate::Build; use crate::core::config::TargetSelection; +use crate::core::session::Build; /// A structure representing a Rust compiler. /// diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 8ca1c74b929e3..f74def6a61d8b 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1845,7 +1845,7 @@ NOTE: Please add `--stage 2` to your command line, or if you're sure you want to /// /// This *does not* update the submodule if `bootstrap.toml` explicitly says /// not to, or if we're not in a git repository (like a plain source - /// tarball). Typically [`crate::Build::require_submodule`] should be + /// tarball). Typically [`crate::core::session::Build::require_submodule`] should be /// used instead to provide a nice error to the user if the submodule is /// missing. #[cfg_attr( diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 56c2541161cec..da479251c68ab 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -10,7 +10,6 @@ use clap_complete::Generator; #[cfg(feature = "tracing")] use tracing::instrument; -use crate::Build; use crate::core::backend::CodegenBackendKind; use crate::core::build_steps::perf::PerfArgs; use crate::core::build_steps::setup::Profile; @@ -18,6 +17,7 @@ use crate::core::build_steps::test::TestTarget; use crate::core::builder::{Builder, Kind}; use crate::core::config::Config; use crate::core::config::target_selection::{TargetSelectionList, target_selection_list}; +use crate::core::session::Build; use crate::utils::helpers; #[derive(Copy, Clone, Default, Debug, ValueEnum)] diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index a3b52e1071d24..5e88277008971 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -11,7 +11,7 @@ use std::path::PathBuf; use serde_derive::Deserialize; -use crate::Build; +use crate::core::session::Build; use crate::utils::exec::command; use crate::utils::helpers::t; diff --git a/src/bootstrap/src/core/mod.rs b/src/bootstrap/src/core/mod.rs index d6db6c701cc35..3c79dad5b00b6 100644 --- a/src/bootstrap/src/core/mod.rs +++ b/src/bootstrap/src/core/mod.rs @@ -8,3 +8,6 @@ pub(crate) mod debuggers; pub(crate) mod download; pub(crate) mod metadata; pub(crate) mod sanity; +pub(crate) mod session { + pub(crate) use crate::*; +} diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index a8359ad34fa50..456019fc96977 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -14,11 +14,11 @@ use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use std::{env, fs}; -use crate::Build; use crate::core::build_steps::tool; use crate::core::builder::Builder; use crate::core::config::flags::Subcommand; use crate::core::config::{CompilerBuiltins, DebuggerPath, Target}; +use crate::core::session::Build; use crate::utils::exec::command; use crate::utils::helpers::{self, t}; diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs index d27d5fa2cf420..36a3d0772e5ad 100644 --- a/src/bootstrap/src/utils/build_stamp.rs +++ b/src/bootstrap/src/utils/build_stamp.rs @@ -7,11 +7,11 @@ use std::{fs, io}; use sha2::digest::Digest; -use crate::Mode; use crate::core::backend::CodegenBackendKind; use crate::core::builder::Builder; use crate::core::compiler::Compiler; use crate::core::config::TargetSelection; +use crate::core::session::Mode; use crate::utils::helpers::{self, hex_encode, mtime, t}; #[cfg(test)] diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 977b4a31eadc4..e753ee71683fd 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -27,8 +27,8 @@ use std::path::{Path, PathBuf}; use crate::core::config::flags::Subcommand; use crate::core::config::{CompressDebuginfo, TargetSelection}; +use crate::core::session::{Build, CLang, GitRepo}; use crate::utils::exec::{BootstrapCommand, command}; -use crate::{Build, CLang, GitRepo}; /// Creates and configures a new [`cc::Build`] instance for the given target. fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index a2f35e6a1030d..716407cb0cb1c 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -2,8 +2,8 @@ use std::iter; use std::path::PathBuf; use super::*; -use crate::Build; use crate::core::config::{Target, TargetSelection}; +use crate::core::session::Build; use crate::utils::tests::TestCtx; #[test] diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index 21b4257e54d0b..ebb40edf9b262 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -10,7 +10,7 @@ use std::path::Path; use super::exec::ExecutionContext; use super::helpers; -use crate::Build; +use crate::core::session::Build; use crate::utils::helpers::t; #[derive(Clone, Default)] diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs index 887deb41ca8bc..942ac6c80e4ee 100644 --- a/src/bootstrap/src/utils/job.rs +++ b/src/bootstrap/src/utils/job.rs @@ -1,11 +1,13 @@ #[cfg(windows)] pub use for_windows::*; +use crate::core::session::Build; + #[cfg(any(target_os = "haiku", target_os = "hermit", not(any(unix, windows))))] -pub unsafe fn setup(_build: &mut crate::Build) {} +pub unsafe fn setup(_build: &mut Build) {} #[cfg(all(unix, not(target_os = "haiku")))] -pub unsafe fn setup(build: &mut crate::Build) { +pub unsafe fn setup(build: &mut Build) { if build.config.low_priority { unsafe { libc::setpriority(libc::PRIO_PGRP as _, 0, 10); @@ -58,9 +60,7 @@ mod for_windows { use windows::Win32::System::Threading::{BELOW_NORMAL_PRIORITY_CLASS, GetCurrentProcess}; use windows::core::PCWSTR; - use crate::Build; - - pub unsafe fn setup(build: &mut Build) { + pub unsafe fn setup(build: &mut super::Build) { // SAFETY: pretty much everything below is unsafe unsafe { // Enable the Windows Error Reporting dialog which msys disables, diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index e685c64733c66..a309b1d53b8e9 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -16,8 +16,8 @@ use build_helper::metrics::{ }; use sysinfo::{CpuRefreshKind, RefreshKind, System}; -use crate::Build; use crate::core::builder::{Builder, Step}; +use crate::core::session::Build; use crate::utils::helpers::t; // Update this number whenever a breaking change is made to the build metrics. diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 41ad6b022ac18..3ba7dbdb984c8 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -7,10 +7,10 @@ use std::path::{Path, PathBuf}; -use crate::FileType; use crate::core::build_steps::dist::distdir; use crate::core::builder::{Builder, Kind}; use crate::core::config::BUILDER_CONFIG_FILENAME; +use crate::core::session::FileType; use crate::utils::channel; use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{self, move_file, t}; From f068a507f43170b5f853077a0050ff47600c89d6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 18 Aug 2026 17:00:44 +1000 Subject: [PATCH 25/32] Temporarily rename `lib.rs` to `session.rs` This intermediate commit helps to preserve line history. --- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/src/{lib.rs => session.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/bootstrap/src/{lib.rs => session.rs} (100%) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 4dcf87e3290a2..8379b441008cb 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -10,7 +10,7 @@ build-metrics = ["dep:sysinfo", "build_helper/metrics"] tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:chrono"] [lib] -path = "src/lib.rs" +path = "src/session.rs" doctest = false [[bin]] diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/session.rs similarity index 100% rename from src/bootstrap/src/lib.rs rename to src/bootstrap/src/session.rs From 91374a526c3b755b0e1e0ce78afb5e413bd933b7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 18 Aug 2026 17:00:44 +1000 Subject: [PATCH 26/32] Move all non-module items out of the crate root --- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/src/core/mod.rs | 4 +--- src/bootstrap/src/{ => core}/session.rs | 30 +++---------------------- src/bootstrap/src/lib.rs | 26 +++++++++++++++++++++ 4 files changed, 31 insertions(+), 31 deletions(-) rename src/bootstrap/src/{ => core}/session.rs (98%) create mode 100644 src/bootstrap/src/lib.rs diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 8379b441008cb..4dcf87e3290a2 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -10,7 +10,7 @@ build-metrics = ["dep:sysinfo", "build_helper/metrics"] tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:chrono"] [lib] -path = "src/session.rs" +path = "src/lib.rs" doctest = false [[bin]] diff --git a/src/bootstrap/src/core/mod.rs b/src/bootstrap/src/core/mod.rs index 3c79dad5b00b6..c130051a8c7c4 100644 --- a/src/bootstrap/src/core/mod.rs +++ b/src/bootstrap/src/core/mod.rs @@ -8,6 +8,4 @@ pub(crate) mod debuggers; pub(crate) mod download; pub(crate) mod metadata; pub(crate) mod sanity; -pub(crate) mod session { - pub(crate) use crate::*; -} +pub(crate) mod session; diff --git a/src/bootstrap/src/session.rs b/src/bootstrap/src/core/session.rs similarity index 98% rename from src/bootstrap/src/session.rs rename to src/bootstrap/src/core/session.rs index 1fe73fb78f819..3e6668258c641 100644 --- a/src/bootstrap/src/session.rs +++ b/src/bootstrap/src/core/session.rs @@ -1,26 +1,3 @@ -//! Implementation of bootstrap, the Rust build system. -//! -//! This module, and its descendants, are the implementation of the Rust build -//! system. Most of this build system is backed by Cargo but the outer layer -//! here serves as the ability to orchestrate calling Cargo, sequencing Cargo -//! builds, building artifacts like LLVM, etc. The goals of bootstrap are: -//! -//! * To be an easily understandable, easily extensible, and maintainable build -//! system. -//! * Leverage standard tools in the Rust ecosystem to build the compiler, aka -//! crates.io and Cargo. -//! * A standard interface to build across all platforms, including MSVC -//! -//! ## Further information -//! -//! More documentation can be found in each respective module below, and you can -//! also check out the `src/bootstrap/README.md` file for more information. - -// tidy-alphabetical-start -#![allow(clippy::assertions_on_constants, reason = "false positive for `assert!(cfg!(..))`")] -#![allow(clippy::map_clone, reason = "false positive for `|x: &&Foo| Foo::clone(x)`")] -// tidy-alphabetical-end - use std::cell::Cell; use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::Display; @@ -42,16 +19,15 @@ use crate::core::compiler::Compiler; use crate::core::config::flags::{self, Subcommand}; use crate::core::config::{BootstrapOverrideLld, Config, DryRun, LlvmLibunwind, TargetSelection}; use crate::core::metadata::Crate; +#[cfg(feature = "tracing")] +use crate::trace_io; use crate::utils::build_stamp::BuildStamp; use crate::utils::channel::GitInfo; use crate::utils::exec::{BootstrapCommand, ExecutionContext, command}; use crate::utils::helpers::{ self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo, symlink_dir, t, }; - -pub mod cli_main; -mod core; -mod utils; +use crate::{debug, trace}; pub(crate) enum GitRepo { Rustc, diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs new file mode 100644 index 0000000000000..cafe81af4d56e --- /dev/null +++ b/src/bootstrap/src/lib.rs @@ -0,0 +1,26 @@ +//! Implementation of bootstrap, the Rust build system. +//! +//! This module, and its descendants, are the implementation of the Rust build +//! system. Most of this build system is backed by Cargo but the outer layer +//! here serves as the ability to orchestrate calling Cargo, sequencing Cargo +//! builds, building artifacts like LLVM, etc. The goals of bootstrap are: +//! +//! * To be an easily understandable, easily extensible, and maintainable build +//! system. +//! * Leverage standard tools in the Rust ecosystem to build the compiler, aka +//! crates.io and Cargo. +//! * A standard interface to build across all platforms, including MSVC +//! +//! ## Further information +//! +//! More documentation can be found in each respective module below, and you can +//! also check out the `src/bootstrap/README.md` file for more information. + +// tidy-alphabetical-start +#![allow(clippy::assertions_on_constants, reason = "false positive for `assert!(cfg!(..))`")] +#![allow(clippy::map_clone, reason = "false positive for `|x: &&Foo| Foo::clone(x)`")] +// tidy-alphabetical-end + +pub mod cli_main; +mod core; +mod utils; From 0ff906ae755fd8a5a12215ecc105e2b97650e4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 20 Aug 2026 10:47:44 +0200 Subject: [PATCH 27/32] Configure LLM policy URL for triagebot --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index a842b2a07c15f..4990c72ffce6c 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1581,6 +1581,7 @@ cc = ["@rust-lang/wg-const-eval"] [assign] warn_non_default_branch.enable = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" +llm_policy_url = "https://forge.rust-lang.org/policies/llm-usage.html" [[assign.warn_non_default_branch.exceptions]] title = "[beta" From ac623ff4034caeee28f423ae7800e8516cbc0078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Sanz=20Gonz=C3=A1lez?= <80487270+hsanzg@users.noreply.github.com> Date: Wed, 19 Aug 2026 19:40:05 +0200 Subject: [PATCH 28/32] Double-word align `_Unwind_Exception` --- library/unwind/src/types.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/unwind/src/types.rs b/library/unwind/src/types.rs index 7634052c93f33..d745b836e822b 100644 --- a/library/unwind/src/types.rs +++ b/library/unwind/src/types.rs @@ -42,6 +42,12 @@ pub const unwinder_private_data_size: usize = cfg_select! { }; #[repr(C)] +// The Itanium C++ ABI requires this type to have "double-word" alignment, +// which libunwind and libgcc interpret as the maximum alignment of any +// scalar type on the current target. +#[cfg_attr(target_pointer_width = "16", repr(align(4)))] +#[cfg_attr(target_pointer_width = "32", repr(align(8)))] +#[cfg_attr(target_pointer_width = "64", repr(align(16)))] pub struct _Unwind_Exception { pub exception_class: _Unwind_Exception_Class, pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, From ed151ed962581e8e995ea70b55ea1affa7c4e466 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 14 Feb 2026 14:58:58 +0100 Subject: [PATCH 29/32] std: update definitions on Fuchsia --- library/std/src/sys/pal/unix/fuchsia.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/pal/unix/fuchsia.rs b/library/std/src/sys/pal/unix/fuchsia.rs index c118dee624764..8b0e9cb1ff10a 100644 --- a/library/std/src/sys/pal/unix/fuchsia.rs +++ b/library/std/src/sys/pal/unix/fuchsia.rs @@ -9,12 +9,12 @@ use crate::io; // Time // ////////// -pub type zx_time_t = i64; +pub type zx_instant_mono_t = i64; -pub const ZX_TIME_INFINITE: zx_time_t = i64::MAX; +pub const ZX_TIME_INFINITE: zx_instant_mono_t = i64::MAX; unsafe extern "C" { - pub safe fn zx_clock_get_monotonic() -> zx_time_t; + pub safe fn zx_clock_get_monotonic() -> zx_instant_mono_t; } ///////////// @@ -62,7 +62,7 @@ unsafe extern "C" { pub fn zx_object_wait_one( handle: zx_handle_t, signals: zx_signals_t, - timeout: zx_time_t, + deadline: zx_instant_mono_t, pending: *mut zx_signals_t, ) -> zx_status_t; @@ -70,7 +70,7 @@ unsafe extern "C" { value_ptr: *const zx_futex_t, current_value: zx_futex_t, new_futex_owner: zx_handle_t, - deadline: zx_time_t, + deadline: zx_instant_mono_t, ) -> zx_status_t; pub fn zx_futex_wake(value_ptr: *const zx_futex_t, wake_count: u32) -> zx_status_t; pub fn zx_futex_wake_single_owner(value_ptr: *const zx_futex_t) -> zx_status_t; @@ -117,7 +117,7 @@ pub type zx_info_process_flags_t = u32; #[repr(C)] pub struct zx_info_process_t { pub return_code: i64, - pub start_time: zx_time_t, + pub start_time: zx_instant_mono_t, pub flags: zx_info_process_flags_t, pub reserved1: u32, } From 95d6b37a456fb809406edb327a8ce358e6d41d16 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 14 Feb 2026 15:04:06 +0100 Subject: [PATCH 30/32] std: implement `sleep_until` for Fuchsia --- library/std/src/sys/pal/unix/fuchsia.rs | 1 + library/std/src/sys/thread/mod.rs | 4 +++- library/std/src/sys/thread/unix.rs | 10 ++++++++++ library/std/src/sys/time/unix.rs | 5 +++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/fuchsia.rs b/library/std/src/sys/pal/unix/fuchsia.rs index 8b0e9cb1ff10a..f9dfd52a610bb 100644 --- a/library/std/src/sys/pal/unix/fuchsia.rs +++ b/library/std/src/sys/pal/unix/fuchsia.rs @@ -15,6 +15,7 @@ pub const ZX_TIME_INFINITE: zx_instant_mono_t = i64::MAX; unsafe extern "C" { pub safe fn zx_clock_get_monotonic() -> zx_instant_mono_t; + pub safe fn zx_nanosleep(deadline: zx_instant_mono_t) -> zx_status_t; } ///////////// diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index 9816981c7fc88..1ae0da23fe5e1 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -73,6 +73,7 @@ cfg_select! { target_os = "vxworks", target_os = "wasi", target_vendor = "apple", + target_os = "fuchsia", ))] pub use unix::sleep_until; #[expect(dead_code)] @@ -134,7 +135,8 @@ cfg_select! { target_os = "wasi", target_vendor = "apple", target_os = "motor", - target_os = "vexos" + target_os = "vexos", + target_os = "fuchsia", )))] pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 2dbb0314cb271..4988b32a431df 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -778,6 +778,16 @@ pub fn sleep_until(deadline: crate::time::Instant) { } } +#[cfg(target_os = "fuchsia")] +pub fn sleep_until(deadline: crate::time::Instant) { + use crate::sys::pal::fuchsia::{zx_cvt, zx_nanosleep}; + + let deadline = deadline.into_inner().into_deadline(); + if let Err(error) = zx_cvt(zx_nanosleep(deadline)) { + panic!("zx_nanosleep failed: {error}"); + } +} + pub fn yield_now() { let ret = unsafe { libc::sched_yield() }; debug_assert_eq!(ret, 0); diff --git a/library/std/src/sys/time/unix.rs b/library/std/src/sys/time/unix.rs index 944cb552cad9e..d84256df0cd53 100644 --- a/library/std/src/sys/time/unix.rs +++ b/library/std/src/sys/time/unix.rs @@ -123,6 +123,11 @@ impl Instant { // 126 bits. Some((nanos * u128::from(timebase.denom)).div_ceil(u128::from(timebase.numer))) } + + #[cfg(target_os = "fuchsia")] + pub fn into_deadline(self) -> crate::sys::pal::fuchsia::zx_instant_mono_t { + self.t.tv_sec.saturating_mul(1_000_000_000).saturating_add(self.t.tv_nsec.as_inner().into()) + } } impl AsInner for Instant { From 1c0a0d9a1229869297c760fc73adc98c267dc47c Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 21 May 2026 15:48:26 +0200 Subject: [PATCH 31/32] std: update `sleep_until` syscall table --- library/std/src/thread/functions.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/library/std/src/thread/functions.rs b/library/std/src/thread/functions.rs index 355a00c2a95ad..6a940f9b677b6 100644 --- a/library/std/src/thread/functions.rs +++ b/library/std/src/thread/functions.rs @@ -313,19 +313,21 @@ pub fn sleep(dur: Duration) { /// /// | Platform | System call | /// |-----------|----------------------------------------------------------------------| -/// | Linux | [clock_nanosleep] (Monotonic Clock) | -/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock) | -/// | Android | [clock_nanosleep] (Monotonic Clock) | -/// | Solaris | [clock_nanosleep] (Monotonic Clock) | -/// | Illumos | [clock_nanosleep] (Monotonic Clock) | -/// | Dragonfly | [clock_nanosleep] (Monotonic Clock) | -/// | Hurd | [clock_nanosleep] (Monotonic Clock) | -/// | Vxworks | [clock_nanosleep] (Monotonic Clock) | +/// | Linux | [`clock_nanosleep`] (Monotonic Clock) | +/// | BSD except OpenBSD | [`clock_nanosleep`] (Monotonic Clock) | +/// | Android | [`clock_nanosleep`] (Monotonic Clock) | +/// | Solaris | [`clock_nanosleep`] (Monotonic Clock) | +/// | Illumos | [`clock_nanosleep`] (Monotonic Clock) | +/// | Dragonfly | [`clock_nanosleep`] (Monotonic Clock) | +/// | Hurd | [`clock_nanosleep`] (Monotonic Clock) | +/// | Vxworks | [`clock_nanosleep`] (Monotonic Clock) | /// | Apple | `mach_wait_until` | +/// | Fuchsia | [`zx_nanosleep`] | /// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself | /// /// [currently]: crate::io#platform-specific-behavior -/// [clock_nanosleep]: https://linux.die.net/man/3/clock_nanosleep +/// [`clock_nanosleep`]: https://linux.die.net/man/3/clock_nanosleep +/// [`zx_nanosleep`]: https://fuchsia.dev/reference/syscalls/nanosleep /// /// **Disclaimer:** These system calls might change over time. /// From 2d28ce9ee7a5fcad7e09641d7c2738a7ecaeb931 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 20 Aug 2026 13:37:44 +0200 Subject: [PATCH 32/32] std: add a comment about elapsed deadlines for `sleep_until` --- library/std/src/thread/functions.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/thread/functions.rs b/library/std/src/thread/functions.rs index 355a00c2a95ad..918c266cdbd34 100644 --- a/library/std/src/thread/functions.rs +++ b/library/std/src/thread/functions.rs @@ -295,9 +295,10 @@ pub fn sleep(dur: Duration) { /// Puts the current thread to sleep until the specified deadline has passed. /// -/// The thread may still be asleep after the deadline specified due to -/// scheduling specifics or platform-dependent functionality. It will never -/// wake before. +/// If the deadline has already passed at the time this function is called, it +/// will return immediately. Note that the thread may still be asleep after the +/// deadline specified due to scheduling specifics or platform-dependent +/// functionality. It will never wake before. /// /// This function is blocking, and should not be used in `async` functions. ///