From ec5375fc55802290738b710ae285e78244e141f5 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Thu, 11 Sep 2025 21:51:13 +0100 Subject: [PATCH 01/11] Add general arm-linux.md platform doc. Covers all Arm Linux systems, and means that we can reduce the amount of information required in the target specific pages to just the Tier level, the maintainer, and any specific details for that target. --- src/doc/rustc/src/SUMMARY.md | 9 +- .../rustc/src/platform-support/arm-linux.md | 217 ++++++++++++++++++ .../armeb-unknown-linux-gnueabi.md | 3 + .../armv5te-unknown-linux-gnueabi.md | 3 + .../armv7-unknown-linux-uclibceabi.md | 3 + .../armv7-unknown-linux-uclibceabihf.md | 3 + 6 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 src/doc/rustc/src/platform-support/arm-linux.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 8e378e53e518a..fc3f71b4a6a8a 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -51,7 +51,6 @@ - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md) - [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md) - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md) - - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) - [arm-none-eabi](platform-support/arm-none-eabi.md) - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) @@ -62,12 +61,14 @@ - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md) - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md) - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md) - - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md) + - [arm\*-unknown-linux-\*](./platform-support/arm-linux.md) + - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) + - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md) + - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) + - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md) - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md) - - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) - - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [armv7a-vex-v5](platform-support/armv7a-vex-v5.md) - [\*-android and \*-androideabi](platform-support/android.md) - [\*-linux-ohos](platform-support/openharmony.md) diff --git a/src/doc/rustc/src/platform-support/arm-linux.md b/src/doc/rustc/src/platform-support/arm-linux.md new file mode 100644 index 0000000000000..5f320762e9378 --- /dev/null +++ b/src/doc/rustc/src/platform-support/arm-linux.md @@ -0,0 +1,217 @@ +# Arm Linux support in Rust + +The Arm Architecture has been around since the mid-1980s, going through nine +major revisions, many minor revisions, and spanning both 32-bith and 64-bit +architectures. This page covers 32-bit Arm platforms that run some form of +Linux (but not Android). Those targets are: + +* `arm-unknown-linux-gnueabi` +* `arm-unknown-linux-gnueabihf` +* `arm-unknown-linux-musleabi` +* `arm-unknown-linux-musleabihf` +* [`armeb-unknown-linux-gnueabi`](armeb-unknown-linux-gnueabi.md) +* `armv4t-unknown-linux-gnueabi` +* [`armv5te-unknown-linux-gnueabi`](armv5te-unknown-linux-gnueabi.md) +* `armv5te-unknown-linux-musleabi` +* `armv5te-unknown-linux-uclibceabi` +* `armv7-unknown-linux-gnueabi` +* `armv7-unknown-linux-gnueabihf` +* `armv7-unknown-linux-musleabi` +* `armv7-unknown-linux-musleabihf` +* `armv7-unknown-linux-ohos` +* [`armv7-unknown-linux-uclibceabi`](armv7-unknown-linux-uclibceabi.md) +* [`armv7-unknown-linux-uclibceabihf`](armv7-unknown-linux-uclibceabihf.md) +* `thumbv7neon-unknown-linux-gnueabihf` +* `thumbv7neon-unknown-linux-musleabihf` + +Some of these targets have dedicated pages and some do not. This is largely +due to historical accident, or the enthusiasm of the maintainers. This +document attempts to cover all the targets, but only in broad terms. + +To make sense of this list, the architecture and ABI component of the +`-unknown-linux-` tuple will be discussed separately. + +The second part of the tuple is `unknown` because these systems don't come +from any one specific vendor (like `powerpc-ibm-aix` or +`aarch64-apple-darwin`). The third part is `linux`, because this page only +discusses Linux targets. + +## Architecture Component + +* `arm` +* `armeb` +* `armv4t` +* `armv5te` +* `armv7` +* `thumbv7neon` + +The architecture component simply called `arm` corresponds to the Armv6 +architecture - that is, version 6 of the Arm Architecture as defined in +version 6 of the Arm Architecture Reference Manual (the Arm ARM). This was the +last 'legacy' release of the Arm architecture, before they split into +Application, Real-Time and Microcontroller profiles (leading to Armv7-A, +Armv7-R and Armv7-M). Processors that implement the Armv6 architecture include +the ARM1176JZF-S, as found in BCM2835 SoC that powers the Raspberry Pi Zero. +Arm processors are generally fairly backwards compatible, especially for +user-mode code, so code compiled for the `arm` architecture should also work +on newer ARMv7-A systems, or even 64/32-bit Armv8-A systems. + +The `armeb` architecture component specifies an Armv6 processor running in Big +Endian mode (`eb` is for big-endian - the letters are backwards because +engineers used to little-endian systems perceive big-endian numbers to be +written into memory backwards, and they thought it was funnier like that). +Most Arm processors can operate in either little-endian or big-endian mode and +little-endian mode is by far the most common. However, if for whatever reason +you wish to store your Most Significant Bytes first, these targets are +available. They just aren't terribly well tested, or compatible with most +existing pre-compiled Arm libraries. + +Targets that start with `armv4t` are for processors implementing the Armv4T +architecture from 1994. These include the ARM7TDMI, as found in the Nokia 6110 +brick-phone and the Game Boy Advance. The 'T' stands for *Thumb* and indicate +that the processors can execute smaller 16-bit versions of some of the 32-bit +Arm instructions. Because a Thumb is like a small version of an Arm. + +Targets that start with `armv5te` are for processors implementing the Armv5TE +architecture. These are mostly from the ARM9 family, like the ARM946E-S found +in the Nintendo DS. If you are programming an Arm machine from the early +2000s, this might be what you need. + +The `armv7` is arguably a misnomer, and it should be `armv7a`. This is because +it corresponds to the Application profile of Armv7 (i.e. Armv7-A), as opposed +to the Real-Time or Microcontroller profile. Processors implementing this +architecture include the Cortex-A7 and Cortex-A8. + +The `thumbv7neon` component indicates support for a processor that implements +ARMv7-A (the same as `armv7`), it generates Thumb instructions (technically +Thumb-2, also known as the T32 ISA) as opposed to Arm instructions (also known +as the A32 ISA). These instructions are smaller, giving more code per KB of +RAM, but may have a performance penalty if they take two instructions to do +something Arm instructions could do in one. It's a complex trade-off and you +should be doing benchmarks to work out which is better for you, if you +strongly care about code size and/or performance. This component also enables +support for Arm's SIMD extensions, known as Neon. These extensions will +improve performance for certain kinds of repetitive operations. + +## ABI Component + +* `gnueabi` +* `gnueabihf` +* `musleabi` +* `musleabihf` +* `ohos` +* `uclibceabi` +* `uclibceabihf` + +You will need to select the appropriate ABI to match the system you want to be +running this code on. For example, running `eabihf` code on an `eabi` system +will not work correctly. + +The `gnueabi` ABI component indicates support for using the GNU C Library +(glibc), and the Arm Embedded ABI (EABI). The EABI is a replacement of for the +original ABI (now called the Old ABI or OABI), and it is the standard ABI for +32-bit Arm systems. With this ABI, function parameters that are `f32` or `f64` +are passed as if they were integers, instead of being passed via in FPU +registers. Generally these targets also disable the use of the FPU entirely, +although that isn't always true. + +The `gnueabihf` ABI component is like `gnueabi`, except that it support the +'hard-float' of the EABI. That is, function parameters that are `f32` or `f64` +are passed in FPU registers. Naturally, this makes the FPU mandatory. + +Most 'desktop' Linux distributions (Debian, Ubuntu, Fedora, etc) use the GNU C +Library and so you should probably select either `gnueabi` or `gnueabihf`, +depending on whether your distribution is using 'soft-float' (EABI) or +'hard-float' (EABIHF). Debian happens to offer +[both](https://wiki.debian.org/ArmEabiPort) +[kinds](https://wiki.debian.org/ArmHardFloatPort). + +The `musleabi` and `musleabihf` ABI components offer support for the [musl C +library](https://musl.libc.org/). This C library can be used to create 'static +binaries' that have no run-time library requirements (a feature that that +glibc does not support). There are soft-float (`eabi`) and hard-float +(`eabihf`) variants, as per the `gnu*` targets above. + +The `uclibceabi` and `uclibceabihf` ABI components are for the [uClibc-ng C +library](https://uclibc-ng.org/). This is sometimes used in light-weight +embedded Linux distributions, like those created with +[buildroot](https://www.buildroot.org/). + +## Cross Compilation + +Unfortunately, 32-bit Arm machines are generally not the fastest around, and +they don't have much RAM. This means you are likely to be cross-compiling. + +To do this, you need to give Rust a suitable linker to use - one that knows +the Arm architecture, and more importantly, knows where to find a suitable C +Library to link against. + +To do that, you can add the `linker` property to your `.cargo/config.toml`. +Typically you would refer to a suitable copy of GCC that has built as a +cross-compiler, alongside a C library. + +```toml +[target.arm-unknown-linux-gnueabi] +linker = "arm-linux-gnueabi-gcc" +``` + +On Debian Linux, you could install such a cross-compilation toolchain with +`apt install gcc-arm-linux-gnueabi`. For more exotic combinations, you might +need to build a bespoke version of GCC using [crosstool-ng]. + +[crosstool-ng]: https://github.com/crosstool-ng/crosstool-ng + +Note that for GCC, all 32-bit Arm architectures are handled in the same build +- there are no separate Armv4T or Armv6 builds of GCC. The architecture is +selected with flags, like `-march=armv6`, but they aren't required for the +linker. + +Let's assume we are on some Debian machine, and we want to build a basic Arm +Linux binary for a distribution using the GNU C Library, targeting Armv6 with +a hard-float ABI. Such a binary should work on a Raspberry Pi, for example. +The commands are: + +```bash +sudo apt install -y gcc-arm-linux-gnueabihf +rustup target add arm-unknown-linux-gnueabihf +cargo new --bin armdemo +cd armdemo +mkdir .cargo +cat > .cargo/config.toml << EOF +[target.arm-unknown-linux-gnueabihf] +linker = "arm-linux-gnueabihf-gcc" +EOF +cargo build --target=arm-unknown-linux-gnueabihf +``` + +This will give us our ARM Linux binary for the GNU C Library with a soft-float ABI: + +```console +$ file ./target/arm-unknown-linux-gnueabi/debug/armdemo +./target/arm-unknown-linux-gnueabi/debug/armdemo: ELF 32-bit LSB pie + executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter + /lib/ld-linux.so.3, BuildID[sha1]=dd0b9aa5ae876330fd4e2fcf393850f083ec7fcd, + for GNU/Linux 3.2.0, with debug_info, not stripped +``` + +If you are building C code as part of your Rust project, you may want to +direct `cc-rs` to use an appropriate cross-compiler with the `CROSS_COMPILE` +environment variable. You may also want to set the CFLAGS environment variable +for the target. For example: + +```bash +export CROSS_COMPILE=arm-linux-gnueabi +export CFLAGS_arm_unknown_linux_gnueabi="-march=armv6" +``` + +(Note that the dashes (`-`) turn to underscores (`_`) to form the name of the +CFLAGS environment variable) + +If you are building for a Tier 3 target using `-Zbuild-std` (on Nightly Rust), +you need to set these variables as well: + +```bash +export CXX_arm_unknown_linux_gnueabi=arm-linux-gnueabi-g++ +export CC_arm_unknown_linux_gnueabi=arm-linux-gnueabi-gcc +cargo +nightly build -Zbuild-std --target=arm-unknown-linux-gnueabi +``` diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md index 7c1c5db7076b6..cd0623f73a1db 100644 --- a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md +++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md @@ -3,6 +3,9 @@ Target for cross-compiling Linux user-mode applications targeting the Arm BE8 architecture. +See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux +targets. + ## Overview BE8 architecture retains the same little-endian ordered code-stream used by conventional little endian Arm systems, however the data accesses are in big-endian. BE8 is used primarily in high-performance networking applications where the ability to read packets in their native "Network Byte Order" is important (many network protocols transmit data in big-endian byte order for their wire formats). diff --git a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md index 0aebbc34d400b..a924f476411df 100644 --- a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md +++ b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md @@ -5,6 +5,9 @@ This target supports Linux programs with glibc on ARMv5TE CPUs without floating-point units. +See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux +targets. + ## Target maintainers There are currently no formally documented target maintainers. diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md index e553c49589de6..4ab0a07090a62 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md @@ -4,6 +4,9 @@ This target supports Armv7-A softfloat CPUs and uses the uclibc-ng standard library. This is a common configuration on many consumer routers (e.g., Netgear R7000, Asus RT-AC68U). +See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux +targets. + ## Target maintainers [@lancethepants](https://github.com/lancethepants) diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md index 91f3ea886ccb5..9fb24906b4fc3 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md @@ -4,6 +4,9 @@ This tier supports the Armv7-A processor running a Linux kernel and uClibc-ng standard library. It provides full support for rust and the rust standard library. +See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux +targets. + ## Target Maintainers [@skrap](https://github.com/skrap) From 4d273c4d91fc31b02c345f0dadea4a0b751f0238 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Fri, 12 Sep 2025 20:45:34 +0100 Subject: [PATCH 02/11] Fix two typos spotted in review --- src/doc/rustc/src/platform-support/arm-linux.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc/src/platform-support/arm-linux.md b/src/doc/rustc/src/platform-support/arm-linux.md index 5f320762e9378..5f40743f3d070 100644 --- a/src/doc/rustc/src/platform-support/arm-linux.md +++ b/src/doc/rustc/src/platform-support/arm-linux.md @@ -108,7 +108,7 @@ running this code on. For example, running `eabihf` code on an `eabi` system will not work correctly. The `gnueabi` ABI component indicates support for using the GNU C Library -(glibc), and the Arm Embedded ABI (EABI). The EABI is a replacement of for the +(glibc), and the Arm Embedded ABI (EABI). The EABI is a replacement for the original ABI (now called the Old ABI or OABI), and it is the standard ABI for 32-bit Arm systems. With this ABI, function parameters that are `f32` or `f64` are passed as if they were integers, instead of being passed via in FPU @@ -128,9 +128,9 @@ depending on whether your distribution is using 'soft-float' (EABI) or The `musleabi` and `musleabihf` ABI components offer support for the [musl C library](https://musl.libc.org/). This C library can be used to create 'static -binaries' that have no run-time library requirements (a feature that that -glibc does not support). There are soft-float (`eabi`) and hard-float -(`eabihf`) variants, as per the `gnu*` targets above. +binaries' that have no run-time library requirements (a feature that glibc +does not support). There are soft-float (`eabi`) and hard-float (`eabihf`) +variants, as per the `gnu*` targets above. The `uclibceabi` and `uclibceabihf` ABI components are for the [uClibc-ng C library](https://uclibc-ng.org/). This is sometimes used in light-weight From 5595f437c7b82b1ca18f77f8834fe9398b682153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 25 Sep 2025 18:12:39 +0200 Subject: [PATCH 03/11] Remove `verbose_than` function --- src/bootstrap/src/core/build_steps/compile.rs | 7 +------ src/bootstrap/src/lib.rs | 13 ++++--------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 14104d7d1d783..b47b4f248a9ac 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1902,12 +1902,7 @@ impl Step for Sysroot { if !path.parent().is_none_or(|p| p.ends_with(&suffix)) { return true; } - if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) { - builder.verbose_than(1, || println!("ignoring {}", path.display())); - false - } else { - true - } + filtered_files.iter().all(|f| f != path.file_name().unwrap()) }); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index e953fe2945e48..db963f9c6f990 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1092,13 +1092,6 @@ impl Build { self.verbosity > level } - /// Runs a function if verbosity is greater than `level`. - fn verbose_than(&self, level: usize, f: impl Fn()) { - if self.is_verbose_than(level) { - f() - } - } - fn info(&self, msg: &str) { match self.config.get_dry_run() { DryRun::SelfCheck => (), @@ -1816,7 +1809,6 @@ impl Build { if self.config.dry_run() { return; } - self.verbose_than(1, || println!("Copy/Link {src:?} to {dst:?}")); if src == dst { return; } @@ -1933,7 +1925,10 @@ impl Build { return; } let dst = dstdir.join(src.file_name().unwrap()); - self.verbose_than(1, || println!("Install {src:?} to {dst:?}")); + + #[cfg(feature = "tracing")] + let _span = trace_io!("install", ?src, ?dst); + t!(fs::create_dir_all(dstdir)); if !src.exists() { panic!("ERROR: File \"{}\" not found!", src.display()); From 5a6e3cccebd9cac06af815f0480ad58d14182480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 25 Sep 2025 18:14:33 +0200 Subject: [PATCH 04/11] Remove `is_verbose_than` function --- src/bootstrap/src/core/builder/cargo.rs | 2 +- src/bootstrap/src/lib.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index ee2bb710674c0..9fc4ce669c2a5 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -1139,7 +1139,7 @@ impl Builder<'_> { cargo.env("RUSTC_BACKTRACE_ON_ICE", "1"); } - if self.is_verbose_than(1) { + if self.verbosity >= 2 { // This provides very useful logs especially when debugging build cache-related stuff. cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info"); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index db963f9c6f990..75cc79e6689c8 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1087,11 +1087,6 @@ impl Build { }) } - /// Check if verbosity is greater than the `level` - pub fn is_verbose_than(&self, level: usize) -> bool { - self.verbosity > level - } - fn info(&self, msg: &str) { match self.config.get_dry_run() { DryRun::SelfCheck => (), From 0374df1b50d227f173c07631b390b271efb04ae6 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Fri, 5 Sep 2025 08:34:00 +0200 Subject: [PATCH 05/11] Introduce and use CmCell during import resolution. --- .../rustc_resolve/src/build_reduced_graph.rs | 19 +-- compiler/rustc_resolve/src/imports.rs | 26 ++-- compiler/rustc_resolve/src/lib.rs | 128 +++++++++++++++--- compiler/rustc_resolve/src/macros.rs | 2 +- 4 files changed, 135 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index fa3c06059b3da..c10b6ca7e71b5 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -5,7 +5,6 @@ //! unexpanded macros in the fragment are visited and registered. //! Imports are also considered items and placed into modules here, but not resolved yet. -use std::cell::Cell; use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; @@ -35,6 +34,7 @@ use crate::Namespace::{MacroNS, TypeNS, ValueNS}; use crate::def_collector::collect_definitions; use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; +use crate::ref_mut::CmCell; use crate::{ BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used, @@ -87,7 +87,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. let key = BindingKey::new_disambiguated(ident, ns, || { - parent.underscore_disambiguator.update(|d| d + 1); + // FIXME(batched): Will be fixed in batched resolution. + parent.underscore_disambiguator.update_unchecked(|d| d + 1); parent.underscore_disambiguator.get() }); if self @@ -477,7 +478,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind, parent_scope: self.parent_scope, module_path, - imported_module: Cell::new(None), + imported_module: CmCell::new(None), span, use_span: item.span, use_span_with_attributes: item.span_with_attributes(), @@ -505,7 +506,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); } } - ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(import), + ImportKind::Glob { .. } => current_module.globs.borrow_mut(self.r).push(import), _ => unreachable!(), } } @@ -668,7 +669,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ast::UseTreeKind::Glob => { if !ast::attr::contains_name(&item.attrs, sym::prelude_import) { - let kind = ImportKind::Glob { max_vis: Cell::new(None), id }; + let kind = ImportKind::Glob { max_vis: CmCell::new(None), id }; self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); } else { // Resolve the prelude import early. @@ -971,7 +972,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, parent_scope: self.parent_scope, - imported_module: Cell::new(module), + imported_module: CmCell::new(module), has_attributes: !item.attrs.is_empty(), use_span_with_attributes: item.span_with_attributes(), use_span: item.span, @@ -1103,7 +1104,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind: ImportKind::MacroUse { warn_private }, root_id: item.id, parent_scope: this.parent_scope, - imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), + imported_module: CmCell::new(Some(ModuleOrUniformRoot::Module(module))), use_span_with_attributes: item.span_with_attributes(), has_attributes: !item.attrs.is_empty(), use_span: item.span, @@ -1196,7 +1197,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { /// directly into its parent scope's module. fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'ra> { let invoc_id = self.visit_invoc(id); - self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); + self.parent_scope.module.unexpanded_invocations.borrow_mut(self.r).insert(invoc_id); self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) } @@ -1274,7 +1275,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind: ImportKind::MacroExport, root_id: item.id, parent_scope: self.parent_scope, - imported_module: Cell::new(None), + imported_module: CmCell::new(None), has_attributes: false, use_span_with_attributes: span, use_span: span, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d7fc028287ff5..2370bf8093943 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1,6 +1,5 @@ //! A bunch of methods and structures more or less related to resolving imports. -use std::cell::Cell; use std::mem; use rustc_ast::NodeId; @@ -32,6 +31,7 @@ use crate::errors::{ CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates, ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate, }; +use crate::ref_mut::CmCell; use crate::{ AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, @@ -68,7 +68,7 @@ pub(crate) enum ImportKind<'ra> { /// It will directly use `source` when the format is `use prefix::source`. target: Ident, /// Bindings introduced by the import. - bindings: PerNS>>, + bindings: PerNS>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -89,7 +89,7 @@ pub(crate) enum ImportKind<'ra> { Glob { // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. - max_vis: Cell>, + max_vis: CmCell>, id: NodeId, }, ExternCrate { @@ -182,7 +182,7 @@ pub(crate) struct ImportData<'ra> { /// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions | /// |`use ::foo` | `ModuleOrUniformRoot::ModuleAndExternPrelude` | a special case in 2015 edition | /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | - pub imported_module: Cell>>, + pub imported_module: CmCell>>, pub vis: Visibility, /// Span of the visibility. @@ -320,7 +320,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && (vis == import_vis || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx))) { - max_vis.set(Some(vis.expect_local())) + // FIXME(batched): Will be fixed in batched import resolution. + max_vis.set_unchecked(Some(vis.expect_local())) } self.arenas.alloc_name_binding(NameBindingData { @@ -349,7 +350,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. let key = BindingKey::new_disambiguated(ident, ns, || { - module.underscore_disambiguator.update(|d| d + 1); + // FIXME(batched): Will be fixed in batched resolution. + module.underscore_disambiguator.update_unchecked(|d| d + 1); module.underscore_disambiguator.get() }); self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { @@ -482,7 +484,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else { + let Ok(glob_importers) = module.glob_importers.try_borrow_mut_unchecked() else { return t; }; @@ -862,7 +864,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - import.imported_module.set(Some(module)); + // FIXME(batched): Will be fixed in batched import resolution. + import.imported_module.set_unchecked(Some(module)); let (source, target, bindings, type_ns_only) = match import.kind { ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => { (source, target, bindings, type_ns_only) @@ -937,7 +940,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PendingBinding::Pending } }; - bindings[ns].set(binding); + // FIXME(batched): Will be fixed in batched import resolution. + bindings[ns].set_unchecked(binding); } }); @@ -1508,7 +1512,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Add to module's glob_importers - module.glob_importers.borrow_mut().push(import); + module.glob_importers.borrow_mut_unchecked().push(import); // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. @@ -1550,7 +1554,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // reporting conflicts, and reporting unresolved imports. fn finalize_resolutions_in(&mut self, module: Module<'ra>) { // Since import resolution is finished, globs will not define any more names. - *module.globs.borrow_mut() = Vec::new(); + *module.globs.borrow_mut(self) = Vec::new(); let Some(def_id) = module.opt_def_id() else { return }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0dea6ae332735..245bcdac81e86 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -19,6 +19,7 @@ #![feature(default_field_values)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(ptr_as_ref_unchecked)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![recursion_limit = "256"] @@ -26,7 +27,7 @@ use std::cell::{Cell, Ref, RefCell}; use std::collections::BTreeSet; -use std::fmt; +use std::fmt::{self}; use std::sync::Arc; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; @@ -95,6 +96,8 @@ pub mod rustdoc; pub use macros::registered_tools_ast; +use crate::ref_mut::{CmCell, CmRefCell}; + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[derive(Debug)] @@ -592,22 +595,22 @@ struct ModuleData<'ra> { /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'ra>, /// True if this is a module from other crate that needs to be populated on access. - populate_on_access: Cell, + populate_on_access: Cell, // FIXME(parallel): Use an atomic in parallel import resolution /// Used to disambiguate underscore items (`const _: T = ...`) in the module. - underscore_disambiguator: Cell, + underscore_disambiguator: CmCell, /// Macro invocations that can expand into items in this module. - unexpanded_invocations: RefCell>, + unexpanded_invocations: CmRefCell>, /// Whether `#[no_implicit_prelude]` is active. no_implicit_prelude: bool, - glob_importers: RefCell>>, - globs: RefCell>>, + glob_importers: CmRefCell>>, + globs: CmRefCell>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. traits: - RefCell, Option>)]>>>, + CmRefCell, Option>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -656,12 +659,12 @@ impl<'ra> ModuleData<'ra> { kind, lazy_resolutions: Default::default(), populate_on_access: Cell::new(is_foreign), - underscore_disambiguator: Cell::new(0), + underscore_disambiguator: CmCell::new(0), unexpanded_invocations: Default::default(), no_implicit_prelude, - glob_importers: RefCell::new(Vec::new()), - globs: RefCell::new(Vec::new()), - traits: RefCell::new(None), + glob_importers: CmRefCell::new(Vec::new()), + globs: CmRefCell::new(Vec::new()), + traits: CmRefCell::new(None), span, expansion, self_binding, @@ -696,7 +699,7 @@ impl<'ra> Module<'ra> { /// This modifies `self` in place. The traits will be stored in `self.traits`. fn ensure_traits<'tcx>(self, resolver: &impl AsRef>) { - let mut traits = self.traits.borrow_mut(); + let mut traits = self.traits.borrow_mut(resolver.as_ref()); if traits.is_none() { let mut collected_traits = Vec::new(); self.for_each_child(resolver, |r, name, ns, binding| { @@ -1974,6 +1977,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> { if module.populate_on_access.get() { + // FIXME(batched): Will be fixed in batched import resolution. module.populate_on_access.set(false); self.build_reduced_graph_external(module); } @@ -2502,9 +2506,20 @@ pub fn provide(providers: &mut Providers) { providers.registered_tools = macros::registered_tools; } +/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions. +/// +/// `Cm` stands for "conditionally mutable". +/// +/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. +type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; + mod ref_mut { + use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut}; + use std::fmt; use std::ops::Deref; + use crate::Resolver; + /// A wrapper around a mutable reference that conditionally allows mutable access. pub(crate) struct RefOrMut<'a, T> { p: &'a mut T, @@ -2553,11 +2568,86 @@ mod ref_mut { self.p } } -} -/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions. -/// -/// `Cm` stands for "conditionally mutable". -/// -/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. -type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; + /// A wrapper around a [`Cell`] that only allows mutation based on a condition in the resolver. + #[derive(Default)] + pub(crate) struct CmCell(Cell); + + impl fmt::Debug for CmCell { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("CmCell").field(&self.get()).finish() + } + } + + impl Clone for CmCell { + #[inline] + fn clone(&self) -> CmCell { + CmCell::new(self.get()) + } + } + + impl CmCell { + pub(crate) const fn get(&self) -> T { + self.0.get() + } + + pub(crate) fn update_unchecked(&self, f: impl FnOnce(T) -> T) + where + T: Copy, + { + let old = self.get(); + self.set_unchecked(f(old)); + } + } + + impl CmCell { + pub(crate) const fn new(value: T) -> CmCell { + CmCell(Cell::new(value)) + } + + pub(crate) fn set_unchecked(&self, val: T) { + self.0.set(val); + } + + pub(crate) fn into_inner(self) -> T { + self.0.into_inner() + } + } + + /// A wrapper around a [`RefCell`] that only allows mutable borrows based on a condition in the resolver. + #[derive(Default)] + pub(crate) struct CmRefCell(RefCell); + + impl CmRefCell { + pub(crate) const fn new(value: T) -> CmRefCell { + CmRefCell(RefCell::new(value)) + } + + #[inline] + #[track_caller] + pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> { + self.0.borrow_mut() + } + + #[inline] + #[track_caller] + pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> { + if r.assert_speculative { + panic!("Not allowed to mutably borrow a CmRefCell during speculative resolution"); + } + self.borrow_mut_unchecked() + } + + #[inline] + #[track_caller] + pub(crate) fn try_borrow_mut_unchecked(&self) -> Result, BorrowMutError> { + self.0.try_borrow_mut() + } + + #[inline] + #[track_caller] + pub(crate) fn borrow(&self) -> Ref<'_, T> { + self.0.borrow() + } + } +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5fa87b4cd9b68..3b6ef88c5303a 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -189,7 +189,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope); self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope); - parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); + parent_scope.module.unexpanded_invocations.borrow_mut(self).remove(&expansion); if let Some(unexpanded_invocations) = self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion)) { From 8ea9122c9b9465982424f7254a9cd88147e85642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 25 Sep 2025 18:16:56 +0200 Subject: [PATCH 06/11] Rename `verbose` to `do_if_verbose` --- src/bootstrap/src/core/build_steps/compile.rs | 7 ++++--- src/bootstrap/src/core/build_steps/dist.rs | 2 +- src/bootstrap/src/core/build_steps/gcc.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 6 +++--- src/bootstrap/src/core/builder/mod.rs | 4 ++-- src/bootstrap/src/core/config/config.rs | 6 +++--- src/bootstrap/src/core/download.rs | 18 ++++++++++-------- src/bootstrap/src/lib.rs | 10 +++++----- src/bootstrap/src/utils/build_stamp.rs | 2 +- src/bootstrap/src/utils/cc_detect.rs | 10 +++++----- src/bootstrap/src/utils/exec.rs | 6 +++--- src/bootstrap/src/utils/render_tests.rs | 2 +- src/bootstrap/src/utils/tarball.rs | 2 +- 13 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index b47b4f248a9ac..e699922f4dc05 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1832,8 +1832,9 @@ impl Step for Sysroot { let sysroot = sysroot_dir(compiler.stage); trace!(stage = ?compiler.stage, ?sysroot); - builder - .verbose(|| println!("Removing sysroot {} to avoid caching bugs", sysroot.display())); + builder.do_if_verbose(|| { + println!("Removing sysroot {} to avoid caching bugs", sysroot.display()) + }); let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); @@ -2591,7 +2592,7 @@ pub fn stream_cargo( cmd.arg(arg); } - builder.verbose(|| println!("running: {cmd:?}")); + builder.do_if_verbose(|| println!("running: {cmd:?}")); let streaming_command = cmd.stream_capture_stdout(&builder.config.exec_ctx); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 99a1062109adc..b79d2cb413db7 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2304,7 +2304,7 @@ fn maybe_install_llvm( let mut cmd = command(host_llvm_config); cmd.cached(); cmd.arg("--libfiles"); - builder.verbose(|| println!("running {cmd:?}")); + builder.do_if_verbose(|| println!("running {cmd:?}")); let files = cmd.run_capture_stdout(builder).stdout(); let build_llvm_out = &builder.llvm_out(builder.config.host_target); let target_llvm_out = &builder.llvm_out(target); diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 717dea37e9e61..17ab8c4e2f479 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -128,7 +128,7 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option\n". let sysroot = stdout.trim_end(); - builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); + builder.do_if_verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); PathBuf::from(sysroot) } } @@ -2675,7 +2675,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> return true; } - builder.verbose(|| println!("doc tests for: {}", markdown.display())); + builder.do_if_verbose(|| println!("doc tests for: {}", markdown.display())); let mut cmd = builder.rustdoc_cmd(compiler); builder.add_rust_test_threads(&mut cmd); // allow for unstable options such as new editions diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 8226b4325b6b8..049d2647bec49 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -545,7 +545,7 @@ impl StepDescription { if !builder.config.skip.is_empty() && !matches!(builder.config.get_dry_run(), DryRun::SelfCheck) { - builder.verbose(|| { + builder.do_if_verbose(|| { println!( "{:?} not skipped for {:?} -- not in {:?}", pathset, self.name, builder.config.skip @@ -947,7 +947,7 @@ impl Step for Libdir { // Sysroot`). if !builder.download_rustc() { let sysroot_target_libdir = sysroot.join(self.target).join("lib"); - builder.verbose(|| { + builder.do_if_verbose(|| { eprintln!( "Removing sysroot {} to avoid caching bugs", sysroot_target_libdir.display() diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index dd2d5a1fd5332..fb7c334491b34 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1571,8 +1571,8 @@ impl Config { } /// Runs a function if verbosity is greater than 0 - pub fn verbose(&self, f: impl Fn()) { - self.exec_ctx.verbose(f); + pub fn do_if_verbose(&self, f: impl Fn()) { + self.exec_ctx.do_if_verbose(f); } pub fn any_sanitizers_to_build(&self) -> bool { @@ -2061,7 +2061,7 @@ pub fn download_ci_rustc_commit<'a>( // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let freshness = check_path_modifications_(dwn_ctx, RUSTC_IF_UNCHANGED_ALLOWED_PATHS); - dwn_ctx.exec_ctx.verbose(|| { + dwn_ctx.exec_ctx.do_if_verbose(|| { eprintln!("rustc freshness: {freshness:?}"); }); match freshness { diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 2f3c80559c0ef..37871f0fe1e28 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -106,7 +106,7 @@ enum DownloadSource { /// Functions that are only ever called once, but named for clarity and to avoid thousand-line functions. impl Config { pub(crate) fn download_clippy(&self) -> PathBuf { - self.verbose(|| println!("downloading stage0 clippy artifacts")); + self.do_if_verbose(|| println!("downloading stage0 clippy artifacts")); let date = &self.stage0_metadata.compiler.date; let version = &self.stage0_metadata.compiler.version; @@ -151,7 +151,9 @@ impl Config { } pub(crate) fn download_ci_rustc(&self, commit: &str) { - self.verbose(|| println!("using downloaded stage2 artifacts from CI (commit {commit})")); + self.do_if_verbose(|| { + println!("using downloaded stage2 artifacts from CI (commit {commit})") + }); let version = self.artifact_version_part(commit); // download-rustc doesn't need its own cargo, it can just use beta's. But it does need the @@ -258,7 +260,7 @@ impl Config { let llvm_root = self.ci_llvm_root(); let llvm_freshness = detect_llvm_freshness(self, self.rust_info.is_managed_git_subrepository()); - self.verbose(|| { + self.do_if_verbose(|| { eprintln!("LLVM freshness: {llvm_freshness:?}"); }); let llvm_sha = match llvm_freshness { @@ -557,7 +559,7 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef(dwn_ctx: impl AsRef>, out: &Path) { let dwn_ctx = dwn_ctx.as_ref(); - dwn_ctx.exec_ctx.verbose(|| { + dwn_ctx.exec_ctx.do_if_verbose(|| { println!("downloading stage0 beta artifacts"); }); @@ -812,7 +814,7 @@ fn download_component<'a>( unpack(dwn_ctx.exec_ctx, &tarball, &bin_root, prefix); return; } else { - dwn_ctx.exec_ctx.verbose(|| { + dwn_ctx.exec_ctx.do_if_verbose(|| { println!( "ignoring cached file {} due to failed verification", tarball.display() @@ -853,7 +855,7 @@ download-rustc = false pub(crate) fn verify(exec_ctx: &ExecutionContext, path: &Path, expected: &str) -> bool { use sha2::Digest; - exec_ctx.verbose(|| { + exec_ctx.do_if_verbose(|| { println!("verifying {}", path.display()); }); @@ -934,7 +936,7 @@ fn unpack(exec_ctx: &ExecutionContext, tarball: &Path, dst: &Path, pattern: &str short_path = short_path.strip_prefix(pattern).unwrap_or(short_path); let dst_path = dst.join(short_path); - exec_ctx.verbose(|| { + exec_ctx.do_if_verbose(|| { println!("extracting {} to {}", original_path.display(), dst.display()); }); @@ -965,7 +967,7 @@ fn download_file<'a>( ) { let dwn_ctx = dwn_ctx.as_ref(); - dwn_ctx.exec_ctx.verbose(|| { + dwn_ctx.exec_ctx.do_if_verbose(|| { println!("download {url}"); }); // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/. diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 75cc79e6689c8..4f4d35673d5d1 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -415,7 +415,7 @@ macro_rules! forward { } forward! { - verbose(f: impl Fn()), + do_if_verbose(f: impl Fn()), is_verbose() -> bool, create(path: &Path, s: &str), remove(f: &Path), @@ -601,11 +601,11 @@ impl Build { .unwrap() .trim(); if local_release.split('.').take(2).eq(version.split('.').take(2)) { - build.verbose(|| println!("auto-detected local-rebuild {local_release}")); + build.do_if_verbose(|| println!("auto-detected local-rebuild {local_release}")); build.local_rebuild = true; } - build.verbose(|| println!("finding compilers")); + build.do_if_verbose(|| println!("finding compilers")); utils::cc_detect::fill_compilers(&mut build); // When running `setup`, the profile is about to change, so any requirements we have now may // be different on the next invocation. Don't check for them until the next time x.py is @@ -613,7 +613,7 @@ impl Build { // // Similarly, for `setup` we don't actually need submodules or cargo metadata. if !matches!(build.config.cmd, Subcommand::Setup { .. }) { - build.verbose(|| println!("running sanity check")); + build.do_if_verbose(|| println!("running sanity check")); crate::core::sanity::check(&mut build); // Make sure we update these before gathering metadata so we don't get an error about missing @@ -631,7 +631,7 @@ impl Build { // Now, update all existing submodules. build.update_existing_submodules(); - build.verbose(|| println!("learning about cargo")); + build.do_if_verbose(|| println!("learning about cargo")); crate::core::metadata::build(&mut build); } diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs index 4c35388a181aa..5cd68f6d4fe7f 100644 --- a/src/bootstrap/src/utils/build_stamp.rs +++ b/src/bootstrap/src/utils/build_stamp.rs @@ -112,7 +112,7 @@ pub fn clear_if_dirty(builder: &Builder<'_>, dir: &Path, input: &Path) -> bool { let stamp = BuildStamp::new(dir); let mut cleared = false; if mtime(stamp.path()) < mtime(input) { - builder.verbose(|| println!("Dirty - {}", dir.display())); + builder.do_if_verbose(|| println!("Dirty - {}", dir.display())); let _ = fs::remove_dir_all(dir); cleared = true; } else if stamp.path().exists() { diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index d3926df9650ce..0662ae304ac06 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -137,16 +137,16 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { build.cxx.insert(target, compiler); } - build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target))); - build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple)); + build.do_if_verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target))); + build.do_if_verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple)); if let Ok(cxx) = build.cxx(target) { let mut cxxflags = build.cc_handled_clags(target, CLang::Cxx); cxxflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx)); - build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple)); - build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); + build.do_if_verbose(|| println!("CXX_{} = {cxx:?}", target.triple)); + build.do_if_verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); } if let Some(ar) = ar { - build.verbose(|| println!("AR_{} = {ar:?}", target.triple)); + build.do_if_verbose(|| println!("AR_{} = {ar:?}", target.triple)); build.ar.insert(target, ar); } diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index e09f3086b777c..f875e6e1af75c 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -630,7 +630,7 @@ impl ExecutionContext { &self.dry_run } - pub fn verbose(&self, f: impl Fn()) { + pub fn do_if_verbose(&self, f: impl Fn()) { if self.is_verbose() { f() } @@ -686,7 +686,7 @@ impl ExecutionContext { if let Some(cached_output) = self.command_cache.get(&fingerprint) { command.mark_as_executed(); - self.verbose(|| println!("Cache hit: {command:?}")); + self.do_if_verbose(|| println!("Cache hit: {command:?}")); self.profiler.record_cache_hit(fingerprint); return DeferredCommand { state: CommandState::Cached(cached_output) }; } @@ -713,7 +713,7 @@ impl ExecutionContext { }; } - self.verbose(|| { + self.do_if_verbose(|| { println!("running: {command:?} (created at {created_at}, executed at {executed_at})") }); diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 90fd57d976d3f..e90a7ef42324a 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -48,7 +48,7 @@ pub(crate) fn try_run_tests( } fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { - builder.verbose(|| println!("running: {cmd:?}")); + builder.do_if_verbose(|| println!("running: {cmd:?}")); let Some(mut streaming_command) = cmd.stream_capture_stdout(&builder.config.exec_ctx) else { return true; diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 7b77b21293413..079afb7a00548 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -356,7 +356,7 @@ impl<'a> Tarball<'a> { // For `x install` tarball files aren't needed, so we can speed up the process by not producing them. let compression_profile = if self.builder.kind == Kind::Install { - self.builder.verbose(|| { + self.builder.do_if_verbose(|| { println!("Forcing dist.compression-profile = 'no-op' for `x install`.") }); // "no-op" indicates that the rust-installer won't produce compressed tarball sources. From a2d286992409d8077a03e0994a3839abdbfccc90 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 24 Sep 2025 09:56:57 -0700 Subject: [PATCH 07/11] Add `clippy::unconditional_recursion` to `./x clippy ci` The clippy lint catches some things that rustc's equivalent builtin lint does not, for example rust-lang/rust#146940: error: function cannot return without recursing --> library/std/src/path.rs:3428:5 | 3428 | / fn eq(&self, other: &String) -> bool { 3429 | | self == &*other 3430 | | } | |_____^ | note: recursive call site --> library/std/src/path.rs:3429:9 | 3429 | self == &*other | ^^^^^^^^^^^^^^^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unconditional_recursion = note: requested on the command line with `-D clippy::unconditional-recursion` --- src/bootstrap/src/core/build_steps/clippy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 2083c675e1fdd..d5b15d7908646 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -564,6 +564,7 @@ impl Step for CI { "clippy::same_item_push".into(), "clippy::single_char_add_str".into(), "clippy::to_string_in_format_args".into(), + "clippy::unconditional_recursion".into(), ], forbid: vec![], }; @@ -591,6 +592,7 @@ impl Step for CI { "clippy::same_item_push".into(), "clippy::single_char_add_str".into(), "clippy::to_string_in_format_args".into(), + "clippy::unconditional_recursion".into(), ], forbid: vec![], }; From c98b3b2da46146956b982e4ae1747c3614a461fd Mon Sep 17 00:00:00 2001 From: Akrm Al-Hakimi Date: Thu, 25 Sep 2025 13:57:59 -0400 Subject: [PATCH 08/11] const_caller_location: edit FIXME to explain use of `DUMMY_SP` Co-authored-by: Ralf Jung --- compiler/rustc_const_eval/src/util/caller_location.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 5249b32eca469..4e7c8310007b8 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -61,7 +61,7 @@ pub(crate) fn const_caller_location_provider( trace!("const_caller_location: {}:{}:{}", file, line, col); let mut ecx = mk_eval_cx_to_read_const_val( tcx, - rustc_span::DUMMY_SP, // FIXME: use a proper span here? + rustc_span::DUMMY_SP, // This interpreter cannot fail, so the span is irrelevant. ty::TypingEnv::fully_monomorphized(), CanAccessMutGlobal::No, ); From 8daad494b11ae5d0e5282be485625687bcf27e37 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 25 Sep 2025 14:13:26 -0700 Subject: [PATCH 09/11] rustdoc: put the toolbar on the all item index --- src/librustdoc/html/render/mod.rs | 7 ++++++- src/librustdoc/html/render/write_shared.rs | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 6d684449b6d2e..bb494de19d9bd 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -601,7 +601,12 @@ impl AllTypes { } fmt::from_fn(|f| { - f.write_str("

