From 6c4c4384e8f66476214d56b82313c39472c8215e Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 19 Dec 2025 11:37:22 +0000 Subject: [PATCH 01/35] destabilise target-spec-json --- compiler/rustc_driver_impl/src/lib.rs | 3 ++- compiler/rustc_interface/src/interface.rs | 1 + compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/config.rs | 3 ++- compiler/rustc_session/src/session.rs | 7 +++++-- compiler/rustc_target/src/spec/mod.rs | 15 ++++++++++++--- tests/run-make/target-specs/rmake.rs | 16 +++++++++++++++- 7 files changed, 38 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 63fc9c96f450d..5a30e7869f86a 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1124,9 +1124,10 @@ fn get_backend_from_raw_matches( let backend_name = debug_flags .iter() .find_map(|x| x.strip_prefix("codegen-backend=").or(x.strip_prefix("codegen_backend="))); + let unstable_options = debug_flags.iter().find(|x| *x == "unstable-options").is_some(); let target = parse_target_triple(early_dcx, matches); let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from)); - let target = config::build_target_config(early_dcx, &target, sysroot.path()); + let target = config::build_target_config(early_dcx, &target, sysroot.path(), unstable_options); get_codegen_backend(early_dcx, &sysroot, backend_name, &target) } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c0f8f33692e8c..863c56f1a54f0 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -427,6 +427,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se &early_dcx, &config.opts.target_triple, config.opts.sysroot.path(), + config.opts.unstable_opts.unstable_options, ); let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); let path_mapping = config.opts.file_path_mapping(); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8dab3a7f37f59..0ea7232cb7a9b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -46,6 +46,7 @@ where &early_dcx, &sessopts.target_triple, sessopts.sysroot.path(), + sessopts.unstable_opts.unstable_options, ); let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target); let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm(); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a3a97dfec61dc..74826d0531016 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1586,8 +1586,9 @@ pub fn build_target_config( early_dcx: &EarlyDiagCtxt, target: &TargetTuple, sysroot: &Path, + unstable_options: bool, ) -> Target { - match Target::search(target, sysroot) { + match Target::search(target, sysroot, unstable_options) { Ok((target, warnings)) => { for warning in warnings.warning_messages() { early_dcx.early_warn(warning) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1a0ec600af47d..1d5b36fc61b8b 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1002,8 +1002,11 @@ pub fn build_session( } let host_triple = TargetTuple::from_tuple(config::host_tuple()); - let (host, target_warnings) = Target::search(&host_triple, sopts.sysroot.path()) - .unwrap_or_else(|e| dcx.handle().fatal(format!("Error loading host specification: {e}"))); + let (host, target_warnings) = + Target::search(&host_triple, sopts.sysroot.path(), sopts.unstable_opts.unstable_options) + .unwrap_or_else(|e| { + dcx.handle().fatal(format!("Error loading host specification: {e}")) + }); for warning in target_warnings.warning_messages() { dcx.handle().warn(warning) } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 3d500694c978b..d6d607fb18d63 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3299,10 +3299,19 @@ impl Target { pub fn search( target_tuple: &TargetTuple, sysroot: &Path, + unstable_options: bool, ) -> Result<(Target, TargetWarnings), String> { use std::{env, fs}; - fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> { + fn load_file( + path: &Path, + unstable_options: bool, + ) -> Result<(Target, TargetWarnings), String> { + if !unstable_options { + return Err( + "custom targets are unstable and require `-Zunstable-options`".to_string() + ); + } let contents = fs::read_to_string(path).map_err(|e| e.to_string())?; Target::from_json(&contents) } @@ -3326,7 +3335,7 @@ impl Target { for dir in env::split_paths(&target_path) { let p = dir.join(&path); if p.is_file() { - return load_file(&p); + return load_file(&p, unstable_options); } } @@ -3339,7 +3348,7 @@ impl Target { Path::new("target.json"), ]); if p.is_file() { - return load_file(&p); + return load_file(&p, unstable_options); } Err(format!("could not find specification for target {target_tuple:?}")) diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index 7c30a5b21b339..69292af5fd69c 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -15,11 +15,20 @@ fn main() { .run_fail() .assert_stderr_contains("error loading target specification"); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("my-incomplete-platform.json") .run_fail() .assert_stderr_contains("missing field `llvm-target`"); + let test_platform = rustc() + .input("foo.rs") + .target("my-x86_64-unknown-linux-gnu-platform") + .crate_type("lib") + .emit("asm") + .run_fail() + .assert_stderr_contains("custom targets are unstable and require `-Zunstable-options`"); rustc() + .arg("-Zunstable-options") .env("RUST_TARGET_PATH", ".") .input("foo.rs") .target("my-awesome-platform") @@ -27,6 +36,7 @@ fn main() { .emit("asm") .run(); rustc() + .arg("-Zunstable-options") .env("RUST_TARGET_PATH", ".") .input("foo.rs") .target("my-x86_64-unknown-linux-gnu-platform") @@ -52,27 +62,31 @@ fn main() { .actual_text("test-platform-2", test_platform_2) .run(); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("endianness-mismatch") .run_fail() .assert_stderr_contains(r#""data-layout" claims architecture is little-endian"#); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("mismatching-data-layout") .crate_type("lib") .run_fail() .assert_stderr_contains("data-layout for target"); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("require-explicit-cpu") .crate_type("lib") .run_fail() .assert_stderr_contains("target requires explicitly specifying a cpu"); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("require-explicit-cpu") .crate_type("lib") .arg("-Ctarget-cpu=generic") .run(); - rustc().target("require-explicit-cpu").arg("--print=target-cpus").run(); + rustc().arg("-Zunstable-options").target("require-explicit-cpu").print("target-cpus").run(); } From ee12ffe79f97db4ac5e4e763dd9bd99e94863230 Mon Sep 17 00:00:00 2001 From: Mattias Petersson Date: Sun, 14 Dec 2025 17:23:23 +0100 Subject: [PATCH 02/35] Add example for profiling diff locally Added an example for profiling an external crate diff locally. The original issue also mentions that the debuginfo-level = 1 should be highlighted, but that has been solved by a different commit and as such was not included here. --- .../src/profiling/with_rustc_perf.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index c47fed24e6e31..19935d3d262fc 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -28,6 +28,24 @@ You can use the following options for the `x perf` command, which mirror the cor - `--profiles`: Select profiles (`Check`, `Debug`, `Opt`, `Doc`) which should be profiled/benchmarked. - `--scenarios`: Select scenarios (`Full`, `IncrFull`, `IncrPatched`, `IncrUnchanged`) which should be profiled/benchmarked. +## Example profiling diff for external crates +It can be of interest to generate a local diff for two commits of the compiler for external crates. +To start, in the `rustc-perf` repo, build the collector, which runs the Rust compiler benchmarks as follows. +``` +cargo build --release -p collector +``` +After this the collector can be located in `.\target\release\collector`, can be run locally with `bench_local` and expects the following arguments: +- ``: Profiler selection for how performance should be measured. For this example we will use Cachegrind. +- ``: The Rust compiler revision to benchmark, specified as a commit SHA from `rust-lang/rust`. +Optional arguments allow running profiles and scenarios as described above. `--include` in `x perf` is instead `--exact-match`. More information regarding the mandatory and +optional arguments can be found in the [rustc-perf-readme-profilers]. + +Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` in the `rust-lang/rust` repository, run the following +``` +./target/release/collector profile_local cachegrind + --rustc2 + --exact-match serde_derive-1.0.136 --profiles Check --scenarios IncrUnchanged +``` + + [samply]: https://github.com/mstange/samply [cachegrind]: https://www.cs.cmu.edu/afs/cs.cmu.edu/project/cmt-40/Nice/RuleRefinement/bin/valgrind-3.2.0/docs/html/cg-manual.html [rustc-perf]: https://github.com/rust-lang/rustc-perf From f4112ee9b655027dc9526c529f074e6f15fe044a Mon Sep 17 00:00:00 2001 From: Mattias Petersson Date: Sun, 28 Dec 2025 16:56:17 +0100 Subject: [PATCH 03/35] Fix commit according to PR review Changed so cargo specifies the binary collector, removing the need to link to its local binary. Clarified that the SHAs should be from the rustc-repo, but the command should be ran in the rustc-perf repo. --- src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index 19935d3d262fc..7c7639a1ac3dc 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -34,15 +34,16 @@ To start, in the `rustc-perf` repo, build the collector, which runs the Rust com ``` cargo build --release -p collector ``` -After this the collector can be located in `.\target\release\collector`, can be run locally with `bench_local` and expects the following arguments: +The collector can then be run using cargo, specifying the collector binary. It expects the following arguments: - ``: Profiler selection for how performance should be measured. For this example we will use Cachegrind. - ``: The Rust compiler revision to benchmark, specified as a commit SHA from `rust-lang/rust`. -Optional arguments allow running profiles and scenarios as described above. `--include` in `x perf` is instead `--exact-match`. More information regarding the mandatory and +Optional arguments allow running profiles and scenarios as described above. More information regarding the mandatory and optional arguments can be found in the [rustc-perf-readme-profilers]. -Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` in the `rust-lang/rust` repository, run the following +Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` from the `rust-lang/rust` repository, +run the following in the `rustc-perf` repo: ``` -./target/release/collector profile_local cachegrind + --rustc2 + --exact-match serde_derive-1.0.136 --profiles Check --scenarios IncrUnchanged +cargo run --release --bin collector profile_local cachegrind + --rustc2 + --exact-match serde_derive-1.0.136 --profiles Check --scenarios IncrUnchanged ``` From 8233943e818eb570ba715ce935ad9764bba5af47 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 6 Jan 2026 14:11:22 +0900 Subject: [PATCH 04/35] Fix indent in rust code --- src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md b/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md index 64a15b7f9aa82..33b685861df37 100644 --- a/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md +++ b/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md @@ -6,7 +6,7 @@ parse. ```rust fn func(arg: T) { - // ^ Unambig type position + // ^ Unambig type position let a: _ = arg; // ^ Unambig type position @@ -108,4 +108,4 @@ This has a number of benefits: [`ast::AnonConst`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/struct.AnonConst.html [`hir::GenericArg::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer [`ast::ExprKind::Underscore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.ExprKind.html#variant.Underscore -[`ast::Ty::Path(N)`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Path \ No newline at end of file +[`ast::Ty::Path(N)`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Path From e2c73b806e629b4fb5a7f082643d602ca541f7b5 Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Thu, 8 Jan 2026 02:32:51 +0000 Subject: [PATCH 05/35] docs:improve const generics --- src/doc/rustc-dev-guide/src/const-generics.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index cb8c7adc07f46..4c2a0ddbabd51 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -111,14 +111,15 @@ The third point is also somewhat subtle, by not inheriting any of the where clau This also makes it much more likely that the compiler will ICE or atleast incidentally emit some kind of error if we *do* accidentally allow generic parameters in an anon const, as the anon const will have none of the necessary information in its environment to properly handle the generic parameters. +#### Array repeat expressions +The one exception to all of the above is repeat counts of array expressions. As a *backwards compatibility hack* we allow the repeat count const argument to use generic parameters. + ```rust fn foo() { - let a = [1_u8; size_of::<*mut T>()]; + let a = [1_u8; size_of::()]; } ``` -The one exception to all of the above is repeat counts of array expressions. As a *backwards compatibility hack* we allow the repeat count const argument to use generic parameters. - However, to avoid most of the problems involved in allowing generic parameters in anon const const arguments we require that the constant be evaluated before monomorphization (e.g. during type checking). In some sense we only allow generic parameters here when they are semantically unused. In the previous example the anon const can be evaluated for any type parameter `T` because raw pointers to sized types always have the same size (e.g. `8` on 64bit platforms). From 48ccb1f187d56a4d8626421575a47898112412b9 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 9 Jan 2026 12:57:39 +0800 Subject: [PATCH 06/35] Retire outdated stage0 std remarks Co-authored-by: Deadbeef --- .../src/building/new-target.md | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/new-target.md b/src/doc/rustc-dev-guide/src/building/new-target.md index 436aec8ee265b..8465a1388870a 100644 --- a/src/doc/rustc-dev-guide/src/building/new-target.md +++ b/src/doc/rustc-dev-guide/src/building/new-target.md @@ -80,32 +80,12 @@ will then add a corresponding file for your new target containing a Look for existing targets to use as examples. -After adding your target to the `rustc_target` crate you may want to add -`core`, `std`, ... with support for your new target. In that case you will -probably need access to some `target_*` cfg. Unfortunately when building with -stage0 (a precompiled compiler), you'll get an error that the target cfg is -unexpected because stage0 doesn't know about the new target specification and -we pass `--check-cfg` in order to tell it to check. - -To fix the errors you will need to manually add the unexpected value to the -different `Cargo.toml` in `library/{std,alloc,core}/Cargo.toml`. Here is an -example for adding `NEW_TARGET_ARCH` as `target_arch`: - -*`library/std/Cargo.toml`*: -```diff - [lints.rust.unexpected_cfgs] - level = "warn" - check-cfg = [ - 'cfg(bootstrap)', -- 'cfg(target_arch, values("xtensa"))', -+ # #[cfg(bootstrap)] NEW_TARGET_ARCH -+ 'cfg(target_arch, values("xtensa", "NEW_TARGET_ARCH"))', -``` - -To use this target in bootstrap, we need to explicitly add the target triple to the `STAGE0_MISSING_TARGETS` -list in `src/bootstrap/src/core/sanity.rs`. This is necessary because the default compiler bootstrap uses does -not recognize the new target we just added. Therefore, it should be added to `STAGE0_MISSING_TARGETS` so that the -bootstrap is aware that this target is not yet supported by the stage0 compiler. +To use this target in bootstrap, we need to explicitly add the target triple to +the `STAGE0_MISSING_TARGETS` list in `src/bootstrap/src/core/sanity.rs`. This +is necessary because the default bootstrap compiler (typically a beta compiler) +does not recognize the new target we just added. Therefore, it should be added to +`STAGE0_MISSING_TARGETS` so that the bootstrap is aware that this target is not +yet supported by the stage0 compiler. ```diff const STAGE0_MISSING_TARGETS: &[&str] = &[ From 6f12b86e9c0703114d3496abf3d7e93f080c6d5e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 8 Jan 2026 19:41:35 +0100 Subject: [PATCH 07/35] s390x: support `f16` and `f16x8` in inline assembly --- compiler/rustc_target/src/asm/s390x.rs | 6 +-- tests/assembly-llvm/asm/s390x-types.rs | 46 ++++++++++++++++++- .../ui/asm/s390x/bad-reg.s390x_vector.stderr | 6 +-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs index 410590b722b14..37176c0d73eaf 100644 --- a/compiler/rustc_target/src/asm/s390x.rs +++ b/compiler/rustc_target/src/asm/s390x.rs @@ -42,13 +42,13 @@ impl S390xInlineAsmRegClass { ) -> &'static [(InlineAsmType, Option)] { match self { Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; }, - Self::freg => types! { _: F32, F64; }, + Self::freg => types! { _: F16, F32, F64; }, Self::vreg => { if allow_experimental_reg { // non-clobber-only vector register support is unstable. types! { - vector: I32, F32, I64, F64, I128, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); + vector: I32, F16, F32, I64, F64, I128, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); } } else { &[] diff --git a/tests/assembly-llvm/asm/s390x-types.rs b/tests/assembly-llvm/asm/s390x-types.rs index 24db91bf77728..10e2966ace0a3 100644 --- a/tests/assembly-llvm/asm/s390x-types.rs +++ b/tests/assembly-llvm/asm/s390x-types.rs @@ -6,8 +6,9 @@ //@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector //@[s390x_vector] needs-llvm-components: systemz //@ compile-flags: -Zmerge-functions=disabled +//@ min-llvm-version: 21 -#![feature(no_core, repr_simd, f128)] +#![feature(no_core, repr_simd, f16, f128)] #![cfg_attr(s390x_vector, feature(asm_experimental_reg))] #![crate_type = "rlib"] #![no_core] @@ -27,6 +28,8 @@ pub struct i32x4([i32; 4]); #[repr(simd)] pub struct i64x2([i64; 2]); #[repr(simd)] +pub struct f16x8([f16; 8]); +#[repr(simd)] pub struct f32x4([f32; 4]); #[repr(simd)] pub struct f64x2([f64; 2]); @@ -35,6 +38,7 @@ impl Copy for i8x16 {} impl Copy for i16x8 {} impl Copy for i32x4 {} impl Copy for i64x2 {} +impl Copy for f16x8 {} impl Copy for f32x4 {} impl Copy for f64x2 {} @@ -127,6 +131,12 @@ check!(reg_i32_addr, i32, reg_addr, "lgr"); // CHECK: #NO_APP check!(reg_i64_addr, i64, reg_addr, "lgr"); +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// CHECK: ler %f{{[0-9]+}}, %f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f16, f16, freg, "ler"); + // CHECK-LABEL: reg_f32: // CHECK: #APP // CHECK: ler %f{{[0-9]+}}, %f{{[0-9]+}} @@ -173,6 +183,13 @@ check!(vreg_i32x4, i32x4, vreg, "vlr"); #[cfg(s390x_vector)] check!(vreg_i64x2, i64x2, vreg, "vlr"); +// s390x_vector-LABEL: vreg_f16x8: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_f16x8, f16x8, vreg, "vlr"); + // s390x_vector-LABEL: vreg_f32x4: // s390x_vector: #APP // s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} @@ -208,6 +225,13 @@ check!(vreg_i64, i64, vreg, "vlr"); #[cfg(s390x_vector)] check!(vreg_i128, i128, vreg, "vlr"); +// s390x_vector-LABEL: vreg_f16: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_f16, f16, vreg, "vlr"); + // s390x_vector-LABEL: vreg_f32: // s390x_vector: #APP // s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} @@ -253,6 +277,12 @@ check_reg!(r0_i32, i32, "r0", "lr"); // CHECK: #NO_APP check_reg!(r0_i64, i64, "r0", "lr"); +// CHECK-LABEL: f0_f16: +// CHECK: #APP +// CHECK: ler %f0, %f0 +// CHECK: #NO_APP +check_reg!(f0_f16, f16, "f0", "ler"); + // CHECK-LABEL: f0_f32: // CHECK: #APP // CHECK: ler %f0, %f0 @@ -293,6 +323,13 @@ check_reg!(v0_i32x4, i32x4, "v0", "vlr"); #[cfg(s390x_vector)] check_reg!(v0_i64x2, i64x2, "v0", "vlr"); +// s390x_vector-LABEL: v0_f16x8: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_f16x8, f16x8, "v0", "vlr"); + // s390x_vector-LABEL: v0_f32x4: // s390x_vector: #APP // s390x_vector: vlr %v0, %v0 @@ -328,6 +365,13 @@ check_reg!(v0_i64, i64, "v0", "vlr"); #[cfg(s390x_vector)] check_reg!(v0_i128, i128, "v0", "vlr"); +// s390x_vector-LABEL: v0_f16: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_f16, f16, "v0", "vlr"); + // s390x_vector-LABEL: v0_f32: // s390x_vector: #APP // s390x_vector: vlr %v0, %v0 diff --git a/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr index 897f872ae72af..8e2da4dcc2a4d 100644 --- a/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr +++ b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr @@ -282,7 +282,7 @@ error: type `u8` cannot be used with this register class LL | asm!("", in("v0") b); | ^ | - = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: type `u8` cannot be used with this register class --> $DIR/bad-reg.rs:95:28 @@ -290,7 +290,7 @@ error: type `u8` cannot be used with this register class LL | asm!("", out("v0") b); | ^ | - = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: type `u8` cannot be used with this register class --> $DIR/bad-reg.rs:108:35 @@ -298,7 +298,7 @@ error: type `u8` cannot be used with this register class LL | asm!("/* {} */", in(vreg) b); | ^ | - = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: type `i32` cannot be used with this register class --> $DIR/bad-reg.rs:120:27 From f9c71df88ab864536d07a3a98341d3200aae7603 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 Jan 2026 17:40:28 +0100 Subject: [PATCH 08/35] Improve span for "unresolved intra doc link" on `deprecated` attribute --- compiler/rustc_ast/src/attr/mod.rs | 8 +++---- .../src/attributes/deprecation.rs | 22 ++++++++++++------- compiler/rustc_attr_parsing/src/parser.rs | 7 ++++++ .../rustc_hir/src/attrs/data_structures.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_middle/src/middle/stability.rs | 4 ++-- src/librustdoc/clean/types.rs | 6 ++--- tests/rustdoc-ui/intra-doc/deprecated.stderr | 12 +++++----- tests/ui/unpretty/deprecated-attr.stdout | 8 +++---- 9 files changed, 42 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 0a2a34d932f61..b9411a3269a57 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -235,14 +235,14 @@ impl AttributeExt for Attribute { } } - fn deprecation_note(&self) -> Option { + fn deprecation_note(&self) -> Option { match &self.kind { AttrKind::Normal(normal) if normal.item.path == sym::deprecated => { let meta = &normal.item; // #[deprecated = "..."] if let Some(s) = meta.value_str() { - return Some(s); + return Some(Ident { name: s, span: meta.span() }); } // #[deprecated(note = "...")] @@ -252,7 +252,7 @@ impl AttributeExt for Attribute { && mi.path == sym::note && let Some(s) = mi.value_str() { - return Some(s); + return Some(Ident { name: s, span: mi.span }); } } } @@ -905,7 +905,7 @@ pub trait AttributeExt: Debug { /// Returns the deprecation note if this is deprecation attribute. /// * `#[deprecated = "note"]` returns `Some("note")`. /// * `#[deprecated(note = "note", ...)]` returns `Some("note")`. - fn deprecation_note(&self) -> Option; + fn deprecation_note(&self) -> Option; fn is_proc_macro_attr(&self) -> bool { [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 2d79e3a103d6e..e01377d247bb6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -13,14 +13,14 @@ fn get( name: Symbol, param_span: Span, arg: &ArgParser, - item: &Option, -) -> Option { + item: Option, +) -> Option { if item.is_some() { cx.duplicate_key(param_span, name); return None; } if let Some(v) = arg.name_value() { - if let Some(value_str) = v.value_as_str() { + if let Some(value_str) = v.value_as_ident() { Some(value_str) } else { cx.expected_string_literal(v.value_span, Some(&v.value_as_lit())); @@ -72,7 +72,7 @@ impl SingleAttributeParser for DeprecationParser { let features = cx.features(); let mut since = None; - let mut note = None; + let mut note: Option = None; let mut suggestion = None; let is_rustc = features.staged_api(); @@ -92,10 +92,16 @@ impl SingleAttributeParser for DeprecationParser { match ident_name { Some(name @ sym::since) => { - since = Some(get(cx, name, param.span(), param.args(), &since)?); + since = Some(get(cx, name, param.span(), param.args(), since)?.name); } Some(name @ sym::note) => { - note = Some(get(cx, name, param.span(), param.args(), ¬e)?); + note = Some(get( + cx, + name, + param.span(), + param.args(), + note.map(|ident| ident.name), + )?); } Some(name @ sym::suggestion) => { if !features.deprecated_suggestion() { @@ -107,7 +113,7 @@ impl SingleAttributeParser for DeprecationParser { } suggestion = - Some(get(cx, name, param.span(), param.args(), &suggestion)?); + Some(get(cx, name, param.span(), param.args(), suggestion)?.name); } _ => { cx.expected_specific_argument( @@ -124,7 +130,7 @@ impl SingleAttributeParser for DeprecationParser { } } ArgParser::NameValue(v) => { - let Some(value) = v.value_as_str() else { + let Some(value) = v.value_as_ident() else { cx.expected_string_literal(v.value_span, Some(v.value_as_lit())); return None; }; diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index d79579fdf0b78..68265649d1823 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -322,6 +322,13 @@ impl NameValueParser { self.value_as_lit().kind.str() } + /// If the value is a string literal, it will return its value associated with its span (an + /// `Ident` in short). + pub fn value_as_ident(&self) -> Option { + let meta_item = self.value_as_lit(); + meta_item.kind.str().map(|name| Ident { name, span: meta_item.span }) + } + pub fn args_span(&self) -> Span { self.eq_span.to(self.value_span) } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index fa8998f0546d1..7c2700cea0581 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -123,7 +123,7 @@ pub enum IntType { pub struct Deprecation { pub since: DeprecatedSince, /// The note to issue a reason. - pub note: Option, + pub note: Option, /// A text snippet used to completely replace any use of the deprecated item in an expression. /// /// This is currently unstable. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2fb6daf6469b7..1b59d76be68c1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1402,7 +1402,7 @@ impl AttributeExt for Attribute { } #[inline] - fn deprecation_note(&self) -> Option { + fn deprecation_note(&self) -> Option { match &self { Attribute::Parsed(AttributeKind::Deprecation { deprecation, .. }) => deprecation.note, _ => None, diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 18520089e3ea3..63bbd1a0b8549 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -185,7 +185,7 @@ pub fn early_report_macro_deprecation( let diag = BuiltinLintDiag::DeprecatedMacro { suggestion: depr.suggestion, suggestion_span: span, - note: depr.note, + note: depr.note.map(|ident| ident.name), path, since_kind: deprecated_since_kind(is_in_effect, depr.since), }; @@ -228,7 +228,7 @@ fn late_report_deprecation( }), kind: def_kind.to_owned(), path: def_path, - note: depr.note, + note: depr.note.map(|ident| ident.name), since_kind: deprecated_since_kind(is_in_effect, depr.since), }; tcx.emit_node_span_lint(lint, hir_id, method_span, diag); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c3bafd3db13ac..c2e63f475bec4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -26,7 +26,7 @@ use rustc_resolve::rustdoc::{ use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, FileName, Loc, RemapPathScopeComponents}; +use rustc_span::{DUMMY_SP, FileName, Ident, Loc, RemapPathScopeComponents}; use tracing::{debug, trace}; use {rustc_ast as ast, rustc_hir as hir}; @@ -418,7 +418,7 @@ impl Item { { Some(Deprecation { since: DeprecatedSince::Unspecified, - note: Some(note), + note: Some(Ident { name: note, span: DUMMY_SP }), suggestion: None, }) } else { @@ -455,7 +455,7 @@ impl Item { .attrs .other_attrs .iter() - .filter_map(|attr| attr.deprecation_note().map(|_| attr.span())); + .filter_map(|attr| attr.deprecation_note().map(|note| note.span)); span_of_fragments(&self.attrs.doc_strings) .into_iter() diff --git a/tests/rustdoc-ui/intra-doc/deprecated.stderr b/tests/rustdoc-ui/intra-doc/deprecated.stderr index 9bd64544eef82..85290c334626d 100644 --- a/tests/rustdoc-ui/intra-doc/deprecated.stderr +++ b/tests/rustdoc-ui/intra-doc/deprecated.stderr @@ -1,8 +1,8 @@ error: unresolved link to `TypeAlias::hoge` - --> $DIR/deprecated.rs:3:1 + --> $DIR/deprecated.rs:3:16 | LL | #[deprecated = "[broken cross-reference](TypeAlias::hoge)"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: @@ -16,10 +16,10 @@ LL | #![deny(rustdoc::broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved link to `TypeAlias::hoge` - --> $DIR/deprecated.rs:6:1 + --> $DIR/deprecated.rs:6:38 | LL | #[deprecated(since = "0.0.0", note = "[broken cross-reference](TypeAlias::hoge)")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: @@ -28,10 +28,10 @@ LL | #[deprecated(since = "0.0.0", note = "[broken cross-reference](TypeAlias::h = note: no item named `TypeAlias` in scope error: unresolved link to `TypeAlias::hoge` - --> $DIR/deprecated.rs:9:1 + --> $DIR/deprecated.rs:9:21 | LL | #[deprecated(note = "[broken cross-reference](TypeAlias::hoge)", since = "0.0.0")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout index 26cc74c11604d..976598b0bfa32 100644 --- a/tests/ui/unpretty/deprecated-attr.stdout +++ b/tests/ui/unpretty/deprecated-attr.stdout @@ -10,19 +10,19 @@ use ::std::prelude::rust_2015::*; struct PlainDeprecated; #[attr = Deprecation {deprecation: Deprecation {since: Unspecified, -note: "here's why this is deprecated"}}] +note: here's why this is deprecated#0}}] struct DirectNote; #[attr = Deprecation {deprecation: Deprecation {since: Unspecified, -note: "here's why this is deprecated"}}] +note: here's why this is deprecated#0}}] struct ExplicitNote; #[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), -note: "here's why this is deprecated"}}] +note: here's why this is deprecated#0}}] struct SinceAndNote; #[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), -note: "here's why this is deprecated"}}] +note: here's why this is deprecated#0}}] struct FlippedOrder; fn f() { From ef1e4e65b7c76bd03fa82bbbc42393712af05f81 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 10 Jan 2026 15:54:09 +0100 Subject: [PATCH 09/35] Move checks from `check_doc_attrs` directly into `rustc_attr_parsing` --- compiler/rustc_attr_parsing/messages.ftl | 3 + .../rustc_attr_parsing/src/attributes/doc.rs | 119 ++++++++++++++---- compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_attr_parsing/src/interface.rs | 3 + .../src/session_diagnostics.rs | 8 ++ compiler/rustc_lint/messages.ftl | 5 + compiler/rustc_lint/src/early/diagnostics.rs | 2 + compiler/rustc_lint/src/lints.rs | 5 + compiler/rustc_lint_defs/src/lib.rs | 1 + compiler/rustc_passes/messages.ftl | 8 -- compiler/rustc_passes/src/check_attr.rs | 87 ++++--------- compiler/rustc_passes/src/errors.rs | 13 -- .../lints/invalid-crate-level-lint.rs | 13 ++ .../lints/invalid-crate-level-lint.stderr | 27 ++++ tests/rustdoc-ui/lints/invalid-doc-attr.rs | 7 -- .../rustdoc-ui/lints/invalid-doc-attr.stderr | 38 ++---- tests/ui/rustdoc/doc-alias-crate-level.stderr | 12 +- tests/ui/rustdoc/doc_keyword.stderr | 12 +- 18 files changed, 204 insertions(+), 160 deletions(-) create mode 100644 tests/rustdoc-ui/lints/invalid-crate-level-lint.rs create mode 100644 tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 36213e68a52be..4b4358ab0a9ca 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -23,6 +23,9 @@ attr_parsing_doc_alias_malformed = attr_parsing_doc_alias_start_end = {$attr_str} cannot start or end with ' ' +attr_parsing_doc_attr_not_crate_level = + `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute + attr_parsing_doc_attribute_not_attribute = nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` .help = only existing builtin attributes are allowed in core/std diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 16dbb04b48ebd..6cc4ac35eadb1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -1,5 +1,6 @@ use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; use rustc_feature::template; +use rustc_hir::Target; use rustc_hir::attrs::{ AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, }; @@ -12,8 +13,8 @@ use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser}; use crate::session_diagnostics::{ - DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, - DocKeywordNotKeyword, + DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttrNotCrateLevel, + DocAttributeNotAttribute, DocKeywordNotKeyword, }; fn check_keyword(cx: &mut AcceptContext<'_, '_, S>, keyword: Symbol, span: Span) -> bool { @@ -43,16 +44,39 @@ fn check_attribute( false } -fn parse_keyword_and_attribute( +/// Checks that an attribute is *not* used at the crate level. Returns `true` if valid. +fn check_attr_not_crate_level( + cx: &mut AcceptContext<'_, '_, S>, + span: Span, + attr_name: Symbol, +) -> bool { + if cx.shared.target.is_some_and(|target| target == Target::Crate) { + cx.emit_err(DocAttrNotCrateLevel { span, attr_name }); + return false; + } + true +} + +/// Checks that an attribute is used at the crate level. Returns `true` if valid. +fn check_attr_crate_level(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool { + if cx.shared.target.is_some_and(|target| target != Target::Crate) { + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::AttrCrateLevelOnly, + span, + ); + return false; + } + true +} + +fn parse_keyword_and_attribute( cx: &mut AcceptContext<'_, '_, S>, path: &OwnedPathParser, args: &ArgParser, attr_value: &mut Option<(Symbol, Span)>, - callback: F, -) where - S: Stage, - F: FnOnce(&mut AcceptContext<'_, '_, S>, Symbol, Span) -> bool, -{ + attr_name: Symbol, +) { let Some(nv) = args.name_value() else { cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); return; @@ -63,16 +87,26 @@ fn parse_keyword_and_attribute( return; }; - if !callback(cx, value, nv.value_span) { + let ret = if attr_name == sym::keyword { + check_keyword(cx, value, nv.value_span) + } else { + check_attribute(cx, value, nv.value_span) + }; + if !ret { return; } + let span = path.span(); if attr_value.is_some() { - cx.duplicate_key(path.span(), path.word_sym().unwrap()); + cx.duplicate_key(span, path.word_sym().unwrap()); return; } - *attr_value = Some((value, path.span())); + if !check_attr_not_crate_level(cx, span, attr_name) { + return; + } + + *attr_value = Some((value, span)); } #[derive(Default, Debug)] @@ -102,6 +136,10 @@ impl DocParser { return; } + if !check_attr_crate_level(cx, path.span()) { + return; + } + self.attribute.no_crate_inject = Some(path.span()) } Some(sym::attr) => { @@ -155,6 +193,9 @@ impl DocParser { cx.emit_err(DocAliasStartEnd { span, attr_str }); return; } + if !check_attr_not_crate_level(cx, span, sym::alias) { + return; + } if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() { cx.emit_lint( @@ -366,7 +407,33 @@ impl DocParser { self.attribute.$ident = Some(path.span()); }}; } - macro_rules! string_arg { + macro_rules! no_args_and_not_crate_level { + ($ident: ident) => {{ + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + return; + } + let span = path.span(); + if !check_attr_not_crate_level(cx, span, sym::$ident) { + return; + } + self.attribute.$ident = Some(span); + }}; + } + macro_rules! no_args_and_crate_level { + ($ident: ident) => {{ + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + return; + } + let span = path.span(); + if !check_attr_crate_level(cx, span) { + return; + } + self.attribute.$ident = Some(span); + }}; + } + macro_rules! string_arg_and_crate_level { ($ident: ident) => {{ let Some(nv) = args.name_value() else { cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); @@ -378,6 +445,10 @@ impl DocParser { return; }; + if !check_attr_crate_level(cx, path.span()) { + return; + } + // FIXME: It's errorring when the attribute is passed multiple times on the command // line. // The right fix for this would be to only check this rule if the attribute is @@ -394,12 +465,14 @@ impl DocParser { match path.word_sym() { Some(sym::alias) => self.parse_alias(cx, path, args), Some(sym::hidden) => no_args!(hidden), - Some(sym::html_favicon_url) => string_arg!(html_favicon_url), - Some(sym::html_logo_url) => string_arg!(html_logo_url), - Some(sym::html_no_source) => no_args!(html_no_source), - Some(sym::html_playground_url) => string_arg!(html_playground_url), - Some(sym::html_root_url) => string_arg!(html_root_url), - Some(sym::issue_tracker_base_url) => string_arg!(issue_tracker_base_url), + Some(sym::html_favicon_url) => string_arg_and_crate_level!(html_favicon_url), + Some(sym::html_logo_url) => string_arg_and_crate_level!(html_logo_url), + Some(sym::html_no_source) => no_args_and_crate_level!(html_no_source), + Some(sym::html_playground_url) => string_arg_and_crate_level!(html_playground_url), + Some(sym::html_root_url) => string_arg_and_crate_level!(html_root_url), + Some(sym::issue_tracker_base_url) => { + string_arg_and_crate_level!(issue_tracker_base_url) + } Some(sym::inline) => self.parse_inline(cx, path, args, DocInline::Inline), Some(sym::no_inline) => self.parse_inline(cx, path, args, DocInline::NoInline), Some(sym::masked) => no_args!(masked), @@ -410,18 +483,18 @@ impl DocParser { path, args, &mut self.attribute.keyword, - check_keyword, + sym::keyword, ), Some(sym::attribute) => parse_keyword_and_attribute( cx, path, args, &mut self.attribute.attribute, - check_attribute, + sym::attribute, ), - Some(sym::fake_variadic) => no_args!(fake_variadic), - Some(sym::search_unbox) => no_args!(search_unbox), - Some(sym::rust_logo) => no_args!(rust_logo), + Some(sym::fake_variadic) => no_args_and_not_crate_level!(fake_variadic), + Some(sym::search_unbox) => no_args_and_not_crate_level!(search_unbox), + Some(sym::rust_logo) => no_args_and_crate_level!(rust_logo), Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args), Some(sym::test) => { let Some(list) = args.list() else { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 732bf111b2568..2e7804e51d816 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -653,6 +653,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> { pub(crate) target_span: Span, /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to pub(crate) target_id: S::Id, + pub(crate) target: Option, pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint), } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index e38fffa6587cf..d87fc3855954b 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -218,6 +218,7 @@ impl<'sess> AttributeParser<'sess, Early> { cx: &mut parser, target_span, target_id: target_node_id, + target: None, emit_lint: &mut emit_lint, }, attr_span, @@ -378,6 +379,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { cx: self, target_span, target_id, + target: Some(target), emit_lint: &mut emit_lint, }, attr_span, @@ -429,6 +431,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { cx: self, target_span, target_id, + target: Some(target), emit_lint: &mut emit_lint, }, all_attrs: &attr_paths, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 20d00a82cadb2..85e7891b1e64b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -47,6 +47,14 @@ pub(crate) struct DocAliasStartEnd<'a> { pub attr_str: &'a str, } +#[derive(Diagnostic)] +#[diag(attr_parsing_doc_attr_not_crate_level)] +pub(crate) struct DocAttrNotCrateLevel { + #[primary_span] + pub span: Span, + pub attr_name: Symbol, +} + #[derive(Diagnostic)] #[diag(attr_parsing_doc_keyword_not_keyword)] #[help] diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index b49b090272d45..9b0b1abc91df6 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -40,6 +40,11 @@ lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` order lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` +lint_attr_crate_level = + this attribute can only be applied at the crate level + .suggestion = to apply to the crate, use an inner attribute + .note = read for more information + lint_bad_attribute_argument = bad attribute argument lint_bad_opt_access = {$msg} diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index f622de7f84d93..5745f0d4eddec 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -417,5 +417,7 @@ pub fn decorate_attribute_lint( } &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.decorate_lint(diag), + + &AttributeLintKind::AttrCrateLevelOnly => lints::AttrCrateLevelOnly.decorate_lint(diag), } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 841b11c996872..33e9375ec71bd 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3312,3 +3312,8 @@ pub(crate) struct DocTestUnknown { #[derive(LintDiagnostic)] #[diag(lint_doc_test_literal)] pub(crate) struct DocTestLiteral; + +#[derive(LintDiagnostic)] +#[diag(lint_attr_crate_level)] +#[note] +pub(crate) struct AttrCrateLevelOnly; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7b41cfbb43ef0..c8713b23633f7 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -820,6 +820,7 @@ pub enum AttributeLintKind { name: Symbol, }, DocTestLiteral, + AttrCrateLevelOnly, } pub type RegisteredTools = FxIndexSet; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index ba44aa3a35ab8..d8e5574efc91b 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -29,11 +29,6 @@ passes_attr_application_struct_union = attribute should be applied to a struct or union .label = not a struct or union -passes_attr_crate_level = - this attribute can only be applied at the crate level - .suggestion = to apply to the crate, use an inner attribute - .note = read for more information - passes_autodiff_attr = `#[autodiff]` should be applied to a function .label = not a function @@ -112,9 +107,6 @@ passes_doc_alias_bad_location = passes_doc_alias_not_an_alias = `#[doc(alias = "{$attr_str}"]` is the same as the item's name -passes_doc_attr_not_crate_level = - `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute - passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 360feacac0e96..512322f9e9335 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1034,29 +1034,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid. - fn check_attr_not_crate_level(&self, span: Span, hir_id: HirId, attr_name: &str) -> bool { - if CRATE_HIR_ID == hir_id { - self.dcx().emit_err(errors::DocAttrNotCrateLevel { span, attr_name }); - return false; - } - true - } - - /// Checks that an attribute is used at the crate level. Returns `true` if valid. - fn check_attr_crate_level(&self, span: Span, hir_id: HirId) -> bool { - if hir_id != CRATE_HIR_ID { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - span, - errors::AttrCrateLevelOnly {}, - ); - return false; - } - true - } - /// Runs various checks on `#[doc]` attributes. /// /// `specified_inline` should be initialized to `None` and kept for the scope @@ -1072,9 +1049,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { inline, // FIXME: currently unchecked cfg: _, - // already check in attr_parsing + // already checked in attr_parsing auto_cfg: _, - // already check in attr_parsing + // already checked in attr_parsing auto_cfg_change: _, fake_variadic, keyword, @@ -1082,70 +1059,48 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // FIXME: currently unchecked notable_trait: _, search_unbox, - html_favicon_url, - html_logo_url, - html_playground_url, - html_root_url, - html_no_source, - issue_tracker_base_url, + // already checked in attr_parsing + html_favicon_url: _, + // already checked in attr_parsing + html_logo_url: _, + // already checked in attr_parsing + html_playground_url: _, + // already checked in attr_parsing + html_root_url: _, + // already checked in attr_parsing + html_no_source: _, + // already checked in attr_parsing + issue_tracker_base_url: _, rust_logo, // allowed anywhere test_attrs: _, - no_crate_inject, + // already checked in attr_parsing + no_crate_inject: _, attribute, } = attr; for (alias, span) in aliases { - if self.check_attr_not_crate_level(*span, hir_id, "alias") { - self.check_doc_alias_value(*span, hir_id, target, *alias); - } + self.check_doc_alias_value(*span, hir_id, target, *alias); } - if let Some((_, span)) = keyword - && self.check_attr_not_crate_level(*span, hir_id, "keyword") - { + if let Some((_, span)) = keyword { self.check_doc_keyword_and_attribute(*span, hir_id, "keyword"); } - if let Some((_, span)) = attribute - && self.check_attr_not_crate_level(*span, hir_id, "attribute") - { + if let Some((_, span)) = attribute { self.check_doc_keyword_and_attribute(*span, hir_id, "attribute"); } - if let Some(span) = fake_variadic - && self.check_attr_not_crate_level(*span, hir_id, "fake_variadic") - { + if let Some(span) = fake_variadic { self.check_doc_fake_variadic(*span, hir_id); } - if let Some(span) = search_unbox - && self.check_attr_not_crate_level(*span, hir_id, "search_unbox") - { + if let Some(span) = search_unbox { self.check_doc_search_unbox(*span, hir_id); } - for i in [ - html_favicon_url, - html_logo_url, - html_playground_url, - issue_tracker_base_url, - html_root_url, - ] { - if let Some((_, span)) = i { - self.check_attr_crate_level(*span, hir_id); - } - } - - for i in [html_no_source, no_crate_inject] { - if let Some(span) = i { - self.check_attr_crate_level(*span, hir_id); - } - } - self.check_doc_inline(hir_id, target, inline); if let Some(span) = rust_logo - && self.check_attr_crate_level(*span, hir_id) && !self.tcx.features().rustdoc_internals() { feature_err( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 14555765e4234..c1b5988cc7f60 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -179,14 +179,6 @@ pub(crate) struct DocMaskedNotExternCrateSelf { pub item_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_doc_attr_not_crate_level)] -pub(crate) struct DocAttrNotCrateLevel<'a> { - #[primary_span] - pub span: Span, - pub attr_name: &'a str, -} - #[derive(Diagnostic)] #[diag(passes_both_ffi_const_and_pure, code = E0757)] pub(crate) struct BothFfiConstAndPure { @@ -1104,11 +1096,6 @@ pub(crate) struct UnnecessaryPartialStableFeature { #[note] pub(crate) struct IneffectiveUnstableImpl; -#[derive(LintDiagnostic)] -#[diag(passes_attr_crate_level)] -#[note] -pub(crate) struct AttrCrateLevelOnly {} - /// "sanitize attribute not allowed here" #[derive(Diagnostic)] #[diag(passes_sanitize_attribute_not_allowed)] diff --git a/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs b/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs new file mode 100644 index 0000000000000..275e20e80a173 --- /dev/null +++ b/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] + +#[doc(test(no_crate_inject))] +//~^ ERROR can only be applied at the crate level + +pub mod bar { + #![doc(test(no_crate_inject))] + //~^ ERROR can only be applied at the crate level + + #[doc(test(no_crate_inject))] + //~^ ERROR can only be applied at the crate level + fn foo() {} +} diff --git a/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr b/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr new file mode 100644 index 0000000000000..fdb95e7de41c6 --- /dev/null +++ b/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr @@ -0,0 +1,27 @@ +error: this attribute can only be applied at the crate level + --> $DIR/invalid-crate-level-lint.rs:3:12 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^ + | + = note: read for more information + = note: `#[deny(invalid_doc_attributes)]` on by default + +error: this attribute can only be applied at the crate level + --> $DIR/invalid-crate-level-lint.rs:7:17 + | +LL | #![doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^ + | + = note: read for more information + +error: this attribute can only be applied at the crate level + --> $DIR/invalid-crate-level-lint.rs:10:16 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^ + | + = note: read for more information + +error: aborting due to 3 previous errors + diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index a8c42b8fd79c0..169d092d7e175 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -4,18 +4,11 @@ #![doc(masked)] //~^ ERROR this attribute can only be applied to an `extern crate` item -#[doc(test(no_crate_inject))] -//~^ ERROR can only be applied at the crate level #[doc(inline)] //~^ ERROR can only be applied to a `use` item pub fn foo() {} pub mod bar { - #![doc(test(no_crate_inject))] - //~^ ERROR can only be applied at the crate level - - #[doc(test(no_crate_inject))] - //~^ ERROR can only be applied at the crate level #[doc(inline)] //~^ ERROR can only be applied to a `use` item pub fn baz() {} diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 82e1b62b57a62..e431b8df22638 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,14 +1,5 @@ -error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:7:12 - | -LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ - | - = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default - error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:9:7 + --> $DIR/invalid-doc-attr.rs:7:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -17,17 +8,10 @@ LL | pub fn foo() {} | ------------ not a `use` item | = note: read for more information - -error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:14:17 - | -LL | #![doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ - | - = note: read for more information + = note: `#[deny(invalid_doc_attributes)]` on by default error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:24:7 + --> $DIR/invalid-doc-attr.rs:17:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -37,7 +21,7 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:30:7 + --> $DIR/invalid-doc-attr.rs:23:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items @@ -48,7 +32,7 @@ LL | pub struct Masked; = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:34:7 + --> $DIR/invalid-doc-attr.rs:27:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items @@ -70,16 +54,8 @@ LL | | pub extern crate self as reexport; | = note: read for more information -error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:17:16 - | -LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ - | - = note: read for more information - error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:19:11 + --> $DIR/invalid-doc-attr.rs:12:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -89,5 +65,5 @@ LL | pub fn baz() {} | = note: read for more information -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/rustdoc/doc-alias-crate-level.stderr b/tests/ui/rustdoc/doc-alias-crate-level.stderr index a40e31714f145..1d10446a4e7c1 100644 --- a/tests/ui/rustdoc/doc-alias-crate-level.stderr +++ b/tests/ui/rustdoc/doc-alias-crate-level.stderr @@ -1,14 +1,14 @@ -error: '\'' character isn't allowed in `#[doc(alias = "...")]` - --> $DIR/doc-alias-crate-level.rs:7:15 - | -LL | #[doc(alias = "shouldn't work!")] - | ^^^^^^^^^^^^^^^^^ - error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute --> $DIR/doc-alias-crate-level.rs:5:16 | LL | #![doc(alias = "not working!")] | ^^^^^^^^^^^^^^ +error: '\'' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/doc-alias-crate-level.rs:7:15 + | +LL | #[doc(alias = "shouldn't work!")] + | ^^^^^^^^^^^^^^^^^ + error: aborting due to 2 previous errors diff --git a/tests/ui/rustdoc/doc_keyword.stderr b/tests/ui/rustdoc/doc_keyword.stderr index 56da4b00724a5..c8038cbf01969 100644 --- a/tests/ui/rustdoc/doc_keyword.stderr +++ b/tests/ui/rustdoc/doc_keyword.stderr @@ -1,3 +1,9 @@ +error: `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute + --> $DIR/doc_keyword.rs:4:8 + | +LL | #![doc(keyword = "match")] + | ^^^^^^^ + error: nonexistent keyword `tadam` used in `#[doc(keyword = "...")]` --> $DIR/doc_keyword.rs:22:17 | @@ -24,11 +30,5 @@ error: `#[doc(keyword = "...")]` should be used on modules LL | #[doc(keyword = "match")] | ^^^^^^^ -error: `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute - --> $DIR/doc_keyword.rs:4:8 - | -LL | #![doc(keyword = "match")] - | ^^^^^^^ - error: aborting due to 5 previous errors From e20d903c1c43a4fb288dc75fc332a6fe39073b9a Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 12 Jan 2026 04:29:24 +0000 Subject: [PATCH 10/35] Prepare for merging from rust-lang/rust This updates the rust-version file to 44a5b55557c26353f388400d7da95527256fe260. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 7b444a9ef5f11..b53a66c667517 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -85c8ff69cb3efd950395cc444a54bbbdad668865 +44a5b55557c26353f388400d7da95527256fe260 From b327e309b9dba5f3fadc3fc9d2b3bc0ca9e1b747 Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Mon, 12 Jan 2026 03:16:27 -0500 Subject: [PATCH 11/35] core: ptr: split_at_mut: fix typo in safety doc Removes the double subject "it" in the safety documentation of `core::ptr::split_at_mut` for raw slice pointers, as it does not refer to anything. Reported-by: Johnathan Van Why --- library/core/src/ptr/mut_ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 8976154c61db9..11e0a83bd7ec0 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1742,7 +1742,7 @@ impl *mut [T] { /// that is at least `mid * size_of::()` bytes long. Not upholding these /// requirements is *[undefined behavior]* even if the resulting pointers are not used. /// - /// Since `len` being in-bounds it is not a safety invariant of `*mut [T]` the + /// Since `len` being in-bounds is not a safety invariant of `*mut [T]` the /// safety requirements of this method are the same as for [`split_at_mut_unchecked`]. /// The explicit bounds check is only as useful as `len` is correct. /// From 6ca950136de7abd91cc1820b5a7f7109fe568016 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Mon, 12 Jan 2026 11:03:04 +0100 Subject: [PATCH 12/35] Relax test expectation for @__llvm_profile_runtime_user After https://github.com/llvm/llvm-project/pull/174174 it has profile info marking it cold. --- tests/codegen-llvm/instrument-coverage/testprog.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codegen-llvm/instrument-coverage/testprog.rs b/tests/codegen-llvm/instrument-coverage/testprog.rs index 9e918499d577f..ef61ede6de8ee 100644 --- a/tests/codegen-llvm/instrument-coverage/testprog.rs +++ b/tests/codegen-llvm/instrument-coverage/testprog.rs @@ -109,7 +109,7 @@ fn main() { // CHECK: declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] -// WIN: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { +// WIN: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {{.*}}{ // WIN-NEXT: %1 = load i32, ptr @__llvm_profile_runtime // WIN-NEXT: ret i32 %1 // WIN-NEXT: } From c451e9bac648c9c6adcdbd9b4aa6067e38b606cb Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 19 Sep 2021 15:18:05 +0200 Subject: [PATCH 13/35] Remove a workaround for a bug I don't think it is necessary anymore. As I understand it from issue 39504 the original problem was that rustbuild changed a hardlink in the cargo build dir to point to copy in the sysroot while cargo may have hardlinked it to the original first. I don't think this happens anymore and as such this workaround is no longer necessary. --- compiler/rustc_metadata/src/locator.rs | 29 -------------------------- 1 file changed, 29 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 6c30ce0ddb3d3..004d73da8cbda 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -242,7 +242,6 @@ use crate::rmeta::{METADATA_HEADER, MetadataBlob, rustc_version}; pub(crate) struct CrateLocator<'a> { // Immutable per-session configuration. only_needs_metadata: bool, - sysroot: &'a Path, metadata_loader: &'a dyn MetadataLoader, cfg_version: &'static str, @@ -318,7 +317,6 @@ impl<'a> CrateLocator<'a> { CrateLocator { only_needs_metadata, - sysroot: sess.opts.sysroot.path(), metadata_loader, cfg_version: sess.cfg_version, crate_name, @@ -670,33 +668,6 @@ impl<'a> CrateLocator<'a> { continue; } - // Ok so at this point we've determined that `(lib, kind)` above is - // a candidate crate to load, and that `slot` is either none (this - // is the first crate of its kind) or if some the previous path has - // the exact same hash (e.g., it's the exact same crate). - // - // In principle these two candidate crates are exactly the same so - // we can choose either of them to link. As a stupidly gross hack, - // however, we favor crate in the sysroot. - // - // You can find more info in rust-lang/rust#39518 and various linked - // issues, but the general gist is that during testing libstd the - // compilers has two candidates to choose from: one in the sysroot - // and one in the deps folder. These two crates are the exact same - // crate but if the compiler chooses the one in the deps folder - // it'll cause spurious errors on Windows. - // - // As a result, we favor the sysroot crate here. Note that the - // candidates are all canonicalized, so we canonicalize the sysroot - // as well. - if let Some(prev) = &ret { - let sysroot = self.sysroot; - let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf()); - if prev.starts_with(&sysroot) { - continue; - } - } - // We error eagerly here. If we're locating a rlib, then in theory the full metadata // could still be in a (later resolved) dylib. In practice, if the rlib and dylib // were produced in a way where one has full metadata and the other hasn't, it would From 90b32e731b7899adf31067716883cbf483b6f72f Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 12 Jan 2026 14:56:04 +0100 Subject: [PATCH 14/35] Fix typo in `MaybeUninit` docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit –- → – (extra ASCII minus after endash) Introduced in https://github.com/rust-lang/rust/pull/140463 (11627f00c0599c5d033b3e38e3196786537c439b). --- library/core/src/mem/maybe_uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index e0001153a6e7f..320eb97f83a43 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -256,7 +256,7 @@ use crate::{fmt, intrinsics, ptr, slice}; /// /// # Validity /// -/// `MaybeUninit` has no validity requirements –- any sequence of [bytes] of +/// `MaybeUninit` has no validity requirements – any sequence of [bytes] of /// the appropriate length, initialized or uninitialized, are a valid /// representation. /// From 50b60aaff331e6d938c18ee6d2f08691b36db9d0 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Mon, 12 Jan 2026 11:31:20 +0530 Subject: [PATCH 15/35] std: sys: net: uefi: Make TcpStream Send - Since UEFI has no threads, this should be safe. - Makes compiling remote-test-server simpler. Signed-off-by: Ayush Singh --- library/std/src/sys/net/connection/uefi/tcp.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 3e79aa0491872..1e58db0d70468 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -9,6 +9,9 @@ pub(crate) enum Tcp { V4(tcp4::Tcp4), } +// SAFETY: UEFI has no threads. +unsafe impl Send for Tcp {} + impl Tcp { pub(crate) fn connect(addr: &SocketAddr, timeout: Option) -> io::Result { match addr { From 439da0745347783ed5516caaccf3b96468ff858f Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 12 Jan 2026 18:01:10 +0100 Subject: [PATCH 16/35] Update books --- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/nomicon b/src/doc/nomicon index 5b3a9d084cbc6..050c002a360fa 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 5b3a9d084cbc64e54da87e3eec7c7faae0e48ba9 +Subproject commit 050c002a360fa45b701ea34feed7a860dc8a41bf diff --git a/src/doc/reference b/src/doc/reference index 6363385ac4ebe..28b5a54419985 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 6363385ac4ebe1763f1e6fb2063c0b1db681a072 +Subproject commit 28b5a54419985f03db5294de5eede71b6665b594 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 2e02f22a10e7e..8de6ff811315a 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 2e02f22a10e7eeb758e6aba484f13d0f1988a3e5 +Subproject commit 8de6ff811315ac3a96ebe01d74057382e42ffdee From 418cff3ec04a836490a71e9853b9fff48847d32e Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 11 Jan 2026 00:23:45 +0100 Subject: [PATCH 17/35] Port `#[must_not_suspend]` to attribute parser --- .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/must_not_suspend.rs | 35 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 3 +- .../rustc_hir/src/attrs/data_structures.rs | 3 ++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_mir_transform/src/coroutine.rs | 15 ++++---- compiler/rustc_mir_transform/src/errors.rs | 2 +- compiler/rustc_passes/messages.ftl | 4 --- compiler/rustc_passes/src/check_attr.rs | 12 +------ compiler/rustc_passes/src/errors.rs | 9 ----- tests/ui/attributes/malformed-attrs.stderr | 31 ++++++++-------- tests/ui/lint/must_not_suspend/other_items.rs | 2 +- .../lint/must_not_suspend/other_items.stderr | 6 ++-- tests/ui/lint/must_not_suspend/return.rs | 2 +- tests/ui/lint/must_not_suspend/return.stderr | 12 +++---- 15 files changed, 77 insertions(+), 61 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index fafac7ea909da..e02d71a261581 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -47,6 +47,7 @@ pub(crate) mod link_attrs; pub(crate) mod lint_helpers; pub(crate) mod loop_match; pub(crate) mod macro_attrs; +pub(crate) mod must_not_suspend; pub(crate) mod must_use; pub(crate) mod no_implicit_prelude; pub(crate) mod no_link; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs new file mode 100644 index 0000000000000..8456ce7977587 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs @@ -0,0 +1,35 @@ +use super::prelude::*; + +pub(crate) struct MustNotSuspendParser; + +impl SingleAttributeParser for MustNotSuspendParser { + const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::Trait), + ]); + const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let reason = match args { + ArgParser::NameValue(reason) => match reason.value_as_str() { + Some(val) => Some(val), + None => { + cx.expected_nv_or_no_args(reason.value_span); + return None; + } + }, + ArgParser::NoArgs => None, + ArgParser::List(list) => { + cx.expected_nv_or_no_args(list.span); + return None; + } + }; + + Some(AttributeKind::MustNotSupend { reason }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 835bf8ae5c9c4..0217b6370408d 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -51,6 +51,7 @@ use crate::attributes::macro_attrs::{ AllowInternalUnsafeParser, CollapseDebugInfoParser, MacroEscapeParser, MacroExportParser, MacroUseParser, }; +use crate::attributes::must_not_suspend::MustNotSuspendParser; use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; use crate::attributes::no_link::NoLinkParser; @@ -89,7 +90,6 @@ use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, ParsedDescription, }; use crate::target_checking::AllowedTargets; - type GroupType = LazyLock>; pub(super) struct GroupTypeInner { @@ -208,6 +208,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index a5ecfa45fb408..b3c1974c00313 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -824,6 +824,9 @@ pub enum AttributeKind { /// Represents `#[move_size_limit]` MoveSizeLimit { attr_span: Span, limit_span: Span, limit: Limit }, + /// Represents `#[must_not_suspend]` + MustNotSupend { reason: Option }, + /// Represents `#[must_use]`. MustUse { span: Span, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index efdb4f2f22b2e..e02e954c94a5f 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -71,6 +71,7 @@ impl AttributeKind { Marker(..) => No, MayDangle(..) => No, MoveSizeLimit { .. } => No, + MustNotSupend { .. } => Yes, MustUse { .. } => Yes, Naked(..) => No, NoCore(..) => No, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 7fad380ba5a19..705551c58f320 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -64,9 +64,9 @@ use itertools::izip; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::pluralize; -use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::lang_items::LangItem; -use rustc_hir::{CoroutineDesugaring, CoroutineKind}; +use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind, find_attr}; use rustc_index::bit_set::{BitMatrix, DenseBitSet, GrowableBitSet}; use rustc_index::{Idx, IndexVec, indexvec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -85,7 +85,6 @@ use rustc_mir_dataflow::{ }; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::source_map::dummy_spanned; -use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt as _; @@ -1989,11 +1988,11 @@ fn check_must_not_suspend_def( hir_id: hir::HirId, data: SuspendCheckData<'_>, ) -> bool { - if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) { - let reason = attr.value_str().map(|s| errors::MustNotSuspendReason { - span: data.source_span, - reason: s.as_str().to_string(), - }); + if let Some(reason_str) = + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::MustNotSupend {reason} => reason) + { + let reason = + reason_str.map(|s| errors::MustNotSuspendReason { span: data.source_span, reason: s }); tcx.emit_node_span_lint( rustc_session::lint::builtin::MUST_NOT_SUSPEND, hir_id, diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 21a6c4d653bc5..d4c58f7fe05d9 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -323,7 +323,7 @@ impl<'a> LintDiagnostic<'a, ()> for MustNotSupend<'_, '_> { pub(crate) struct MustNotSuspendReason { #[primary_span] pub span: Span, - pub reason: String, + pub reason: Symbol, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 39ad541ee85a9..9628e6d4efe93 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -376,10 +376,6 @@ passes_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` a passes_must_implement_not_function_span_note = required by this annotation -passes_must_not_suspend = - `must_not_suspend` attribute should be applied to a struct, enum, union, or trait - .label = is not a struct, enum, union, or trait - passes_no_main_function = `main` function not found in crate `{$crate_name}` .here_is_main = here is a function named `main` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 717a0e54d0c6e..c9357b99cea20 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -308,6 +308,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ThreadLocal | AttributeKind::CfiEncoding { .. } | AttributeKind::RustcHasIncoherentInherentImpls + | AttributeKind::MustNotSupend { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -325,7 +326,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_dirty, ..] | [sym::rustc_if_this_changed, ..] | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), - [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } @@ -1197,16 +1197,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait. - fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) { - match target { - Target::Struct | Target::Enum | Target::Union | Target::Trait => {} - _ => { - self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span(), span }); - } - } - } - /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) { if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index ace738c559a42..49b9618ef2af9 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -194,15 +194,6 @@ pub(crate) struct BothFfiConstAndPure { pub attr_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_must_not_suspend)] -pub(crate) struct MustNotSuspend { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - #[derive(LintDiagnostic)] #[diag(passes_link)] #[warning] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index fd6f34fb45e29..fc644668735ed 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -32,21 +32,6 @@ error: malformed `patchable_function_entry` attribute input LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: malformed `must_not_suspend` attribute input - --> $DIR/malformed-attrs.rs:138:1 - | -LL | #[must_not_suspend()] - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[must_not_suspend()] -LL + #[must_not_suspend = "reason"] - | -LL - #[must_not_suspend()] -LL + #[must_not_suspend] - | - error: malformed `allow` attribute input --> $DIR/malformed-attrs.rs:184:1 | @@ -527,6 +512,22 @@ LL | #[rustc_layout_scalar_valid_range_end] | expected this to be a list | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` +error[E0539]: malformed `must_not_suspend` attribute input + --> $DIR/malformed-attrs.rs:138:1 + | +LL | #[must_not_suspend()] + | ^^^^^^^^^^^^^^^^^^--^ + | | + | didn't expect a list here + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[must_not_suspend(count)] + | +++++ +LL - #[must_not_suspend()] +LL + #[must_not_suspend] + | + error[E0539]: malformed `cfi_encoding` attribute input --> $DIR/malformed-attrs.rs:140:1 | diff --git a/tests/ui/lint/must_not_suspend/other_items.rs b/tests/ui/lint/must_not_suspend/other_items.rs index 7a42a2bba03b0..1c46cce7ed3ab 100644 --- a/tests/ui/lint/must_not_suspend/other_items.rs +++ b/tests/ui/lint/must_not_suspend/other_items.rs @@ -2,7 +2,7 @@ #![feature(must_not_suspend)] #![deny(must_not_suspend)] -#[must_not_suspend] //~ ERROR attribute should be +#[must_not_suspend] //~ ERROR attribute cannot be used on modules mod inner {} fn main() {} diff --git a/tests/ui/lint/must_not_suspend/other_items.stderr b/tests/ui/lint/must_not_suspend/other_items.stderr index dff5210b7e47f..999a9d2fb3dc8 100644 --- a/tests/ui/lint/must_not_suspend/other_items.stderr +++ b/tests/ui/lint/must_not_suspend/other_items.stderr @@ -1,10 +1,10 @@ -error: `must_not_suspend` attribute should be applied to a struct, enum, union, or trait +error: `#[must_not_suspend]` attribute cannot be used on modules --> $DIR/other_items.rs:5:1 | LL | #[must_not_suspend] | ^^^^^^^^^^^^^^^^^^^ -LL | mod inner {} - | ------------ is not a struct, enum, union, or trait + | + = help: `#[must_not_suspend]` can be applied to data types, traits, and unions error: aborting due to 1 previous error diff --git a/tests/ui/lint/must_not_suspend/return.rs b/tests/ui/lint/must_not_suspend/return.rs index a04f6a4cfb430..de78ee0f92998 100644 --- a/tests/ui/lint/must_not_suspend/return.rs +++ b/tests/ui/lint/must_not_suspend/return.rs @@ -2,7 +2,7 @@ #![feature(must_not_suspend)] #![deny(must_not_suspend)] -#[must_not_suspend] //~ ERROR attribute should be +#[must_not_suspend] //~ ERROR attribute cannot be used on functions fn foo() -> i32 { 0 } diff --git a/tests/ui/lint/must_not_suspend/return.stderr b/tests/ui/lint/must_not_suspend/return.stderr index 440f816568622..1a81b1a39f0c8 100644 --- a/tests/ui/lint/must_not_suspend/return.stderr +++ b/tests/ui/lint/must_not_suspend/return.stderr @@ -1,12 +1,10 @@ -error: `must_not_suspend` attribute should be applied to a struct, enum, union, or trait +error: `#[must_not_suspend]` attribute cannot be used on functions --> $DIR/return.rs:5:1 | -LL | #[must_not_suspend] - | ^^^^^^^^^^^^^^^^^^^ -LL | / fn foo() -> i32 { -LL | | 0 -LL | | } - | |_- is not a struct, enum, union, or trait +LL | #[must_not_suspend] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[must_not_suspend]` can be applied to data types, traits, and unions error: aborting due to 1 previous error From ffe359fe2b61a48b7b0e13dfbdbdbbc1abeab654 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:07:26 +0200 Subject: [PATCH 18/35] another corner case --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index d41a57d6f7474..ebcd472d70129 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -80,6 +80,7 @@ fn ignore(line: &str, in_code_block: bool) -> bool { in_code_block || line.to_lowercase().contains("e.g.") || line.to_lowercase().contains("n.b.") + || line.contains(" etc.") || line.contains("i.e.") || line.contains("et. al") || line.contains('|') @@ -189,6 +190,7 @@ must! be. split? ignore | tables ignore e.g. and ignore i.e. and +ignore etc. and ignore E.g. too - list. entry * list. entry @@ -212,6 +214,7 @@ split? ignore | tables ignore e.g. and ignore i.e. and +ignore etc. and ignore E.g. too - list. entry From 52a5023e762475c7384c8711489dba916dd7fd3d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:08:03 +0200 Subject: [PATCH 19/35] sembr src/external-repos.md --- src/doc/rustc-dev-guide/src/external-repos.md | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index c43c1f680acf0..3d5a0075389e4 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -30,8 +30,8 @@ The following external projects are managed using some form of a `subtree`: In contrast to `submodule` dependencies (see below for those), the `subtree` dependencies are just regular files and directories which can be updated in tree. However, if possible, enhancements, bug fixes, etc. specific -to these tools should be filed against the tools directly in their respective -upstream repositories. The exception is that when rustc changes are required to +to these tools should be filed against the tools directly in their respective upstream repositories. +The exception is that when rustc changes are required to implement a new tool feature or test, that should happen in one collective rustc PR. `subtree` dependencies are currently managed by two distinct approaches: @@ -51,7 +51,9 @@ implement a new tool feature or test, that should happen in one collective rustc ### Josh subtrees -The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh. We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree). +The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. +Specific tooling is required to work with josh. +We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree). ### Synchronizing a Josh subtree @@ -69,8 +71,7 @@ changes from the subtree to rust-lang/rust) are performed from the subtree repos switch to its repository checkout directory in your terminal). #### Performing pull -1) Checkout a new branch that will be used to create a PR into the subtree -2) Run the pull command +1) Checkout a new branch that will be used to create a PR into the subtree 2) Run the pull command ``` rustc-josh-sync pull ``` @@ -97,7 +98,8 @@ If you want to migrate a repository dependency from `git subtree` or `git submod Periodically the changes made to subtree based dependencies need to be synchronized between this repository and the upstream tool repositories. -Subtree synchronizations are typically handled by the respective tool maintainers. Other users +Subtree synchronizations are typically handled by the respective tool maintainers. +Other users are welcome to submit synchronization PRs, however, in order to do so you will need to modify your local git installation and follow a very precise set of instructions. These instructions are documented, along with several useful tips and tricks, in the @@ -108,8 +110,8 @@ use the correct corresponding subtree directory and remote repository. The synchronization process goes in two directions: `subtree push` and `subtree pull`. A `subtree push` takes all the changes that happened to the copy in this repo and creates commits -on the remote repo that match the local changes. Every local -commit that touched the subtree causes a commit on the remote repo, but +on the remote repo that match the local changes. +Every local commit that touched the subtree causes a commit on the remote repo, but is modified to move the files from the specified directory to the tool repo root. A `subtree pull` takes all changes since the last `subtree pull` @@ -119,14 +121,17 @@ the tool changes into the specified directory in the Rust repository. It is recommended that you always do a push first and get that merged to the default branch of the tool. Then, when you do a pull, the merge works without conflicts. While it's definitely possible to resolve conflicts during a pull, you may have to redo the conflict -resolution if your PR doesn't get merged fast enough and there are new conflicts. Do not try to +resolution if your PR doesn't get merged fast enough and there are new conflicts. +Do not try to rebase the result of a `git subtree pull`, rebasing merge commits is a bad idea in general. You always need to specify the `-P` prefix to the subtree directory and the corresponding remote -repository. If you specify the wrong directory or repository +repository. +If you specify the wrong directory or repository you'll get very fun merges that try to push the wrong directory to the wrong remote repository. Luckily you can just abort this without any consequences by throwing away either the pulled commits -in rustc or the pushed branch on the remote and try again. It is usually fairly obvious +in rustc or the pushed branch on the remote and try again. +It is usually fairly obvious that this is happening because you suddenly get thousands of commits that want to be synchronized. [clippy-sync-docs]: https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html @@ -140,8 +145,8 @@ repository's root directory!) git subtree add -P src/tools/clippy https://github.com/rust-lang/rust-clippy.git master ``` -This will create a new commit, which you may not rebase under any circumstances! Delete the commit -and redo the operation if you need to rebase. +This will create a new commit, which you may not rebase under any circumstances! +Delete the commit and redo the operation if you need to rebase. Now you're done, the `src/tools/clippy` directory behaves as if Clippy were part of the rustc monorepo, so no one but you (or others that synchronize @@ -149,24 +154,25 @@ subtrees) actually needs to use `git subtree`. ## External Dependencies (submodules) -Building Rust will also use external git repositories tracked using [git -submodules]. The complete list may be found in the [`.gitmodules`] file. Some -of these projects are required (like `stdarch` for the standard library) and +Building Rust will also use external git repositories tracked using [git submodules]. +The complete list may be found in the [`.gitmodules`] file. +Some of these projects are required (like `stdarch` for the standard library) and some of them are optional (like `src/doc/book`). Usage of submodules is discussed more in the [Using Git chapter](git.md#git-submodules). Some of the submodules are allowed to be in a "broken" state where they either don't build or their tests don't pass, e.g. the documentation books -like [The Rust Reference]. Maintainers of these projects will be notified -when the project is in a broken state, and they should fix them as soon -as possible. The current status is tracked on the [toolstate website]. +like [The Rust Reference]. +Maintainers of these projects will be notified +when the project is in a broken state, and they should fix them as soon as possible. +The current status is tracked on the [toolstate website]. More information may be found on the Forge [Toolstate chapter]. In practice, it is very rare for documentation to have broken toolstate. Breakage is not allowed in the beta and stable channels, and must be addressed -before the PR is merged. They are also not allowed to be broken on `main` in -the week leading up to the beta cut. +before the PR is merged. +They are also not allowed to be broken on `main` in the week leading up to the beta cut. [git submodules]: https://git-scm.com/book/en/v2/Git-Tools-Submodules [`.gitmodules`]: https://github.com/rust-lang/rust/blob/HEAD/.gitmodules From 2204cbd9871e6052d4f7ffcddf0de0bbdeb879ad Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:14:36 +0200 Subject: [PATCH 20/35] "in tree" should be "in-tree" --- src/doc/rustc-dev-guide/src/external-repos.md | 2 +- src/doc/rustc-dev-guide/src/tests/directives.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 3d5a0075389e4..c5e5b40e5a258 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -29,7 +29,7 @@ The following external projects are managed using some form of a `subtree`: In contrast to `submodule` dependencies (see below for those), the `subtree` dependencies are just regular files and directories which can -be updated in tree. However, if possible, enhancements, bug fixes, etc. specific +be updated in-tree. However, if possible, enhancements, bug fixes, etc. specific to these tools should be filed against the tools directly in their respective upstream repositories. The exception is that when rustc changes are required to implement a new tool feature or test, that should happen in one collective rustc PR. diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 52e1f09dca0f0..83272a769a543 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -130,7 +130,7 @@ means the test won't be compiled or run. main test files but that `compiletest` should not try to build the file itself. Please backlink to which main test is actually using the auxiliary file. * `ignore-test` always ignores the test. This can be used to temporarily disable - a test if it is currently not working, but you want to keep it in tree to + a test if it is currently not working, but you want to keep it in-tree to re-enable it later. Some examples of `X` in `ignore-X` or `only-X`: @@ -211,7 +211,7 @@ settings: - `needs-target-std` — ignores if target platform does not have std support. - `ignore-backends` — ignores the listed backends, separated by whitespace characters. Please note that this directive can be overriden with the `--bypass-ignore-backends=[BACKEND]` command line - flag. + flag. - `needs-backends` — only runs the test if current codegen backend is listed. - `needs-offload` — ignores if our LLVM backend was not built with offload support. - `needs-enzyme` — ignores if our Enzyme submodule was not built. @@ -290,9 +290,9 @@ You can also force `./x test` to use a specific edition by passing the `-- --edi However, tests with the `//@ edition` directive will clamp the value passed to the argument. For example, if we run `./x test -- --edition=2015`: -- A test with the `//@ edition: 2018` will run with the 2018 edition. -- A test with the `//@ edition: 2015..2021` will be run with the 2015 edition. -- A test with the `//@ edition: 2018..` will run with the 2018 edition. +- A test with the `//@ edition: 2018` will run with the 2018 edition. +- A test with the `//@ edition: 2015..2021` will be run with the 2015 edition. +- A test with the `//@ edition: 2018..` will run with the 2018 edition. ### Rustdoc From c4b05c3883e00eaa7eeec854ded90a9f9576c4fd Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:24:28 +0200 Subject: [PATCH 21/35] fix sembr tool limitation --- src/doc/rustc-dev-guide/src/external-repos.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index c5e5b40e5a258..7c8cc3b5d62ce 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -71,11 +71,12 @@ changes from the subtree to rust-lang/rust) are performed from the subtree repos switch to its repository checkout directory in your terminal). #### Performing pull -1) Checkout a new branch that will be used to create a PR into the subtree 2) Run the pull command +1. Checkout a new branch that will be used to create a PR into the subtree +2. Run the pull command ``` rustc-josh-sync pull ``` -3) Push the branch to your fork and create a PR into the subtree repository +3. Push the branch to your fork and create a PR into the subtree repository - If you have `gh` CLI installed, `rustc-josh-sync` can create the PR for you. #### Performing push @@ -83,11 +84,11 @@ switch to its repository checkout directory in your terminal). > NOTE: > Before you proceed, look at some guidance related to Git [on josh-sync README]. -1) Run the push command to create a branch named `` in a `rustc` fork under the `` account +1. Run the push command to create a branch named `` in a `rustc` fork under the `` account ``` rustc-josh-sync push ``` -2) Create a PR from `` into `rust-lang/rust` +2. Create a PR from `` into `rust-lang/rust` ### Creating a new Josh subtree dependency From 9a81699f061c0ec39efda7cb5c959a309ad7f71f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:24:52 +0200 Subject: [PATCH 22/35] use a stronger pause --- src/doc/rustc-dev-guide/src/external-repos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 7c8cc3b5d62ce..2e32fcfe78c1d 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -124,7 +124,7 @@ Then, when you do a pull, the merge works without conflicts. While it's definitely possible to resolve conflicts during a pull, you may have to redo the conflict resolution if your PR doesn't get merged fast enough and there are new conflicts. Do not try to -rebase the result of a `git subtree pull`, rebasing merge commits is a bad idea in general. +rebase the result of a `git subtree pull`; rebasing merge commits is a bad idea in general. You always need to specify the `-P` prefix to the subtree directory and the corresponding remote repository. From 98e65aa454b6bfc157ca719551e387c20e0367c6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:42:16 +0200 Subject: [PATCH 23/35] handle another numbered list notation --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index ebcd472d70129..6f4ce4415f04a 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -27,7 +27,7 @@ static REGEX_SPLIT: LazyLock = LazyLock::new(|| Regex::new(r"([^\.\d\-\*]\.|[^r]\?|!)\s").unwrap()); // list elements, numbered (1.) or not (- and *) static REGEX_LIST_ENTRY: LazyLock = - LazyLock::new(|| Regex::new(r"^\s*(\d\.|\-|\*)\s+").unwrap()); + LazyLock::new(|| Regex::new(r"^\s*(\d\.|\-|\*|\d\))\s+").unwrap()); fn main() -> Result<()> { let cli = Cli::parse(); @@ -194,6 +194,7 @@ ignore etc. and ignore E.g. too - list. entry * list. entry + 1) list. entry ``` some code. block ``` @@ -220,6 +221,8 @@ ignore E.g. too entry * list. entry + 1) list. + entry ``` some code. block ``` From 419655be815b3e46b38c2b76dc0818a77f9581f6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:52:54 +0200 Subject: [PATCH 24/35] sembr src/tests/directives.md --- .../rustc-dev-guide/src/tests/directives.md | 167 ++++++++---------- 1 file changed, 77 insertions(+), 90 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 83272a769a543..0852f300b9bef 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -7,8 +7,8 @@ FIXME(jieyouxu) completely revise this chapter. Directives are special comments that tell compiletest how to build and interpret a test. They may also appear in `rmake.rs` [run-make tests](compiletest.md#run-make-tests). -They are normally put after the short comment that explains the point of this -test. Compiletest test suites use `//@` to signal that a comment is a directive. +They are normally put after the short comment that explains the point of this test. +Compiletest test suites use `//@` to signal that a comment is a directive. For example, this test uses the `//@ compile-flags` command to specify a custom flag to give to rustc when the test is compiled: @@ -27,15 +27,16 @@ Directives can be standalone (like `//@ run-pass`) or take a value (like `//@ compile-flags: -C overflow-checks=off`). Directives are written one directive per line: you cannot write multiple -directives on the same line. For example, if you write `//@ only-x86 -only-windows` then `only-windows` is interpreted as a comment, not a separate -directive. +directives on the same line. +For example, if you write `//@ only-x86 +only-windows` then `only-windows` is interpreted as a comment, not a separate directive. ## Listing of compiletest directives -The following is a list of compiletest directives. Directives are linked to -sections that describe the command in more detail if available. This list may -not be exhaustive. Directives can generally be found by browsing the +The following is a list of compiletest directives. +Directives are linked to sections that describe the command in more detail if available. +This list may not be exhaustive. +Directives can generally be found by browsing the `TestProps` structure found in [`directives.rs`] from the compiletest source. [`directives.rs`]: https://github.com/rust-lang/rust/tree/HEAD/src/tools/compiletest/src/directives.rs @@ -65,8 +66,7 @@ See [Building auxiliary crates](compiletest.html#building-auxiliary-crates) ### Controlling outcome expectations -See [Controlling pass/fail -expectations](ui.md#controlling-passfail-expectations). +See [Controlling pass/fail expectations](ui.md#controlling-passfail-expectations). | Directive | Explanation | Supported test suites | Possible values | |-----------------------------|---------------------------------------------|-------------------------------------------|-----------------| @@ -87,8 +87,7 @@ expectations](ui.md#controlling-passfail-expectations). ### Controlling output snapshots and normalizations See [Normalization](ui.md#normalization), [Output -comparison](ui.md#output-comparison) and [Rustfix tests](ui.md#rustfix-tests) -for more details. +comparison](ui.md#output-comparison) and [Rustfix tests](ui.md#rustfix-tests) for more details. | Directive | Explanation | Supported test suites | Possible values | |-----------------------------------|--------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|-----------------------------------------------------------------------------------------| @@ -115,8 +114,8 @@ for more details. [^check_stdout]: presently this has a weird quirk where the test binary's stdout and stderr gets concatenated and then - `error-pattern`s are matched on this combined output, which is ??? slightly - questionable to say the least. + `error-pattern`s are matched on this combined output, which is ??? + slightly questionable to say the least. ### Controlling when tests are run @@ -124,14 +123,13 @@ These directives are used to ignore the test in some situations, which means the test won't be compiled or run. * `ignore-X` where `X` is a target detail or other criteria on which to ignore the test (see below) -* `only-X` is like `ignore-X`, but will *only* run the test on that target or - stage +* `only-X` is like `ignore-X`, but will *only* run the test on that target or stage * `ignore-auxiliary` is intended for files that *participate* in one or more other main test files but that `compiletest` should not try to build the file itself. Please backlink to which main test is actually using the auxiliary file. -* `ignore-test` always ignores the test. This can be used to temporarily disable - a test if it is currently not working, but you want to keep it in-tree to - re-enable it later. +* `ignore-test` always ignores the test. + This can be used to temporarily disable + a test if it is currently not working, but you want to keep it in-tree to re-enable it later. Some examples of `X` in `ignore-X` or `only-X`: @@ -158,16 +156,15 @@ Some examples of `X` in `ignore-X` or `only-X`: - This needs to be enabled with `COMPILETEST_ENABLE_DIST_TESTS=1` - The `rustc_abi` of the target: e.g. `rustc_abi-x86_64-sse2` -The following directives will check rustc build settings and target -settings: +The following directives will check rustc build settings and target settings: - `needs-asm-support` — ignores if the **host** architecture doesn't have - stable support for `asm!`. For tests that cross-compile to explicit targets + stable support for `asm!`. + For tests that cross-compile to explicit targets via `--target`, use `needs-llvm-components` instead to ensure the appropriate backend is available. - `needs-profiler-runtime` — ignores the test if the profiler runtime was not - enabled for the target - (`build.profiler = true` in rustc's `bootstrap.toml`) + enabled for the target (`build.profiler = true` in rustc's `bootstrap.toml`) - `needs-sanitizer-support` — ignores if the sanitizer support was not enabled for the target (`sanitizers = true` in rustc's `bootstrap.toml`) - `needs-sanitizer-{address,hwaddress,leak,memory,thread}` — ignores if the @@ -175,41 +172,36 @@ settings: hardware-assisted AddressSanitizer, LeakSanitizer, MemorySanitizer or ThreadSanitizer respectively) - `needs-run-enabled` — ignores if it is a test that gets executed, and running - has been disabled. Running tests can be disabled with the `x test --run=never` - flag, or running on fuchsia. + has been disabled. + Running tests can be disabled with the `x test --run=never` flag, or running on fuchsia. - `needs-unwind` — ignores if the target does not support unwinding - `needs-rust-lld` — ignores if the rust lld support is not enabled (`rust.lld = true` in `bootstrap.toml`) - `needs-threads` — ignores if the target does not have threading support - `needs-subprocess` — ignores if the target does not have subprocess support -- `needs-symlink` — ignores if the target does not support symlinks. This can be - the case on Windows if the developer did not enable privileged symlink +- `needs-symlink` — ignores if the target does not support symlinks. + This can be the case on Windows if the developer did not enable privileged symlink permissions. -- `ignore-std-debug-assertions` — ignores if std was built with debug - assertions. -- `needs-std-debug-assertions` — ignores if std was not built with debug - assertions. -- `ignore-std-remap-debuginfo` — ignores if std was built with remapping of - it's sources. -- `needs-std-remap-debugino` — ignores if std was not built with remapping of - it's sources. -- `ignore-rustc-debug-assertions` — ignores if rustc was built with debug - assertions. -- `needs-rustc-debug-assertions` — ignores if rustc was not built with debug - assertions. +- `ignore-std-debug-assertions` — ignores if std was built with debug assertions. +- `needs-std-debug-assertions` — ignores if std was not built with debug assertions. +- `ignore-std-remap-debuginfo` — ignores if std was built with remapping of it's sources. +- `needs-std-remap-debugino` — ignores if std was not built with remapping of it's sources. +- `ignore-rustc-debug-assertions` — ignores if rustc was built with debug assertions. +- `needs-rustc-debug-assertions` — ignores if rustc was not built with debug assertions. - `needs-target-has-atomic` — ignores if target does not have support for all specified atomic widths, e.g. the test with `//@ needs-target-has-atomic: 8, - 16, ptr` will only run if it supports the comma-separated list of atomic - widths. + 16, ptr` will only run if it supports the comma-separated list of atomic widths. - `needs-dynamic-linking` — ignores if target does not support dynamic linking (which is orthogonal to it being unable to create `dylib` and `cdylib` crate types) - `needs-crate-type` — ignores if target platform does not support one or more - of the comma-delimited list of specified crate types. For example, + of the comma-delimited list of specified crate types. + For example, `//@ needs-crate-type: cdylib, proc-macro` will cause the test to be ignored on `wasm32-unknown-unknown` target because the target does not support the `proc-macro` crate type. - `needs-target-std` — ignores if target platform does not have std support. -- `ignore-backends` — ignores the listed backends, separated by whitespace characters. Please note +- `ignore-backends` — ignores the listed backends, separated by whitespace characters. + Please note that this directive can be overriden with the `--bypass-ignore-backends=[BACKEND]` command line flag. - `needs-backends` — only runs the test if current codegen backend is listed. @@ -220,29 +212,23 @@ The following directives will check LLVM support: - `exact-llvm-major-version: 19` — ignores if the llvm major version does not match the specified llvm major version. -- `min-llvm-version: 13.0` — ignored if the LLVM version is less than the given - value +- `min-llvm-version: 13.0` — ignored if the LLVM version is less than the given value - `min-system-llvm-version: 12.0` — ignored if using a system LLVM and its version is less than the given value - `max-llvm-major-version: 19` — ignored if the LLVM major version is higher than the given major version - `ignore-llvm-version: 9.0` — ignores a specific LLVM version -- `ignore-llvm-version: 7.0 - 9.9.9` — ignores LLVM versions in a range - (inclusive) -- `needs-llvm-components: powerpc` — ignores if the specific LLVM component was - not built. Note: The test will fail on CI (when - `COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS` is set) if the component does not - exist. +- `ignore-llvm-version: 7.0 - 9.9.9` — ignores LLVM versions in a range (inclusive) +- `needs-llvm-components: powerpc` — ignores if the specific LLVM component was not built. + Note: The test will fail on CI (when + `COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS` is set) if the component does not exist. - `needs-forced-clang-based-tests` — test is ignored unless the environment - variable `RUSTBUILD_FORCE_CLANG_BASED_TESTS` is set, which enables building - clang alongside LLVM + variable `RUSTBUILD_FORCE_CLANG_BASED_TESTS` is set, which enables building clang alongside LLVM - This is only set in two CI jobs ([`x86_64-gnu-debug`] and - [`aarch64-gnu-debug`]), which only runs a - subset of `run-make` tests. Other tests with this directive will not - run at all, which is usually not what you want. + [`aarch64-gnu-debug`]), which only runs a subset of `run-make` tests. + Other tests with this directive will not run at all, which is usually not what you want. -See also [Debuginfo tests](compiletest.md#debuginfo-tests) for directives for -ignoring debuggers. +See also [Debuginfo tests](compiletest.md#debuginfo-tests) for directives for ignoring debuggers. [remote testing]: running.md#running-tests-on-a-remote-machine [compare modes]: ui.md#compare-modes @@ -311,7 +297,8 @@ Asked in The test suites [`rustdoc-html`][rustdoc-html-tests], [`rustdoc-js`/`rustdoc-js-std`][rustdoc-js-tests] and [`rustdoc-json`][rustdoc-json-tests] each feature an additional set of directives whose basic syntax resembles the one of compiletest directives but which are ultimately read and checked by -separate tools. For more information, please read their respective chapters as linked above. +separate tools. +For more information, please read their respective chapters as linked above. [rustdoc-html-tests]: ../rustdoc-internals/rustdoc-html-test-suite.md [rustdoc-js-tests]: ../rustdoc-internals/search.html#testing-the-search-engine @@ -327,8 +314,7 @@ See [Pretty-printer](compiletest.md#pretty-printer-tests). - [`revisions`](compiletest.md#revisions) — compile multiple times -[`forbid-output`](compiletest.md#incremental-tests) — incremental cfail rejects output pattern -- [`should-ice`](compiletest.md#incremental-tests) — incremental cfail should - ICE +- [`should-ice`](compiletest.md#incremental-tests) — incremental cfail should ICE - [`reference`] — an annotation linking to a rule in the reference - `disable-gdb-pretty-printers` — disable gdb pretty printers for debuginfo tests @@ -348,40 +334,37 @@ test suites that use those tools: ### Tidy specific directives -The following directives control how the [tidy script](../conventions.md#formatting) -verifies tests. +The following directives control how the [tidy script](../conventions.md#formatting) verifies tests. - `ignore-tidy-target-specific-tests` disables checking that the appropriate LLVM component is required (via a `needs-llvm-components` directive) when a - test is compiled for a specific target (via the `--target` flag in a - `compile-flag` directive). + test is compiled for a specific target (via the `--target` flag in a `compile-flag` directive). - [`unused-revision-names`](compiletest.md#ignoring-unused-revision-names) - suppress tidy checks for mentioning unknown revision names. ## Substitutions Directive values support substituting a few variables which will be replaced -with their corresponding value. For example, if you need to pass a compiler flag +with their corresponding value. +For example, if you need to pass a compiler flag with a path to a specific file, something like the following could work: ```rust,ignore //@ compile-flags: --remap-path-prefix={{src-base}}=/the/src ``` -Where the sentinel `{{src-base}}` will be replaced with the appropriate path -described below: +Where the sentinel `{{src-base}}` will be replaced with the appropriate path described below: -- `{{cwd}}`: The directory where compiletest is run from. This may not be the - root of the checkout, so you should avoid using it where possible. +- `{{cwd}}`: The directory where compiletest is run from. + This may not be the root of the checkout, so you should avoid using it where possible. - Examples: `/path/to/rust`, `/path/to/build/root` -- `{{src-base}}`: The directory where the test is defined. This is equivalent to - `$DIR` for [output normalization]. +- `{{src-base}}`: The directory where the test is defined. + This is equivalent to `$DIR` for [output normalization]. - Example: `/path/to/rust/tests/ui/error-codes` -- `{{build-base}}`: The base directory where the test's output goes. This is - equivalent to `$TEST_BUILD_DIR` for [output normalization]. +- `{{build-base}}`: The base directory where the test's output goes. + This is equivalent to `$TEST_BUILD_DIR` for [output normalization]. - Example: `/path/to/rust/build/x86_64-unknown-linux-gnu/test/ui` -- `{{rust-src-base}}`: The sysroot directory where libstd/libcore/... are - located +- `{{rust-src-base}}`: The sysroot directory where libstd/libcore/... are located - `{{sysroot-base}}`: Path of the sysroot directory used to build the test. - Mainly intended for `ui-fulldeps` tests that run the compiler via API. - `{{target-linker}}`: Linker that would be passed to `-Clinker` for this test, @@ -400,7 +383,8 @@ for an example of a test that uses this substitution. ## Adding a directive One would add a new directive if there is a need to define some test property or -behavior on an individual, test-by-test basis. A directive property serves as +behavior on an individual, test-by-test basis. +A directive property serves as the directive's backing store (holds the command's current value) at runtime. To add a new directive property: @@ -420,19 +404,21 @@ declaration block is found in [`src/tools/compiletest/src/common.rs`]). `TestProps`'s `load_from()` method will try passing the current line of text to each parser, which, in turn typically checks to see if the line begins with a particular commented (`//@`) directive such as `//@ must-compile-successfully` -or `//@ failure-status`. Whitespace after the comment marker is optional. +or `//@ failure-status`. +Whitespace after the comment marker is optional. Parsers will override a given directive property's default value merely by being specified in the test file as a directive or by having a parameter value specified in the test file, depending on the directive. Parsers defined in `impl Config` are typically named `parse_` -(note kebab-case `` transformed to snake-case -``). `impl Config` also defines several 'low-level' parsers +(note kebab-case `` transformed to snake-case ``). +`impl Config` also defines several 'low-level' parsers which make it simple to parse common patterns like simple presence or not (`parse_name_directive()`), `directive:parameter(s)` (`parse_name_value_directive()`), optional parsing only if a particular `cfg` -attribute is defined (`has_cfg_prefix()`) and many more. The low-level parsers +attribute is defined (`has_cfg_prefix()`) and many more. +The low-level parsers are found near the end of the `impl Config` block; be sure to look through them and their associated parsers immediately above to see how they are used to avoid writing additional parsing code unnecessarily. @@ -483,15 +469,16 @@ As a concrete example, here is the implementation for the ### Implementing the behavior change When a test invokes a particular directive, it is expected that some behavior -will change as a result. What behavior, obviously, will depend on the purpose of -the directive. In the case of `failure-status`, the behavior that changes is +will change as a result. +What behavior, obviously, will depend on the purpose of the directive. +In the case of `failure-status`, the behavior that changes is that `compiletest` expects the failure code defined by the directive invoked in the test, rather than the default value. Although specific to `failure-status` (as every directive will have a different implementation in order to invoke behavior change) perhaps it is helpful to see -the behavior change implementation of one case, simply as an example. To -implement `failure-status`, the `check_correct_failure_status()` function found +the behavior change implementation of one case, simply as an example. +To implement `failure-status`, the `check_correct_failure_status()` function found in the `TestCx` implementation block, located in [`src/tools/compiletest/src/runtest.rs`], was modified as per below: @@ -532,10 +519,10 @@ in the `TestCx` implementation block, located in } ``` -Note the use of `self.props.failure_status` to access the directive property. In -tests which do not specify the failure status directive, -`self.props.failure_status` will evaluate to the default value of 101 at the -time of this writing. But for a test which specifies a directive of, for +Note the use of `self.props.failure_status` to access the directive property. +In tests which do not specify the failure status directive, +`self.props.failure_status` will evaluate to the default value of 101 at the time of this writing. +But for a test which specifies a directive of, for example, `//@ failure-status: 1`, `self.props.failure_status` will evaluate to 1, as `parse_failure_status()` will have overridden the `TestProps` default value, for that test specifically. From e0d9c079ee616f7f6ef6a0b81d9e12962689bfb5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:06:43 +0200 Subject: [PATCH 25/35] add missing pause --- src/doc/rustc-dev-guide/src/tests/directives.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 0852f300b9bef..ae341599f15ad 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -28,8 +28,8 @@ compile-flags: -C overflow-checks=off`). Directives are written one directive per line: you cannot write multiple directives on the same line. -For example, if you write `//@ only-x86 -only-windows` then `only-windows` is interpreted as a comment, not a separate directive. +For example, if you write `//@ only-x86 only-windows`, +then `only-windows` is interpreted as a comment, not a separate directive. ## Listing of compiletest directives From 31c019139531de6cab03cdf3476c71145b635848 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:10:04 +0200 Subject: [PATCH 26/35] sembr src/building/new-target.md --- .../src/building/new-target.md | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/new-target.md b/src/doc/rustc-dev-guide/src/building/new-target.md index 8465a1388870a..d0ed787f520ad 100644 --- a/src/doc/rustc-dev-guide/src/building/new-target.md +++ b/src/doc/rustc-dev-guide/src/building/new-target.md @@ -1,7 +1,7 @@ # Adding a new target -These are a set of steps to add support for a new target. There are -numerous end states and paths to get there, so not all sections may be +These are a set of steps to add support for a new target. +There are numerous end states and paths to get there, so not all sections may be relevant to your desired goal. See also the associated documentation in the [target tier policy]. @@ -11,8 +11,8 @@ See also the associated documentation in the [target tier policy]. ## Specifying a new LLVM For very new targets, you may need to use a different fork of LLVM -than what is currently shipped with Rust. In that case, navigate to -the `src/llvm-project` git submodule (you might need to run `./x +than what is currently shipped with Rust. +In that case, navigate to the `src/llvm-project` git submodule (you might need to run `./x check` at least once so the submodule is updated), check out the appropriate commit for your fork, then commit that new submodule reference in the main Rust repository. @@ -31,11 +31,9 @@ git commit -m 'Use my custom LLVM' ### Using pre-built LLVM If you have a local LLVM checkout that is already built, you may be -able to configure Rust to treat your build as the system LLVM to avoid -redundant builds. +able to configure Rust to treat your build as the system LLVM to avoid redundant builds. -You can tell Rust to use a pre-built version of LLVM using the `target` section -of `bootstrap.toml`: +You can tell Rust to use a pre-built version of LLVM using the `target` section of `bootstrap.toml`: ```toml [target.x86_64-unknown-linux-gnu] @@ -48,8 +46,8 @@ before, though they may be different from your system: - `/usr/bin/llvm-config-8` - `/usr/lib/llvm-8/bin/llvm-config` -Note that you need to have the LLVM `FileCheck` tool installed, which is used -for codegen tests. This tool is normally built with LLVM, but if you use your +Note that you need to have the LLVM `FileCheck` tool installed, which is used for codegen tests. +This tool is normally built with LLVM, but if you use your own preinstalled LLVM, you will need to provide `FileCheck` in some other way. On Debian-based systems, you can install the `llvm-N-tools` package (where `N` is the LLVM version number, e.g. `llvm-8-tools`). Alternately, you can specify @@ -58,8 +56,8 @@ or you can disable codegen test with the `codegen-tests` item in `bootstrap.toml ## Creating a target specification -You should start with a target JSON file. You can see the specification -for an existing target using `--print target-spec-json`: +You should start with a target JSON file. +You can see the specification for an existing target using `--print target-spec-json`: ``` rustc -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json @@ -70,20 +68,20 @@ Save that JSON to a file and modify it as appropriate for your target. ### Adding a target specification Once you have filled out a JSON specification and been able to compile -somewhat successfully, you can copy the specification into the -compiler itself. +somewhat successfully, you can copy the specification into the compiler itself. You will need to add a line to the big table inside of the -`supported_targets` macro in the `rustc_target::spec` module. You -will then add a corresponding file for your new target containing a +`supported_targets` macro in the `rustc_target::spec` module. +You will then add a corresponding file for your new target containing a `target` function. Look for existing targets to use as examples. To use this target in bootstrap, we need to explicitly add the target triple to -the `STAGE0_MISSING_TARGETS` list in `src/bootstrap/src/core/sanity.rs`. This -is necessary because the default bootstrap compiler (typically a beta compiler) -does not recognize the new target we just added. Therefore, it should be added to +the `STAGE0_MISSING_TARGETS` list in `src/bootstrap/src/core/sanity.rs`. +This is necessary because the default bootstrap compiler (typically a beta compiler) +does not recognize the new target we just added. +Therefore, it should be added to `STAGE0_MISSING_TARGETS` so that the bootstrap is aware that this target is not yet supported by the stage0 compiler. @@ -96,9 +94,9 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ ## Patching crates You may need to make changes to crates that the compiler depends on, -such as [`libc`][] or [`cc`][]. If so, you can use Cargo's -[`[patch]`][patch] ability. For example, if you want to use an -unreleased version of `libc`, you can add it to the top-level +such as [`libc`][] or [`cc`][]. +If so, you can use Cargo's [`[patch]`][patch] ability. +For example, if you want to use an unreleased version of `libc`, you can add it to the top-level `Cargo.toml` file: ```diff @@ -118,9 +116,9 @@ index 1e83f05e0ca..4d0172071c1 100644 After this, run `cargo update -p libc` to update the lockfiles. Beware that if you patch to a local `path` dependency, this will enable -warnings for that dependency. Some dependencies are not warning-free, and due -to the `deny-warnings` setting in `bootstrap.toml`, the build may suddenly start -to fail. +warnings for that dependency. +Some dependencies are not warning-free, and due +to the `deny-warnings` setting in `bootstrap.toml`, the build may suddenly start to fail. To work around warnings, you may want to: - Modify the dependency to remove the warnings - Or for local development purposes, suppress the warnings by setting deny-warnings = false in bootstrap.toml. @@ -137,8 +135,7 @@ deny-warnings = false ## Cross-compiling -Once you have a target specification in JSON and in the code, you can -cross-compile `rustc`: +Once you have a target specification in JSON and in the code, you can cross-compile `rustc`: ``` DESTDIR=/path/to/install/in \ From d442a793b23e2d55f6285abaf08ca2f93bd850df Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:13:40 +0200 Subject: [PATCH 27/35] sembr src/rustdoc-internals/rustdoc-html-test-suite.md --- .../rustdoc-internals/rustdoc-html-test-suite.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md index b74405d310eb5..a88e60c183b0d 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md @@ -34,8 +34,8 @@ pub type Alias = Option; Here, we check that documentation generated for crate `file` contains a page for the public type alias `Alias` where the code block that is found at the top contains the -expected rendering of the item. The `//*[@class="rust item-decl"]//code` is an XPath -expression. +expected rendering of the item. +The `//*[@class="rust item-decl"]//code` is an XPath expression. Conventionally, you place these directives directly above the thing they are meant to test. Technically speaking however, they don't need to be as HtmlDocCk only looks for the directives. @@ -120,8 +120,8 @@ pre-recorded subtree or text (the "snapshot") in file `FILE_STEM.NAME.html` wher is the file stem of the test file. Pass the `--bless` option to `compiletest` to accept the current subtree/text as expected. -This will overwrite the aforementioned file (or create it if it doesn't exist). It will -automatically normalize the channel-dependent URL `https://doc.rust-lang.org/CHANNEL` to +This will overwrite the aforementioned file (or create it if it doesn't exist). +It will automatically normalize the channel-dependent URL `https://doc.rust-lang.org/CHANNEL` to the special string `{{channel}}`. ### `has-dir` @@ -152,7 +152,8 @@ It's *strongly recommended* to read that chapter if you don't know anything abou Here are some details that are relevant to this test suite specifically: * While you can use both `//@ compile-flags` and `//@ doc-flags` to pass flags to `rustdoc`, - prefer to user the latter to show intent. The former is meant for `rustc`. + prefer to user the latter to show intent. + The former is meant for `rustc`. * Add `//@ build-aux-docs` to the test file that has auxiliary crates to not only compile the auxiliaries with `rustc` but to also document them with `rustdoc`. @@ -169,7 +170,8 @@ thus continue to test the correct thing or they won't in which case they would f forcing the author of the change to look at them. Compare that to *negative* checks (e.g., `//@ !has PATH XPATH PATTERN`) which won't fail if their -XPath expression "no longer" matches. The author who changed "the shape" thus won't get notified and +XPath expression "no longer" matches. +The author who changed "the shape" thus won't get notified and as a result someone else can unintentionally reintroduce `PATTERN` into the generated docs without the original negative check failing. From 328942672da88fecfdc04b488307d39ac2b5baf4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:15:18 +0200 Subject: [PATCH 28/35] sembr src/profiling/with_rustc_perf.md --- .../src/profiling/with_rustc_perf.md | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index 7c7639a1ac3dc..de4cb9eae9305 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -1,9 +1,11 @@ # Profiling with rustc-perf The [Rust benchmark suite][rustc-perf] provides a comprehensive way of profiling and benchmarking -the Rust compiler. You can find instructions on how to use the suite in its [manual][rustc-perf-readme]. +the Rust compiler. +You can find instructions on how to use the suite in its [manual][rustc-perf-readme]. -However, using the suite manually can be a bit cumbersome. To make this easier for `rustc` contributors, +However, using the suite manually can be a bit cumbersome. +To make this easier for `rustc` contributors, the compiler build system (`bootstrap`) also provides built-in integration with the benchmarking suite, which will download and build the suite for you, build a local compiler toolchain and let you profile it using a simplified command-line interface. @@ -14,8 +16,9 @@ You can use normal bootstrap flags for this command, such as `--stage 1` or `--s `x perf` currently supports the following commands: - `benchmark `: Benchmark the compiler and store the results under the passed `id`. - `compare `: Compare the benchmark results of two compilers with the two passed `id`s. -- `eprintln`: Just run the compiler and capture its `stderr` output. Note that the compiler normally does not print - anything to `stderr`, you might want to add some `eprintln!` calls to get any output. +- `eprintln`: Just run the compiler and capture its `stderr` output. + Note that the compiler normally does not print + anything to `stderr`, you might want to add some `eprintln!` calls to get any output. - `samply`: Profile the compiler using the [samply][samply] sampling profiler. - `cachegrind`: Use [Cachegrind][cachegrind] to generate a detailed simulated trace of the compiler's execution. @@ -29,15 +32,18 @@ You can use the following options for the `x perf` command, which mirror the cor - `--scenarios`: Select scenarios (`Full`, `IncrFull`, `IncrPatched`, `IncrUnchanged`) which should be profiled/benchmarked. ## Example profiling diff for external crates -It can be of interest to generate a local diff for two commits of the compiler for external crates. +It can be of interest to generate a local diff for two commits of the compiler for external crates. To start, in the `rustc-perf` repo, build the collector, which runs the Rust compiler benchmarks as follows. ``` cargo build --release -p collector ``` -The collector can then be run using cargo, specifying the collector binary. It expects the following arguments: -- ``: Profiler selection for how performance should be measured. For this example we will use Cachegrind. +The collector can then be run using cargo, specifying the collector binary. +It expects the following arguments: +- ``: Profiler selection for how performance should be measured. + For this example we will use Cachegrind. - ``: The Rust compiler revision to benchmark, specified as a commit SHA from `rust-lang/rust`. -Optional arguments allow running profiles and scenarios as described above. More information regarding the mandatory and +Optional arguments allow running profiles and scenarios as described above. +More information regarding the mandatory and optional arguments can be found in the [rustc-perf-readme-profilers]. Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` from the `rust-lang/rust` repository, From c451d97ce1401384a7106892e8b4dfdd2768b82a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:18:18 +0200 Subject: [PATCH 29/35] a more natural continuation --- src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index de4cb9eae9305..55fc0556463cb 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -18,7 +18,7 @@ You can use normal bootstrap flags for this command, such as `--stage 1` or `--s - `compare `: Compare the benchmark results of two compilers with the two passed `id`s. - `eprintln`: Just run the compiler and capture its `stderr` output. Note that the compiler normally does not print - anything to `stderr`, you might want to add some `eprintln!` calls to get any output. + anything to `stderr`, so you might want to add some `eprintln!` calls to get any output. - `samply`: Profile the compiler using the [samply][samply] sampling profiler. - `cachegrind`: Use [Cachegrind][cachegrind] to generate a detailed simulated trace of the compiler's execution. From 2d9616a5d78bc26df42f29c74635edef57fdf743 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:18:33 +0200 Subject: [PATCH 30/35] add missing pause --- src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index 55fc0556463cb..2158b655b3e27 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -40,13 +40,13 @@ cargo build --release -p collector The collector can then be run using cargo, specifying the collector binary. It expects the following arguments: - ``: Profiler selection for how performance should be measured. - For this example we will use Cachegrind. + For this example, we will use Cachegrind. - ``: The Rust compiler revision to benchmark, specified as a commit SHA from `rust-lang/rust`. Optional arguments allow running profiles and scenarios as described above. More information regarding the mandatory and optional arguments can be found in the [rustc-perf-readme-profilers]. -Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` from the `rust-lang/rust` repository, +Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` from the `rust-lang/rust` repository, run the following in the `rustc-perf` repo: ``` cargo run --release --bin collector profile_local cachegrind + --rustc2 + --exact-match serde_derive-1.0.136 --profiles Check --scenarios IncrUnchanged From d89da8044855c064be93f66293bbb97392b5ed65 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:19:30 +0200 Subject: [PATCH 31/35] sembr src/tests/best-practices.md --- .../src/tests/best-practices.md | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index ff4ea11bbc7a9..3a029763db8cf 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -7,8 +7,8 @@ a bunch of git archeology. It's good practice to review the test that you authored by pretending that you are a different contributor who is looking at the test that failed several years -later without much context (this also helps yourself even a few days or months -later!). Then ask yourself: how can I make my life and their lives easier? +later without much context (this also helps yourself even a few days or months later!). +Then ask yourself: how can I make my life and their lives easier? To help put this into perspective, let's start with an aside on how to write a test that makes the life of another contributor as hard as possible. @@ -35,15 +35,14 @@ test that makes the life of another contributor as hard as possible. Make it easy for the reader to immediately understand what the test is exercising, instead of having to type in the issue number and dig through github -search for what the test is trying to exercise. This has an additional benefit -of making the test possible to be filtered via `--test-args` as a collection of -related tests. +search for what the test is trying to exercise. +This has an additional benefit +of making the test possible to be filtered via `--test-args` as a collection of related tests. - Name the test after what it's trying to exercise or prevent regressions of. - Keep it concise. - Avoid using issue numbers alone as test names. -- Avoid starting the test name with `issue-xxxxx` prefix as it degrades - auto-completion. +- Avoid starting the test name with `issue-xxxxx` prefix as it degrades auto-completion. > **Avoid using only issue numbers as test names** > @@ -78,21 +77,22 @@ related tests. ## Test organization -- For most test suites, try to find a semantically meaningful subdirectory to - home the test. +- For most test suites, try to find a semantically meaningful subdirectory to home the test. - E.g. for an implementation of RFC 2093 specifically, we can group a - collection of tests under `tests/ui/rfc-2093-infer-outlives/`. For the - directory name, include what the RFC is about. + collection of tests under `tests/ui/rfc-2093-infer-outlives/`. + For the directory name, include what the RFC is about. - For the [`run-make`]/`run-make-support` test suites, each `rmake.rs` must be contained within an immediate subdirectory under `tests/run-make/` or - `tests/run-make-cargo/` respectively. Further nesting is not presently - supported. Avoid using _only_ an issue number for the test name as well. + `tests/run-make-cargo/` respectively. + Further nesting is not presently supported. + Avoid using _only_ an issue number for the test name as well. ## Test descriptions To help other contributors understand what the test is about if their changes lead to the test failing, we should make sure a test has sufficient docs about -its intent/purpose, links to relevant context (incl. issue numbers or other +its intent/purpose, links to relevant context (incl. +issue numbers or other discussions) and possibly relevant resources (e.g. can be helpful to link to Win32 APIs for specific behavior). @@ -136,8 +136,8 @@ fn main() { } ``` -For how much context/explanation is needed, it is up to the author and -reviewer's discretion. A good rule of thumb is non-trivial things exercised in +For how much context/explanation is needed, it is up to the author and reviewer's discretion. +A good rule of thumb is non-trivial things exercised in the test deserves some explanation to help other contributors to understand. This may include remarks on: @@ -159,17 +159,17 @@ This may include remarks on: ## Flaky tests -All tests need to strive to be reproducible and reliable. Flaky tests are the -worst kind of tests, arguably even worse than not having the test in the first +All tests need to strive to be reproducible and reliable. +Flaky tests are the worst kind of tests, arguably even worse than not having the test in the first place. - Flaky tests can fail in completely unrelated PRs which can confuse other - contributors and waste their time trying to figure out if test failure is - related. + contributors and waste their time trying to figure out if test failure is related. - Flaky tests provide no useful information from its test results other than - it's flaky and not reliable: if a test passed but it's flakey, did I just get - lucky? if a test is flakey but it failed, was it just spurious? -- Flaky tests degrade confidence in the whole test suite. If a test suite can + it's flaky and not reliable: if a test passed but it's flakey, did I just get lucky? + if a test is flakey but it failed, was it just spurious? +- Flaky tests degrade confidence in the whole test suite. + If a test suite can randomly spuriously fail due to flaky tests, did the whole test suite pass or did I just get lucky/unlucky? - Flaky tests can randomly fail in full CI, wasting previous full CI resources. @@ -189,8 +189,8 @@ See [compiletest directives] for a listing of directives. See [LLVM FileCheck guide][FileCheck] for details. - Avoid matching on specific register numbers or basic block numbers unless - they're special or critical for the test. Consider using patterns to match - them where suitable. + they're special or critical for the test. + Consider using patterns to match them where suitable. > **TODO** > From 579e2b3009501d33a1636e84f2b8b48c68e9cdd0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:26:30 +0200 Subject: [PATCH 32/35] some improvements to tests/best-practices.md --- src/doc/rustc-dev-guide/src/tests/best-practices.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index 3a029763db8cf..b6daffa6683c0 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -91,9 +91,8 @@ of making the test possible to be filtered via `--test-args` as a collection of To help other contributors understand what the test is about if their changes lead to the test failing, we should make sure a test has sufficient docs about -its intent/purpose, links to relevant context (incl. -issue numbers or other -discussions) and possibly relevant resources (e.g. can be helpful to link to +its intent/purpose, links to relevant context (including issue numbers or other discussions) +and possibly relevant resources (e.g. it can be helpful to link to Win32 APIs for specific behavior). **Synopsis of a test with good comments** @@ -146,7 +145,7 @@ This may include remarks on: separate because...). - Platform-specific behaviors. - Behavior of external dependencies and APIs: syscalls, linkers, tools, - environments and the likes. + environments and the like. ## Test content @@ -167,7 +166,7 @@ place. contributors and waste their time trying to figure out if test failure is related. - Flaky tests provide no useful information from its test results other than it's flaky and not reliable: if a test passed but it's flakey, did I just get lucky? - if a test is flakey but it failed, was it just spurious? + If a test is flakey but it failed, was it just spurious? - Flaky tests degrade confidence in the whole test suite. If a test suite can randomly spuriously fail due to flaky tests, did the whole test suite pass or From da5aa2825a5413d9120cef7b9d359bfa1110e2a0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:26:55 +0200 Subject: [PATCH 33/35] sembr src/tests/perf.md --- src/doc/rustc-dev-guide/src/tests/perf.md | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/perf.md b/src/doc/rustc-dev-guide/src/tests/perf.md index 18762556137e1..a0aa3c0331745 100644 --- a/src/doc/rustc-dev-guide/src/tests/perf.md +++ b/src/doc/rustc-dev-guide/src/tests/perf.md @@ -6,12 +6,13 @@ A lot of work is put into improving the performance of the compiler and preventing performance regressions. The [rustc-perf](https://github.com/rust-lang/rustc-perf) project provides -several services for testing and tracking performance. It provides hosted -infrastructure for running benchmarks as a service. At this time, only -`x86_64-unknown-linux-gnu` builds are tracked. +several services for testing and tracking performance. +It provides hosted infrastructure for running benchmarks as a service. +At this time, only `x86_64-unknown-linux-gnu` builds are tracked. A "perf run" is used to compare the performance of the compiler in different -configurations for a large collection of popular crates. Different +configurations for a large collection of popular crates. +Different configurations include "fresh builds", builds with incremental compilation, etc. The result of a perf run is a comparison between two versions of the compiler @@ -28,8 +29,8 @@ Any changes are noted in a comment on the PR. ### Manual perf runs -Additionally, performance tests can be ran before a PR is merged on an as-needed -basis. You should request a perf run if your PR may affect performance, +Additionally, performance tests can be ran before a PR is merged on an as-needed basis. +You should request a perf run if your PR may affect performance, especially if it can affect performance adversely. To evaluate the performance impact of a PR, write this comment on the PR: @@ -46,10 +47,10 @@ To evaluate the performance impact of a PR, write this comment on the PR: [perf run]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/perf.20run This will first tell bors to do a "try" build which do a full release build for -`x86_64-unknown-linux-gnu`. After the build finishes, it will place it in the -queue to run the performance suite against it. After the performance tests -finish, the bot will post a comment on the PR with a summary and a link to a -full report. +`x86_64-unknown-linux-gnu`. +After the build finishes, it will place it in the queue to run the performance suite against it. +After the performance tests +finish, the bot will post a comment on the PR with a summary and a link to a full report. If you want to do a perf run for an already built artifact (e.g. for a previous try build that wasn't benchmarked yet), you can run this instead: @@ -59,8 +60,7 @@ try build that wasn't benchmarked yet), you can run this instead: You cannot benchmark the same artifact twice though. More information about the available perf bot commands can be found -[here](https://perf.rust-lang.org/help.html). +[here](https://perf.rust-lang.org/help.html). -More details about the benchmarking process itself are available in the [perf -collector +More details about the benchmarking process itself are available in the [perf collector documentation](https://github.com/rust-lang/rustc-perf/blob/master/collector/README.md). From 2d49cfe6aa0f613dbbd35ea3a0542bfe04957a50 Mon Sep 17 00:00:00 2001 From: Jayan Sunil <73993003+JayanAXHF@users.noreply.github.com> Date: Tue, 13 Jan 2026 03:17:32 +0530 Subject: [PATCH 34/35] fix: added missing type in triagebot.toml --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 89118fdb5948f..f00b4b9daffc8 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1006,7 +1006,7 @@ cc = ["@fmease"] [mentions."library/core/src/mem/type_info.rs"] message = """ The reflection data structures are tied exactly to the implementation -in the compiler. Make sure to also adjust `rustc_const_eval/src/const_eval/type_info.rs +in the compiler. Make sure to also adjust `rustc_const_eval/src/const_eval/type_info.rs` """ cc = ["@oli-obk"] From afe76df79cd43d510cc7e746e7402edf8f8eed58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heath=20Dutton=F0=9F=95=B4=EF=B8=8F?= Date: Mon, 12 Jan 2026 18:04:32 -0500 Subject: [PATCH 35/35] Don't suggest replacing closure parameter with type name When a closure has an inferred parameter type like `|ch|` and the expected type differs in borrowing (e.g., `char` vs `&char`), the suggestion code would incorrectly suggest `|char|` instead of the valid `|ch: char|`. This happened because the code couldn't walk explicit `&` references in the HIR when the type is inferred, and fell back to replacing the entire parameter span with the expected type name. Fix by only emitting the suggestion when we can properly identify the `&` syntax to remove. --- .../src/error_reporting/traits/suggestions.rs | 9 +++------ tests/ui/closures/multiple-fn-bounds.stderr | 5 ----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 511e9e85b5f60..81b921b3744f4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5323,12 +5323,9 @@ fn hint_missing_borrow<'tcx>( ty = mut_ty.ty; left -= 1; } - let sugg = if left == 0 { - (span, String::new()) - } else { - (arg.span, expected_arg.to_string()) - }; - remove_borrow.push(sugg); + if left == 0 { + remove_borrow.push((span, String::new())); + } } } } diff --git a/tests/ui/closures/multiple-fn-bounds.stderr b/tests/ui/closures/multiple-fn-bounds.stderr index 9b824fa0eefbd..c99cbac01faf8 100644 --- a/tests/ui/closures/multiple-fn-bounds.stderr +++ b/tests/ui/closures/multiple-fn-bounds.stderr @@ -19,11 +19,6 @@ note: required by a bound in `foo` | LL | fn foo bool + Fn(char) -> bool>(f: F) { | ^^^^^^^^^^^^^^^^ required by this bound in `foo` -help: consider adjusting the signature so it does not borrow its argument - | -LL - foo(move |x| v); -LL + foo(move |char| v); - | error: aborting due to 1 previous error