From 20cb59be6449224b1418200a245a63bd2fd1302c Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 3 Feb 2026 16:30:22 +0100 Subject: [PATCH 01/10] bootstrap: respect modern jobserver When bootstrapping Rust, the `-j N` flag was passed to CMake, which was then forwarded to Ninja. This prevents the jobserver from being used, and as a result leads to oversubscription when Rust is just one of the many packages built as part of a larger software stack. Since Cargo and the Rust compiler have long supported the jobserver, it would be good if also bootstrapping Rust itself would participate in the protocol, leading to composable parallelism. This change allows bootstrapping to respect an existing FIFO based jobserver. Old pipe based jobservers are not supported, because they are brittle: currently the Python scripts in bootstrap do not inherit the file descriptors, but do pass on `MAKEFLAGS`. Because Ninja only supports FIFO based jobservers, it's better to focus on new jobservers only. In summary: * Bootstrap Cargo passes `MAKEFLAGS` verbatim to subprocesses if it advertises a FIFO style jobserver, otherwise it unsets it. * `llvm.rs` does not pass `-j` to `cmake` when a FIFO style jobserver is set in `MAKEFLAGS. * Bootstrap Cargo no longer unsets `MKFLAGS`: from git blame, GNU Make considered it a historical artifact back in 1992, and it is never read by GNU Make, it's only set for backwards compatibility. Signed-off-by: Harmen Stoppels --- src/bootstrap/src/core/build_steps/llvm.rs | 10 +++++++++- src/bootstrap/src/core/builder/cargo.rs | 14 +++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index dbd4f1c814055..ae86874cc99ae 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -773,7 +773,15 @@ fn configure_cmake( .define("CMAKE_CXX_COMPILER", sanitize_cc(&cxx)) .define("CMAKE_ASM_COMPILER", sanitize_cc(&cc)); - cfg.build_arg("-j").build_arg(builder.jobs().to_string()); + // If we are running under a FIFO jobserver, we should not pass -j to CMake; otherwise it + // overrides the jobserver settings and can lead to oversubscription. + let has_modern_jobserver = env::var("MAKEFLAGS") + .map(|flags| flags.contains("--jobserver-auth=fifo:")) + .unwrap_or(false); + + if !has_modern_jobserver { + cfg.build_arg("-j").build_arg(builder.jobs().to_string()); + } let mut cflags = ccflags.cflags.clone(); // FIXME(madsmtm): Allow `cmake-rs` to select flags by itself by passing // our flags via `.cflag`/`.cxxflag` instead. diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 7150b2b0d59f2..f08632d979051 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -547,9 +547,17 @@ impl Builder<'_> { assert_eq!(target, compiler.host); } - // Remove make-related flags to ensure Cargo can correctly set things up - cargo.env_remove("MAKEFLAGS"); - cargo.env_remove("MFLAGS"); + // Bootstrap only supports modern FIFO jobservers. Older pipe-based jobservers can run into + // "invalid file descriptor" errors, as the jobserver file descriptors are not inherited by + // scripts like bootstrap.py, while the environment variable is propagated. So, we pass + // MAKEFLAGS only if we detect a FIFO jobserver, otherwise we clear it. + let has_modern_jobserver = env::var("MAKEFLAGS") + .map(|flags| flags.contains("--jobserver-auth=fifo:")) + .unwrap_or(false); + + if !has_modern_jobserver { + cargo.env_remove("MAKEFLAGS"); + } cargo } From 5c64b89e86bdce77e1936ca4467fe998815f4c1b Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Wed, 18 Feb 2026 19:50:58 +0100 Subject: [PATCH 02/10] DOC: do not link to "nightly" in Iterator::by_ref() docstring --- library/core/src/iter/traits/iterator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d919230d094d8..9e081e65f9ad6 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1908,7 +1908,7 @@ pub const trait Iterator { /// without giving up ownership of the original iterator, /// so you can use the original iterator afterwards. /// - /// Uses [`impl Iterator for &mut I { type Item = I::Item; ...}`](https://doc.rust-lang.org/nightly/std/iter/trait.Iterator.html#impl-Iterator-for-%26mut+I). + /// Uses [`impl Iterator for &mut I { type Item = I::Item; ...}`](Iterator#impl-Iterator-for-%26mut+I). /// /// # Examples /// From a9e6a89b067dc8c7f9eb2a8390343e5584fead62 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 19 Feb 2026 18:13:12 +0800 Subject: [PATCH 03/10] bootstrap: add snapshot tests for {`install`, `install src`} And `install src` with `build.docs = false`. --- src/bootstrap/src/core/builder/tests.rs | 155 +++++++++++++++++++++++- src/bootstrap/src/utils/tests/mod.rs | 5 + 2 files changed, 157 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 002fb32dcf0c6..9c7b66a4d373c 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2854,6 +2854,151 @@ mod snapshot { .render_steps(), @"[clippy] rustc 0 -> bootstrap 1 "); } + #[test] + fn install_plain() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("install") + .args(&[ + // Using backslashes fails with `--set` + "--set", &format!("install.prefix={}", ctx.normalized_dir()), + "--set", &format!("install.bindir={}", ctx.normalized_dir()), + "--set", &format!("install.libdir={}", ctx.normalized_dir()), + "--set", &format!("install.datadir={}", ctx.normalized_dir()), + "--set", &format!("install.mandir={}", ctx.normalized_dir()), + "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), + "--build", "x86_64-unknown-linux-gnu", + "--host", "x86_64-unknown-linux-gnu", + "--target", "x86_64-unknown-linux-gnu", + ]) + .get_steps() + .render_with(RenderConfig { + normalize_host: false + }), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [build] rustc 1 -> std 1 + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [dist] rustc 1 -> std 1 + [build] rustdoc 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + "); + } + + #[test] + fn install_src() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("install") + .path("src") + .args(&[ + // Using backslashes fails with `--set` + "--set", &format!("install.prefix={}", ctx.normalized_dir()), + "--set", &format!("install.bindir={}", ctx.normalized_dir()), + "--set", &format!("install.libdir={}", ctx.normalized_dir()), + "--set", &format!("install.datadir={}", ctx.normalized_dir()), + "--set", &format!("install.mandir={}", ctx.normalized_dir()), + "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), + "--build", "x86_64-unknown-linux-gnu", + "--host", "x86_64-unknown-linux-gnu", + "--target", "x86_64-unknown-linux-gnu", + ]) + .get_steps() + .render_with(RenderConfig { + normalize_host: false + }), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [build] rustc 1 -> std 1 + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [dist] src <> + "); + } + + #[test] + fn install_src_no_docs() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("install") + .path("src") + .args(&[ + // Using backslashes fails with `--set` + "--set", &format!("install.prefix={}", ctx.normalized_dir()), + "--set", &format!("install.bindir={}", ctx.normalized_dir()), + "--set", &format!("install.libdir={}", ctx.normalized_dir()), + "--set", &format!("install.datadir={}", ctx.normalized_dir()), + "--set", &format!("install.mandir={}", ctx.normalized_dir()), + "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), + "--set", "build.docs=false", + "--build", "x86_64-unknown-linux-gnu", + "--host", "x86_64-unknown-linux-gnu", + "--target", "x86_64-unknown-linux-gnu", + ]) + .get_steps() + .render_with(RenderConfig { + normalize_host: false + }), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [dist] src <> + "); + } + #[test] fn install_extended() { let ctx = TestCtx::new(); @@ -2861,12 +3006,16 @@ mod snapshot { ctx.config("install") .args(&[ // Using backslashes fails with `--set` - "--set", &format!("install.prefix={}", ctx.dir().display()).replace("\\", "/"), - "--set", &format!("install.sysconfdir={}", ctx.dir().display()).replace("\\", "/"), + "--set", &format!("install.prefix={}", ctx.normalized_dir()), + "--set", &format!("install.bindir={}", ctx.normalized_dir()), + "--set", &format!("install.libdir={}", ctx.normalized_dir()), + "--set", &format!("install.datadir={}", ctx.normalized_dir()), + "--set", &format!("install.mandir={}", ctx.normalized_dir()), + "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), "--set", "build.extended=true", // For Cranelift to be disted "--build", "x86_64-unknown-linux-gnu", - "--host", "x86_64-unknown-linux-gnu" + "--host", "x86_64-unknown-linux-gnu", ]) .get_steps() .render_with(RenderConfig { diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index 764b89086cf2f..e2a689c0f0ccf 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -35,6 +35,11 @@ impl TestCtx { self.directory.path() } + /// Using backslashes fails with `--set` + pub fn normalized_dir(&self) -> String { + self.dir().to_string_lossy().replace("\\", "/") + } + /// Starts a new invocation of bootstrap that executes `kind` as its top level command /// (i.e. `x `). Returns a builder that configures the created config through CLI flags. pub fn config(&self, kind: &str) -> ConfigBuilder { From f99f24921a8bdaf4e563f0a2b5f3723cf487f2db Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Feb 2026 11:07:04 +0000 Subject: [PATCH 04/10] Remove -Zemit-thin-lto flag As far as I can tell it was introduced to allow fat LTO with -Clinker-plugin-lto. Later a change was made to automatically disable ThinLTO summary generation when -Clinker-plugin-lto -Clto=fat is used, so we can safely remove it. --- compiler/rustc_codegen_llvm/src/back/write.rs | 3 +-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 - compiler/rustc_codegen_ssa/src/back/write.rs | 4 ---- compiler/rustc_interface/src/tests.rs | 1 - .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 17 ++++++++--------- compiler/rustc_session/src/options.rs | 2 -- 6 files changed, 9 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 3e3ccd39e674c..cbf82b05e4d6b 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -786,7 +786,6 @@ pub(crate) unsafe fn llvm_optimize( config.verify_llvm_ir, config.lint_llvm_ir, thin_lto_buffer, - config.emit_thin_lto, config.emit_thin_lto_summary, merge_functions, unroll_loops, @@ -1033,7 +1032,7 @@ pub(crate) fn codegen( "LLVM_module_codegen_make_bitcode", &*module.name, ); - ThinBuffer::new(llmod, config.emit_thin_lto) + ThinBuffer::new(llmod, cgcx.lto != Lto::Fat) }; let data = thin.data(); let _timer = prof diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 4956549f2ed3b..59bf8679d6398 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2376,7 +2376,6 @@ unsafe extern "C" { VerifyIR: bool, LintIR: bool, ThinLTOBuffer: Option<&mut *mut ThinLTOBuffer>, - EmitThinLTO: bool, EmitThinLTOSummary: bool, MergeFunctions: bool, UnrollLoops: bool, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 87a043fbdf245..33595e741cd88 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -101,7 +101,6 @@ pub struct ModuleConfig { pub emit_ir: bool, pub emit_asm: bool, pub emit_obj: EmitObj, - pub emit_thin_lto: bool, pub emit_thin_lto_summary: bool, // Miscellaneous flags. These are mostly copied from command-line @@ -212,9 +211,6 @@ impl ModuleConfig { false ), emit_obj, - // thin lto summaries prevent fat lto, so do not emit them if fat - // lto is requested. See PR #136840 for background information. - emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto && sess.lto() != Lto::Fat, emit_thin_lto_summary: if_regular!( sess.opts.output_types.contains_key(&OutputType::ThinLinkBitcode), false diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 5ebf898f45a34..eabc6baed94d0 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -796,7 +796,6 @@ fn test_unstable_options_tracking_hash() { tracked!(dwarf_version, Some(5)); tracked!(embed_metadata, false); tracked!(embed_source, true); - tracked!(emit_thin_lto, false); tracked!(emscripten_wasm_eh, false); tracked!(export_executable_symbols, true); tracked!(fewer_names, Some(true)); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 7aa4ddea78e1d..ee600ebb72f93 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -566,7 +566,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( LLVMModuleRef ModuleRef, LLVMTargetMachineRef TMRef, LLVMRustPassBuilderOptLevel OptLevelRust, LLVMRustOptStage OptStage, bool IsLinkerPluginLTO, bool NoPrepopulatePasses, bool VerifyIR, - bool LintIR, LLVMRustThinLTOBuffer **ThinLTOBufferRef, bool EmitThinLTO, + bool LintIR, LLVMRustThinLTOBuffer **ThinLTOBufferRef, bool EmitThinLTOSummary, bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers, registerEnzymeAndPassPipelineFn EnzymePtr, @@ -808,7 +808,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( } ModulePassManager MPM; - bool NeedThinLTOBufferPasses = EmitThinLTO; + bool NeedThinLTOBufferPasses = true; auto ThinLTOBuffer = std::make_unique(); raw_string_ostream ThinLTODataOS(ThinLTOBuffer->data); raw_string_ostream ThinLinkDataOS(ThinLTOBuffer->thin_link_data); @@ -840,12 +840,8 @@ extern "C" LLVMRustResult LLVMRustOptimize( // bitcode for embedding is obtained after performing // `ThinLTOPreLinkDefaultPipeline`. MPM.addPass(PB.buildThinLTOPreLinkDefaultPipeline(OptLevel)); - if (EmitThinLTO) { - MPM.addPass(ThinLTOBitcodeWriterPass( - ThinLTODataOS, EmitThinLTOSummary ? &ThinLinkDataOS : nullptr)); - } else { - MPM.addPass(BitcodeWriterPass(ThinLTODataOS)); - } + MPM.addPass(ThinLTOBitcodeWriterPass( + ThinLTODataOS, EmitThinLTOSummary ? &ThinLinkDataOS : nullptr)); *ThinLTOBufferRef = ThinLTOBuffer.release(); MPM.addPass(PB.buildModuleOptimizationPipeline( OptLevel, ThinOrFullLTOPhase::None)); @@ -870,6 +866,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( break; case LLVMRustOptStage::FatLTO: MPM = PB.buildLTODefaultPipeline(OptLevel, nullptr); + NeedThinLTOBufferPasses = false; break; } } @@ -897,7 +894,9 @@ extern "C" LLVMRustResult LLVMRustOptimize( } // For `-Copt-level=0`, ThinLTO, or LTO. if (ThinLTOBufferRef && *ThinLTOBufferRef == nullptr) { - if (EmitThinLTO) { + // thin lto summaries prevent fat lto, so do not emit them if fat + // lto is requested. See PR #136840 for background information. + if (OptStage != LLVMRustOptStage::PreLinkFatLTO) { MPM.addPass(ThinLTOBitcodeWriterPass( ThinLTODataOS, EmitThinLTOSummary ? &ThinLinkDataOS : nullptr)); } else { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 69f9ad9aa3613..1b3dab1a9487d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2335,8 +2335,6 @@ options! { "embed source text in DWARF debug sections (default: no)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), - emit_thin_lto: bool = (true, parse_bool, [TRACKED], - "emit the bc module with thin LTO info (default: yes)"), emscripten_wasm_eh: bool = (true, parse_bool, [TRACKED], "Use WebAssembly error handling for wasm32-unknown-emscripten"), enforce_type_length_limit: bool = (false, parse_bool, [TRACKED], From fa7f138b3238fab645e5019f5792efb608f1c0eb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:19:55 +0000 Subject: [PATCH 05/10] Deduplicate some code in LLVMRustOptimize --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index ee600ebb72f93..768505b63ffe4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -815,24 +815,19 @@ extern "C" LLVMRustResult LLVMRustOptimize( bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO; if (!NoPrepopulatePasses) { + for (const auto &C : PipelineStartEPCallbacks) + PB.registerPipelineStartEPCallback(C); + for (const auto &C : OptimizerLastEPCallbacks) + PB.registerOptimizerLastEPCallback(C); + // The pre-link pipelines don't support O0 and require using // buildO0DefaultPipeline() instead. At the same time, the LTO pipelines do // support O0 and using them is required. if (OptLevel == OptimizationLevel::O0 && !IsLTO) { - for (const auto &C : PipelineStartEPCallbacks) - PB.registerPipelineStartEPCallback(C); - for (const auto &C : OptimizerLastEPCallbacks) - PB.registerOptimizerLastEPCallback(C); - // We manually schedule ThinLTOBufferPasses below, so don't pass the value // to enable it here. MPM = PB.buildO0DefaultPipeline(OptLevel); } else { - for (const auto &C : PipelineStartEPCallbacks) - PB.registerPipelineStartEPCallback(C); - for (const auto &C : OptimizerLastEPCallbacks) - PB.registerOptimizerLastEPCallback(C); - switch (OptStage) { case LLVMRustOptStage::PreLinkNoLTO: if (ThinLTOBufferRef) { From 6dab8fa226adf86ad340430f85e909423526abde Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 17 Feb 2026 11:15:32 +0000 Subject: [PATCH 06/10] Clarify comment --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 768505b63ffe4..f6b4d6cc15439 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -887,7 +887,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( MPM.addPass(CanonicalizeAliasesPass()); MPM.addPass(NameAnonGlobalPass()); } - // For `-Copt-level=0`, ThinLTO, or LTO. + // For `-Copt-level=0`, and the pre-link fat/thin LTO stages. if (ThinLTOBufferRef && *ThinLTOBufferRef == nullptr) { // thin lto summaries prevent fat lto, so do not emit them if fat // lto is requested. See PR #136840 for background information. From ede72796ba79d2dda3a8668a813c307196dd65d8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 18 Feb 2026 22:27:24 +1100 Subject: [PATCH 07/10] Clarify some variable names in the query proc-macro --- compiler/rustc_macros/src/query.rs | 85 +++++++++++++++++++----------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 5b869dc3409a7..d81bac4930a63 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -30,14 +30,28 @@ fn check_attributes(attrs: Vec) -> Result> { attrs.into_iter().map(inner).collect() } -/// A compiler query. `query ... { ... }` +/// Declaration of a compiler query. +/// +/// ```ignore (illustrative) +/// /// Doc comment for `my_query`. +/// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doc_comments +/// query my_query(key: DefId) -> Value { anon } +/// // ^^^^^^^^ name +/// // ^^^ key_pat +/// // ^^^^^ key_ty +/// // ^^^^^^^^ return_ty +/// // ^^^^ modifiers +/// ``` struct Query { doc_comments: Vec, - modifiers: QueryModifiers, name: Ident, - key: Pat, - arg: Type, - result: ReturnType, + + /// Parameter name for the key, or an arbitrary irrefutable pattern (e.g. `_`). + key_pat: Pat, + key_ty: Type, + return_ty: ReturnType, + + modifiers: QueryModifiers, } impl Parse for Query { @@ -47,18 +61,22 @@ impl Parse for Query { // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>` input.parse::()?; let name: Ident = input.parse()?; - let arg_content; - parenthesized!(arg_content in input); - let key = Pat::parse_single(&arg_content)?; - arg_content.parse::()?; - let arg = arg_content.parse()?; - let _ = arg_content.parse::>()?; - let result = input.parse()?; + + // `(key: DefId)` + let parens_content; + parenthesized!(parens_content in input); + let key_pat = Pat::parse_single(&parens_content)?; + parens_content.parse::()?; + let key_ty = parens_content.parse::()?; + let _trailing_comma = parens_content.parse::>()?; + + // `-> Value` + let return_ty = input.parse::()?; // Parse the query modifiers - let content; - braced!(content in input); - let modifiers = parse_query_modifiers(&content)?; + let braces_content; + braced!(braces_content in input); + let modifiers = parse_query_modifiers(&braces_content)?; // If there are no doc-comments, give at least some idea of what // it does by showing the query description. @@ -66,7 +84,7 @@ impl Parse for Query { doc_comments.push(doc_comment_from_desc(&modifiers.desc.expr_list)?); } - Ok(Query { doc_comments, modifiers, name, key, arg, result }) + Ok(Query { doc_comments, modifiers, name, key_pat, key_ty, return_ty }) } } @@ -288,7 +306,7 @@ struct HelperTokenStreams { } fn make_helpers_for_query(query: &Query, streams: &mut HelperTokenStreams) { - let Query { name, key, modifiers, arg, .. } = &query; + let Query { name, key_pat, key_ty, modifiers, .. } = &query; // Replace span for `name` to make rust-analyzer ignore it. let mut erased_name = name.clone(); @@ -301,7 +319,7 @@ fn make_helpers_for_query(query: &Query, streams: &mut HelperTokenStreams) { streams.cache_on_disk_if_fns_stream.extend(quote! { #[allow(unused_variables, rustc::pass_by_value)] #[inline] - pub fn #erased_name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::queries::#name::Key<'tcx>) -> bool + pub fn #erased_name<'tcx>(#tcx: TyCtxt<'tcx>, #key_pat: &crate::queries::#name::Key<'tcx>) -> bool #block }); } @@ -311,8 +329,8 @@ fn make_helpers_for_query(query: &Query, streams: &mut HelperTokenStreams) { let desc = quote! { #[allow(unused_variables)] - pub fn #erased_name<'tcx>(tcx: TyCtxt<'tcx>, key: #arg) -> String { - let (#tcx, #key) = (tcx, key); + pub fn #erased_name<'tcx>(tcx: TyCtxt<'tcx>, key: #key_ty) -> String { + let (#tcx, #key_pat) = (tcx, key); format!(#expr_list) } }; @@ -373,7 +391,7 @@ fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::Toke let mut erased_name = name.clone(); erased_name.set_span(Span::call_site()); - let result = &query.result; + let result = &query.return_ty; // This dead code exists to instruct rust-analyzer about the link between the `rustc_queries` // query names and the corresponding produced provider. The issue is that by nature of this @@ -417,19 +435,20 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { } for query in queries.0 { - let Query { name, arg, modifiers, .. } = &query; - let result_full = &query.result; - let result = match query.result { + let Query { doc_comments, name, key_ty, return_ty, modifiers, .. } = &query; + + // Normalize an absent return type into `-> ()` to make macro-rules parsing easier. + let return_ty = match return_ty { ReturnType::Default => quote! { -> () }, - _ => quote! { #result_full }, + ReturnType::Type(..) => quote! { #return_ty }, }; - let mut attributes = Vec::new(); + let mut modifiers_out = vec![]; macro_rules! passthrough { ( $( $modifier:ident ),+ $(,)? ) => { $( if let Some($modifier) = &modifiers.$modifier { - attributes.push(quote! { (#$modifier) }); + modifiers_out.push(quote! { (#$modifier) }); }; )+ } } @@ -452,7 +471,7 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { // on a synthetic `(cache_on_disk)` modifier that can be inspected by // macro-rules macros. if modifiers.cache_on_disk_if.is_some() { - attributes.push(quote! { (cache_on_disk) }); + modifiers_out.push(quote! { (cache_on_disk) }); } // This uses the span of the query definition for the commas, @@ -462,12 +481,13 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { // at the entire `rustc_queries!` invocation, which wouldn't // be very useful. let span = name.span(); - let attribute_stream = quote_spanned! {span=> #(#attributes),*}; - let doc_comments = &query.doc_comments; + let modifiers_stream = quote_spanned! { span => #(#modifiers_out),* }; + // Add the query to the group query_stream.extend(quote! { #(#doc_comments)* - [#attribute_stream] fn #name(#arg) #result, + [#modifiers_stream] + fn #name(#key_ty) #return_ty, }); if let Some(feedable) = &modifiers.feedable { @@ -482,7 +502,8 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { "Query {name} cannot be both `feedable` and `eval_always`." ); feedable_queries.extend(quote! { - [#attribute_stream] fn #name(#arg) #result, + [#modifiers_stream] + fn #name(#key_ty) #return_ty, }); } From 27c04763e1b74b3ed241002bfb26061f2b3d66be Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Thu, 19 Feb 2026 10:27:22 -0500 Subject: [PATCH 08/10] Fix typo in doc for core::mem::type_info::Struct --- library/core/src/mem/type_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 18612565aeef2..740055563d2d8 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -153,7 +153,7 @@ pub struct Trait { pub is_auto: bool, } -/// Compile-time type information about arrays. +/// Compile-time type information about structs. #[derive(Debug)] #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] From aebafba4bba5d0034edba046821b83ff65ef2a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ozan=20Kenan=20G=C3=BCng=C3=B6r?= Date: Thu, 19 Feb 2026 21:22:06 +0300 Subject: [PATCH 09/10] resolve: do not suggest `_` for unresolved imports `use _` is never valid, so it should not be suggested as a similar name. --- compiler/rustc_resolve/src/imports.rs | 3 +++ .../underscore-bindings-disambiguators.stderr | 12 ------------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d9f9d1ff5a479..704c316bce650 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1282,6 +1282,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if i.name == ident.name { return None; } // Never suggest the same name + if i.name == kw::Underscore { + return None; + } // `use _` is never valid let resolution = resolution.borrow(); if let Some(name_binding) = resolution.best_decl() { diff --git a/tests/ui/resolve/underscore-bindings-disambiguators.stderr b/tests/ui/resolve/underscore-bindings-disambiguators.stderr index 69ac95158f8cb..ec1dec8fe8e28 100644 --- a/tests/ui/resolve/underscore-bindings-disambiguators.stderr +++ b/tests/ui/resolve/underscore-bindings-disambiguators.stderr @@ -3,24 +3,12 @@ error[E0432]: unresolved import `X` | LL | use X as Y; | ^^^^^^ no `X` in the root - | -help: a similar name exists in the module - | -LL - use X as Y; -LL + use _ as Y; - | error[E0432]: unresolved import `Z` --> $DIR/underscore-bindings-disambiguators.rs:26:5 | LL | use Z as W; | ^^^^^^ no `Z` in the root - | -help: a similar name exists in the module - | -LL - use Z as W; -LL + use _ as W; - | error[E0080]: evaluation panicked: not yet implemented --> $DIR/underscore-bindings-disambiguators.rs:19:19 From 4ab6d1f4ccd3d4d4cfa267f839363c787894b0d0 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Thu, 19 Feb 2026 15:04:36 -0800 Subject: [PATCH 10/10] std::ops::ControlFlow - use "a" before `Result` Rather than "an" --- library/core/src/ops/control_flow.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 84fc98cf73f1e..190401967264e 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -197,7 +197,7 @@ impl ControlFlow { } } - /// Converts the `ControlFlow` into an `Result` which is `Ok` if the + /// Converts the `ControlFlow` into a `Result` which is `Ok` if the /// `ControlFlow` was `Break` and `Err` if otherwise. /// /// # Examples @@ -311,7 +311,7 @@ impl ControlFlow { } } - /// Converts the `ControlFlow` into an `Result` which is `Ok` if the + /// Converts the `ControlFlow` into a `Result` which is `Ok` if the /// `ControlFlow` was `Continue` and `Err` if otherwise. /// /// # Examples