List of all items

")?; + f.write_str( + "
\ +

List of all items

\ + \ +
", + )?; // Note: print_entries does not escape the title, because we know the current set of titles // doesn't require escaping. print_entries(&self.structs, ItemSection::Structs).fmt(f)?; diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index e37a5246a7684..3a1db805d01cf 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -386,8 +386,13 @@ impl CratesIndexPart { let layout = &cx.shared.layout; let style_files = &cx.shared.style_files; const DELIMITER: &str = "\u{FFFC}"; // users are being naughty if they have this - let content = - format!("

List of all crates

    {DELIMITER}
"); + let content = format!( + "
\ +

List of all crates

\ + \ +
\ +
    {DELIMITER}
" + ); let template = layout::render(layout, &page, "", content, style_files); SortedTemplate::from_template(&template, DELIMITER) .expect("Object Replacement Character (U+FFFC) should not appear in the --index-page") From 0ede3fe48c0d373d3673459218e1b9e7eaa667b8 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Thu, 25 Sep 2025 16:34:20 -0500 Subject: [PATCH 10/11] std: fix warning in VEXos stdio module --- library/std/src/sys/stdio/vexos.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/stdio/vexos.rs b/library/std/src/sys/stdio/vexos.rs index 1f2251c6421d8..9a391feb7a8a1 100644 --- a/library/std/src/sys/stdio/vexos.rs +++ b/library/std/src/sys/stdio/vexos.rs @@ -13,7 +13,7 @@ impl Stdin { } impl io::Read for Stdin { - fn read(&mut self, mut buf: &mut [u8]) -> io::Result { + fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut count = 0; for out_byte in buf.iter_mut() { From 51ae86dec97f4db86f624f609c41f6bf5e620301 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 25 Sep 2025 15:23:49 -0700 Subject: [PATCH 11/11] rustdoc-search: add test case for all/index.html search --- tests/rustdoc-gui/search-title.goml | 12 ++++++++++++ tests/rustdoc-gui/src/test_docs/lib.rs | 1 + 2 files changed, 13 insertions(+) diff --git a/tests/rustdoc-gui/search-title.goml b/tests/rustdoc-gui/search-title.goml index 83321a05f2bbb..5808ed845a3b1 100644 --- a/tests/rustdoc-gui/search-title.goml +++ b/tests/rustdoc-gui/search-title.goml @@ -20,3 +20,15 @@ assert-document-property: {"title": '"another one" Search - Rust'} press-key: "Escape" assert-document-property: {"title": |title|} + +// check that all.html does it correctly, too. +go-to: "file://" + |DOC_PATH| + "/test_docs/all.html" +assert-document-property: {"title": "List of all items in this crate"} +call-function: ("perform-search", {"query": "verify"}) +assert-document-property: {"title": '"verify" Search - Rust'} + +// check that index.html does it correctly, too. +go-to: "file://" + |DOC_PATH| + "/index.html" +assert-document-property: {"title": "Index of crates"} +call-function: ("perform-search", {"query": "verify"}) +assert-document-property: {"title": '"verify" Search - Rust'} diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 42f2fbd93b1ee..08523d0df2f2e 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -1,3 +1,4 @@ +//@ compile-flags: --enable-index-page -Z unstable-options //! The point of this crate is to be able to have enough different "kinds" of //! documentation generated so we can test each different features. #![doc(html_playground_url="https://play.rust-lang.org/")]