From fc7de9979e418b0ea467bb2833b07486d7c54940 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Aug 2025 13:36:10 +0000 Subject: [PATCH 01/13] Ensure we emit an allocator shim when only some crate types need one --- compiler/rustc_codegen_ssa/src/back/link.rs | 17 ++++++++++--- compiler/rustc_codegen_ssa/src/base.rs | 27 +++++++++++++++++---- tests/ui/linking/mixed-allocator-shim.rs | 15 ++++++++++++ 3 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 tests/ui/linking/mixed-allocator-shim.rs diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 19c919c0e4efe..48b01ea2df197 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -58,6 +58,7 @@ use super::linker::{self, Linker}; use super::metadata::{MetadataPosition, create_wrapper_file}; use super::rpath::{self, RPathConfig}; use super::{apple, versioned_llvm_target}; +use crate::base::needs_allocator_shim_for_linking; use crate::{ CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file, }; @@ -2080,9 +2081,17 @@ fn add_local_crate_regular_objects(cmd: &mut dyn Linker, codegen_results: &Codeg } /// Add object files for allocator code linked once for the whole crate tree. -fn add_local_crate_allocator_objects(cmd: &mut dyn Linker, codegen_results: &CodegenResults) { - if let Some(obj) = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref()) { - cmd.add_object(obj); +fn add_local_crate_allocator_objects( + cmd: &mut dyn Linker, + codegen_results: &CodegenResults, + crate_type: CrateType, +) { + if needs_allocator_shim_for_linking(&codegen_results.crate_info.dependency_formats, crate_type) + { + if let Some(obj) = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref()) + { + cmd.add_object(obj); + } } } @@ -2281,7 +2290,7 @@ fn linker_with_args( codegen_results, metadata, ); - add_local_crate_allocator_objects(cmd, codegen_results); + add_local_crate_allocator_objects(cmd, codegen_results, crate_type); // Avoid linking to dynamic libraries unless they satisfy some undefined symbols // at the point at which they are specified on the command line. diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 8abaf201abae2..97cdf8b697348 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -17,6 +17,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ItemId, Target}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; +use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::{self, SymbolExportKind}; use rustc_middle::middle::lang_items; use rustc_middle::mir::BinOp; @@ -630,14 +631,30 @@ pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option { // If the crate doesn't have an `allocator_kind` set then there's definitely // no shim to generate. Otherwise we also check our dependency graph for all // our output crate types. If anything there looks like its a `Dynamic` - // linkage, then it's already got an allocator shim and we'll be using that - // one instead. If nothing exists then it's our job to generate the - // allocator! - let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| { + // linkage for all crate types we may link as, then it's already got an + // allocator shim and we'll be using that one instead. If nothing exists + // then it's our job to generate the allocator! If crate types disagree + // about whether an allocator shim is necessary or not, we generate one + // and let needs_allocator_shim_for_linking decide at link time whether or + // not to use it for any particular linker invocation. + let all_crate_types_any_dynamic_crate = tcx.dependency_formats(()).iter().all(|(_, list)| { use rustc_middle::middle::dependency_format::Linkage; list.iter().any(|&linkage| linkage == Linkage::Dynamic) }); - if any_dynamic_crate { None } else { tcx.allocator_kind(()) } + if all_crate_types_any_dynamic_crate { None } else { tcx.allocator_kind(()) } +} + +/// Decide if this particular crate type needs an allocator shim linked in. +/// This may return true even when allocator_kind_for_codegen returns false. In +/// this case no allocator shim shall be linked. +pub(crate) fn needs_allocator_shim_for_linking( + dependency_formats: &Dependencies, + crate_type: CrateType, +) -> bool { + use rustc_middle::middle::dependency_format::Linkage; + let any_dynamic_crate = + dependency_formats[&crate_type].iter().any(|&linkage| linkage == Linkage::Dynamic); + !any_dynamic_crate } pub fn codegen_crate( diff --git a/tests/ui/linking/mixed-allocator-shim.rs b/tests/ui/linking/mixed-allocator-shim.rs new file mode 100644 index 0000000000000..b81fbdc5205e7 --- /dev/null +++ b/tests/ui/linking/mixed-allocator-shim.rs @@ -0,0 +1,15 @@ +//@ build-pass +//@ compile-flags: --crate-type staticlib,dylib -Zstaticlib-prefer-dynamic +//@ no-prefer-dynamic + +// Test that compiling for multiple crate types in a single compilation with +// mismatching allocator shim requirements doesn't result in the allocator shim +// missing entirely. +// In this particular test the dylib crate type will statically link libstd and +// thus need an allocator shim, while the staticlib crate type will dynamically +// link libstd and thus not need an allocator shim. +// The -Zstaticlib-prefer-dynamic flag could be avoided by doing it the other +// way around, but testing that the staticlib correctly has the allocator shim +// in that case would require a run-make test instead. + +pub fn foo() {} From 1d309008306f6695bdbbd535245067202ab44802 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Aug 2025 15:16:48 +0000 Subject: [PATCH 02/13] Fix typo in comment --- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index df1e91b12f904..03c30dc0c5929 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1827,7 +1827,7 @@ fn exported_symbols_for_non_proc_macro( let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { // Do not export mangled symbols from cdylibs and don't attempt to export compiler-builtins - // from any cdylib. The latter doesn't work anyway as we use hidden visibility for + // from any dylib. The latter doesn't work anyway as we use hidden visibility for // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning. if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) { symbols.push(( From f4888c2a680aff0bd191704a8d44716eee94103e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Aug 2025 16:59:22 +0000 Subject: [PATCH 03/13] Correctly handle different crate types disagreeing if the allocator shim is exported Previously it would attempt to export the allocator shim even linking for a crate type which pulls in the allocator shim from a dylib rather than locally defining it. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 15 +++++- compiler/rustc_codegen_ssa/src/back/lto.rs | 8 ++- .../src/back/symbol_export.rs | 52 +++++++++---------- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 03c30dc0c5929..a2efd420a327a 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -11,8 +11,9 @@ use rustc_metadata::{ }; use rustc_middle::bug; use rustc_middle::middle::dependency_format::Linkage; -use rustc_middle::middle::exported_symbols; -use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; +use rustc_middle::middle::exported_symbols::{ + self, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, +}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; @@ -22,6 +23,8 @@ use tracing::{debug, warn}; use super::command::Command; use super::symbol_export; +use crate::back::symbol_export::allocator_shim_symbols; +use crate::base::needs_allocator_shim_for_linking; use crate::errors; #[cfg(test)] @@ -1838,6 +1841,14 @@ fn exported_symbols_for_non_proc_macro( } }); + // Mark allocator shim symbols as exported only if they were generated. + if export_threshold == SymbolExportLevel::Rust + && needs_allocator_shim_for_linking(tcx.dependency_formats(()), crate_type) + && tcx.allocator_kind(()).is_some() + { + symbols.extend(allocator_shim_symbols(tcx)); + } + symbols } diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index c95038375a1bd..e6df6a2469f37 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -8,8 +8,9 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::{CrateType, Lto}; use tracing::info; -use crate::back::symbol_export::{self, symbol_name_for_instance_in_crate}; +use crate::back::symbol_export::{self, allocator_shim_symbols, symbol_name_for_instance_in_crate}; use crate::back::write::CodegenContext; +use crate::base::allocator_kind_for_codegen; use crate::errors::{DynamicLinkingWithLTO, LtoDisallowed, LtoDylib, LtoProcMacro}; use crate::traits::*; @@ -115,6 +116,11 @@ pub(super) fn exported_symbols_for_lto( } } + // Mark allocator shim symbols as exported only if they were generated. + if export_threshold == SymbolExportLevel::Rust && allocator_kind_for_codegen(tcx).is_some() { + symbols_below_threshold.extend(allocator_shim_symbols(tcx).map(|(name, _kind)| name)); + } + symbols_below_threshold } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index d8a1480e911fe..b49e67217fb01 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -18,7 +18,7 @@ use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::TlsModel; use tracing::debug; -use crate::base::allocator_kind_for_codegen; +use crate::back::symbol_export; fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { crates_export_threshold(tcx.crate_types()) @@ -217,31 +217,6 @@ fn exported_non_generic_symbols_provider_local<'tcx>( )); } - // Mark allocator shim symbols as exported only if they were generated. - if allocator_kind_for_codegen(tcx).is_some() { - for symbol_name in ALLOCATOR_METHODS - .iter() - .map(|method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str())) - .chain([ - mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - ]) - { - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); - - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - rustc_std_internal_symbol: true, - }, - )); - } - } - // Sort so we get a stable incr. comp. hash. symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); @@ -516,6 +491,31 @@ pub(crate) fn provide(providers: &mut Providers) { upstream_monomorphizations_for_provider; } +pub(crate) fn allocator_shim_symbols( + tcx: TyCtxt<'_>, +) -> impl Iterator { + ALLOCATOR_METHODS + .iter() + .map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str())) + .chain([ + mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), + mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + ]) + .map(move |symbol_name| { + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); + + ( + symbol_export::exporting_symbol_name_for_instance_in_crate( + tcx, + exported_symbol, + LOCAL_CRATE, + ), + SymbolExportKind::Text, + ) + }) +} + fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel { // We export anything that's not mangled at the "C" layer as it probably has // to do with ABI concerns. We do not, however, apply such treatment to From 0711bba9ea368204b1a7f833e0e44c529ce140c8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 31 Aug 2025 20:43:44 +0000 Subject: [PATCH 04/13] Ignore test when dylibs are not supported --- tests/ui/linking/mixed-allocator-shim.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/linking/mixed-allocator-shim.rs b/tests/ui/linking/mixed-allocator-shim.rs index b81fbdc5205e7..e4f20a11ebb37 100644 --- a/tests/ui/linking/mixed-allocator-shim.rs +++ b/tests/ui/linking/mixed-allocator-shim.rs @@ -1,6 +1,7 @@ //@ build-pass //@ compile-flags: --crate-type staticlib,dylib -Zstaticlib-prefer-dynamic //@ no-prefer-dynamic +//@ needs-crate-type: dylib // Test that compiling for multiple crate types in a single compilation with // mismatching allocator shim requirements doesn't result in the allocator shim From f696cd8b0aefc0ea7d3ab4aaf2a7c8d8d520df32 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 27 Aug 2025 20:33:50 -0600 Subject: [PATCH 05/13] fix: Filter suggestion parts that match existing code --- compiler/rustc_errors/src/lib.rs | 21 ++++++++++--------- .../tests/ui/bool_assert_comparison.stderr | 12 ++++------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 71fc54f0d33f0..e646001b64148 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -378,6 +378,11 @@ impl CodeSuggestion { }) .cloned() .filter_map(|mut substitution| { + // Account for cases where we are suggesting the same code that's already + // there. This shouldn't happen often, but in some cases for multipart + // suggestions it's much easier to handle it here than in the origin. + substitution.parts.retain(|p| is_different(sm, &p.snippet, p.span)); + // Assumption: all spans are in the same file, and all spans // are disjoint. Sort in ascending order. substitution.parts.sort_by_key(|part| part.span.lo()); @@ -470,16 +475,12 @@ impl CodeSuggestion { _ => 1, }) .sum(); - if !is_different(sm, &part.snippet, part.span) { - // Account for cases where we are suggesting the same code that's already - // there. This shouldn't happen often, but in some cases for multipart - // suggestions it's much easier to handle it here than in the origin. - } else { - line_highlight.push(SubstitutionHighlight { - start: (cur_lo.col.0 as isize + acc) as usize, - end: (cur_lo.col.0 as isize + acc + len) as usize, - }); - } + + line_highlight.push(SubstitutionHighlight { + start: (cur_lo.col.0 as isize + acc) as usize, + end: (cur_lo.col.0 as isize + acc + len) as usize, + }); + buf.push_str(&part.snippet); let cur_hi = sm.lookup_char_pos(part.span.hi()); // Account for the difference between the width of the current code and the diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr index f823f08f31dca..72aa6303a2026 100644 --- a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr @@ -272,10 +272,8 @@ LL | assert_eq!(a!(), true); | help: replace it with `assert!(..)` | -LL | true -... -LL | -LL ~ assert!(a!()); +LL - assert_eq!(a!(), true); +LL + assert!(a!()); | error: used `assert_eq!` with a literal bool @@ -286,10 +284,8 @@ LL | assert_eq!(true, b!()); | help: replace it with `assert!(..)` | -LL | true -... -LL | -LL ~ assert!(b!()); +LL - assert_eq!(true, b!()); +LL + assert!(b!()); | error: used `debug_assert_eq!` with a literal bool From 5e9b655e7094295ba4ce40568d8f182aef3704fc Mon Sep 17 00:00:00 2001 From: Samuel Moelius <35515885+smoelius@users.noreply.github.com> Date: Tue, 2 Sep 2025 08:43:34 -0400 Subject: [PATCH 06/13] Correct typo in `rustc_errors` comment --- compiler/rustc_errors/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 71fc54f0d33f0..a56e0f3fae132 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1160,7 +1160,7 @@ impl<'a> DiagCtxtHandle<'a> { // - It's only produce with JSON output. // - It's not emitted the usual way, via `emit_diagnostic`. // - The `$message_type` field is "unused_externs" rather than the usual - // "diagnosic". + // "diagnostic". // // We count it as a lint error because it has a lint level. The value // of `loud` (which comes from "unused-externs" or From 5b43244ac59119870c9e0f6b642340ab88355b23 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 28 Aug 2025 23:31:46 +0800 Subject: [PATCH 07/13] Add LSX accelerated implementation for source file analysis This patch introduces an LSX-optimized version of `analyze_source_file` for the `loongarch64` target. Similar to existing SSE2 implementation for x86, this version: - Processes 16-byte chunks at a time using LSX vector intrinsics. - Quickly identifies newlines in ASCII-only chunks. - Falls back to the generic implementation when multi-byte UTF-8 characters are detected or in the tail portion. --- .../rustc_span/src/analyze_source_file.rs | 109 +++++++++++++++++- compiler/rustc_span/src/lib.rs | 1 + 2 files changed, 107 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index c32593a6d95ab..bb2cda77dffff 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -81,8 +81,8 @@ cfg_select! { // use `loadu`, which supports unaligned loading. let chunk = unsafe { _mm_loadu_si128(chunk.as_ptr() as *const __m128i) }; - // For character in the chunk, see if its byte value is < 0, which - // indicates that it's part of a UTF-8 char. + // For each character in the chunk, see if its byte value is < 0, + // which indicates that it's part of a UTF-8 char. let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); // Create a bit mask from the comparison results. let multibyte_mask = _mm_movemask_epi8(multibyte_test); @@ -132,8 +132,111 @@ cfg_select! { } } } + target_arch = "loongarch64" => { + fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut Vec, + ) { + use std::arch::is_loongarch_feature_detected; + + if is_loongarch_feature_detected!("lsx") { + unsafe { + analyze_source_file_lsx(src, lines, multi_byte_chars); + } + } else { + analyze_source_file_generic( + src, + src.len(), + RelativeBytePos::from_u32(0), + lines, + multi_byte_chars, + ); + } + } + + /// Checks 16 byte chunks of text at a time. If the chunk contains + /// something other than printable ASCII characters and newlines, the + /// function falls back to the generic implementation. Otherwise it uses + /// LSX intrinsics to quickly find all newlines. + #[target_feature(enable = "lsx")] + unsafe fn analyze_source_file_lsx( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut Vec, + ) { + use std::arch::loongarch64::*; + + const CHUNK_SIZE: usize = 16; + + let (chunks, tail) = src.as_bytes().as_chunks::(); + + // This variable keeps track of where we should start decoding a + // chunk. If a multi-byte character spans across chunk boundaries, + // we need to skip that part in the next chunk because we already + // handled it. + let mut intra_chunk_offset = 0; + + for (chunk_index, chunk) in chunks.iter().enumerate() { + // All LSX memory instructions support unaligned access, so using + // vld is fine. + let chunk = unsafe { lsx_vld::<0>(chunk.as_ptr() as *const i8) }; + + // For each character in the chunk, see if its byte value is < 0, + // which indicates that it's part of a UTF-8 char. + let multibyte_mask = lsx_vmskltz_b(chunk); + // Create a bit mask from the comparison results. + let multibyte_mask = lsx_vpickve2gr_w::<0>(multibyte_mask); + + // If the bit mask is all zero, we only have ASCII chars here: + if multibyte_mask == 0 { + assert!(intra_chunk_offset == 0); + + // Check for newlines in the chunk + let newlines_test = lsx_vseqi_b::<{b'\n' as i32}>(chunk); + let newlines_mask = lsx_vmskltz_b(newlines_test); + let mut newlines_mask = lsx_vpickve2gr_w::<0>(newlines_mask); + + let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1); + + while newlines_mask != 0 { + let index = newlines_mask.trailing_zeros(); + + lines.push(RelativeBytePos(index) + output_offset); + + // Clear the bit, so we can find the next one. + newlines_mask &= newlines_mask - 1; + } + } else { + // The slow path. + // There are multibyte chars in here, fallback to generic decoding. + let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset; + intra_chunk_offset = analyze_source_file_generic( + &src[scan_start..], + CHUNK_SIZE - intra_chunk_offset, + RelativeBytePos::from_usize(scan_start), + lines, + multi_byte_chars, + ); + } + } + + // There might still be a tail left to analyze + let tail_start = src.len() - tail.len() + intra_chunk_offset; + if tail_start < src.len() { + analyze_source_file_generic( + &src[tail_start..], + src.len() - tail_start, + RelativeBytePos::from_usize(tail_start), + lines, + multi_byte_chars, + ); + } + } + } _ => { - // The target (or compiler version) does not support SSE2 ... + // The target (or compiler version) does not support vector instructions + // our specialized implementations need (x86 SSE2, loongarch64 LSX)... fn analyze_source_file_dispatch( src: &str, lines: &mut Vec, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ae6755f076424..8907c5e4c4aeb 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -18,6 +18,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![cfg_attr(bootstrap, feature(round_char_boundary))] +#![cfg_attr(target_arch = "loongarch64", feature(stdarch_loongarch))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] From a8537ab84bf7fd14b2445a058075dac764932e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 1 Sep 2025 15:21:02 +0200 Subject: [PATCH 08/13] Remove special implementation of `PartialEq` for `InvisibleOrigin` outside macro matching --- compiler/rustc_ast/src/token.rs | 20 +++---------------- compiler/rustc_expand/src/mbe/macro_parser.rs | 20 +++++++++++++++++-- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index ea98bebd30555..6dc6d1026f621 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -22,8 +22,7 @@ pub enum CommentKind { Block, } -// This type must not implement `Hash` due to the unusual `PartialEq` impl below. -#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)] pub enum InvisibleOrigin { // From the expansion of a metavariable in a declarative macro. MetaVar(MetaVarKind), @@ -45,20 +44,6 @@ impl InvisibleOrigin { } } -impl PartialEq for InvisibleOrigin { - #[inline] - fn eq(&self, _other: &InvisibleOrigin) -> bool { - // When we had AST-based nonterminals we couldn't compare them, and the - // old `Nonterminal` type had an `eq` that always returned false, - // resulting in this restriction: - // https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment - // This `eq` emulates that behaviour. We could consider lifting this - // restriction now but there are still cases involving invisible - // delimiters that make it harder than it first appears. - false - } -} - /// Annoyingly similar to `NonterminalKind`, but the slight differences are important. #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum MetaVarKind { @@ -142,7 +127,8 @@ impl Delimiter { } } - // This exists because `InvisibleOrigin`s should be compared. It is only used for assertions. + // This exists because `InvisibleOrigin`s should not be compared. It is only used for + // assertions. pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool { match (self, other) { (Delimiter::Parenthesis, Delimiter::Parenthesis) => true, diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 0324057e331a9..ab8e059b7b77f 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -77,7 +77,7 @@ use std::rc::Rc; pub(crate) use NamedMatch::*; pub(crate) use ParseResult::*; -use rustc_ast::token::{self, DocComment, NonterminalKind, Token}; +use rustc_ast::token::{self, DocComment, NonterminalKind, Token, TokenKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_lint_defs::pluralize; @@ -397,7 +397,23 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { { ident1.name == ident2.name && is_raw1 == is_raw2 } else { - t1.kind == t2.kind + // Note: we SHOULD NOT use `t1.kind == t2.kind` here, and we should instead compare the + // tokens using the special comparison logic below. + // It makes sure that variants containing `InvisibleOrigin` will + // never compare equal to one another. + // + // When we had AST-based nonterminals we couldn't compare them, and the + // old `Nonterminal` type had an `eq` that always returned false, + // resulting in this restriction: + // + // This comparison logic emulates that behaviour. We could consider lifting this + // restriction now but there are still cases involving invisible + // delimiters that make it harder than it first appears. + match (t1.kind, t2.kind) { + (TokenKind::OpenInvisible(_) | TokenKind::CloseInvisible(_), _) + | (_, TokenKind::OpenInvisible(_) | TokenKind::CloseInvisible(_)) => false, + (a, b) => a == b, + } } } From 5d9f8fcd3ea44bdd633ecddac2aff471ffcb797f Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Tue, 2 Sep 2025 18:43:48 +0000 Subject: [PATCH 09/13] llvm: nvptx: Layout update to match LLVM LLVM upstream switched layouts to support 256-bit vector load/store. --- compiler/rustc_codegen_llvm/src/context.rs | 4 ++++ compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4fd6110ac4a11..257c7b95666f7 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -217,6 +217,10 @@ pub(crate) unsafe fn create_module<'ll>( // LLVM 22.0 updated the default layout on avr: https://github.com/llvm/llvm-project/pull/153010 target_data_layout = target_data_layout.replace("n8:16", "n8") } + if sess.target.arch == "nvptx64" { + // LLVM 22 updated the NVPTX layout to indicate 256-bit vector load/store: https://github.com/llvm/llvm-project/pull/155198 + target_data_layout = target_data_layout.replace("-i256:256", ""); + } } // Ensure the data-layout values hardcoded remain the defaults. diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs index 598f0f19f0def..cada0dd640a49 100644 --- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs @@ -6,7 +6,7 @@ use crate::spec::{ pub(crate) fn target() -> Target { Target { arch: "nvptx64".into(), - data_layout: "e-p6:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64".into(), + data_layout: "e-p6:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64".into(), llvm_target: "nvptx64-nvidia-cuda".into(), metadata: TargetMetadata { description: Some("--emit=asm generates PTX code that runs on NVIDIA GPUs".into()), From 5a9e2e4aa8b388b25d146d86f70e55427bda8dd5 Mon Sep 17 00:00:00 2001 From: AudaciousAxiom <179637270+AudaciousAxiom@users.noreply.github.com> Date: Tue, 2 Sep 2025 21:34:04 +0200 Subject: [PATCH 10/13] docs(std): add missing closing code block fences in doc comments --- library/core/src/iter/adapters/chain.rs | 1 + library/core/src/num/int_macros.rs | 2 +- library/core/src/num/uint_macros.rs | 2 +- library/core/src/ops/range.rs | 1 + library/core/src/ptr/mut_ptr.rs | 1 + library/portable-simd/crates/core_simd/src/simd/num/int.rs | 1 + library/portable-simd/crates/core_simd/src/simd/num/uint.rs | 1 + 7 files changed, 7 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 943b88e23305a..3ebdf7b472796 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -321,6 +321,7 @@ impl Default for Chain { /// /// // take requires `Default` /// let _: Chain<_, _> = mem::take(&mut foo.0); + /// ``` fn default() -> Self { Chain::new(Default::default(), Default::default()) } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 25864db5fea77..db70fb65d444e 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1285,7 +1285,7 @@ macro_rules! int_impl { /// /// ```should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] - /// + /// ``` #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index c1e656fdea236..a5c8ae7e26edf 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1620,7 +1620,7 @@ macro_rules! uint_impl { /// /// ```should_panic #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")] - /// + /// ``` #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index c0a27775694c3..58a9431bd845d 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -836,6 +836,7 @@ pub trait RangeBounds { /// assert!(!(0.0..1.0).contains(&f32::NAN)); /// assert!(!(0.0..f32::NAN).contains(&0.5)); /// assert!(!(f32::NAN..1.0).contains(&0.5)); + /// ``` #[inline] #[stable(feature = "range_contains", since = "1.35.0")] fn contains(&self, item: &U) -> bool diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 3fe4b08d459e0..ce6eee4f911ed 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -106,6 +106,7 @@ impl *mut T { /// /// // This dereference is UB. The pointer only has provenance for `x` but points to `y`. /// println!("{:?}", unsafe { &*bad }); + /// ``` #[unstable(feature = "set_ptr_value", issue = "75091")] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] diff --git a/library/portable-simd/crates/core_simd/src/simd/num/int.rs b/library/portable-simd/crates/core_simd/src/simd/num/int.rs index d25050c3e4b47..e7253313f036c 100644 --- a/library/portable-simd/crates/core_simd/src/simd/num/int.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num/int.rs @@ -58,6 +58,7 @@ pub trait SimdInt: Copy + Sealed { /// let sat = x.saturating_sub(max); /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0])); /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0])); + /// ``` fn saturating_sub(self, second: Self) -> Self; /// Lanewise absolute value, implemented in Rust. diff --git a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs index 45d978068b664..e3ba8658bd803 100644 --- a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs @@ -55,6 +55,7 @@ pub trait SimdUint: Copy + Sealed { /// let sat = x.saturating_sub(max); /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0])); /// assert_eq!(sat, Simd::splat(0)); + /// ``` fn saturating_sub(self, second: Self) -> Self; /// Lanewise absolute difference. From 54a545011f64bf69fd661609c6f2f63799d56d09 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 2 Sep 2025 10:59:40 -0700 Subject: [PATCH 11/13] rustdoc-search: add test case for indexing every item type Test case for 7b35d8e1ab2d913f4b15d0ee21d5bd8d50798e9c and ad2e0961366a6bf5e01d6863a459424e78ebcf40 --- .../rustdoc-search-load-itemtype/bar.rs | 27 ++++ .../rustdoc-search-load-itemtype/baz.rs | 3 + .../rustdoc-search-load-itemtype/foo.rs | 119 ++++++++++++++++++ .../rustdoc-search-load-itemtype/rmake.rs | 18 +++ 4 files changed, 167 insertions(+) create mode 100644 tests/run-make/rustdoc-search-load-itemtype/bar.rs create mode 100644 tests/run-make/rustdoc-search-load-itemtype/baz.rs create mode 100644 tests/run-make/rustdoc-search-load-itemtype/foo.rs create mode 100644 tests/run-make/rustdoc-search-load-itemtype/rmake.rs diff --git a/tests/run-make/rustdoc-search-load-itemtype/bar.rs b/tests/run-make/rustdoc-search-load-itemtype/bar.rs new file mode 100644 index 0000000000000..0416b1b75b594 --- /dev/null +++ b/tests/run-make/rustdoc-search-load-itemtype/bar.rs @@ -0,0 +1,27 @@ +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +//@ has bar/macro.a_procmacro.html +//@ hasraw search.index/name/*.js a_procmacro +#[proc_macro] +pub fn a_procmacro(_: TokenStream) -> TokenStream { + unimplemented!() +} + +//@ has bar/attr.a_procattribute.html +//@ hasraw search.index/name/*.js a_procattribute +#[proc_macro_attribute] +pub fn a_procattribute(_: TokenStream, _: TokenStream) -> TokenStream { + unimplemented!() +} + +//@ has bar/derive.AProcDerive.html +//@ !has bar/derive.a_procderive.html +//@ hasraw search.index/name/*.js AProcDerive +//@ !hasraw search.index/name/*.js a_procderive +#[proc_macro_derive(AProcDerive)] +pub fn a_procderive(_: TokenStream) -> TokenStream { + unimplemented!() +} diff --git a/tests/run-make/rustdoc-search-load-itemtype/baz.rs b/tests/run-make/rustdoc-search-load-itemtype/baz.rs new file mode 100644 index 0000000000000..4d1f5430fc630 --- /dev/null +++ b/tests/run-make/rustdoc-search-load-itemtype/baz.rs @@ -0,0 +1,3 @@ +//@ has baz/struct.Baz.html +//@ hasraw search.index/name/*.js Baz +pub struct Baz; diff --git a/tests/run-make/rustdoc-search-load-itemtype/foo.rs b/tests/run-make/rustdoc-search-load-itemtype/foo.rs new file mode 100644 index 0000000000000..93b372d10cbf9 --- /dev/null +++ b/tests/run-make/rustdoc-search-load-itemtype/foo.rs @@ -0,0 +1,119 @@ +#![feature(extern_types, rustc_attrs, rustdoc_internals, trait_alias)] +#![allow(internal_features)] +#![no_std] + +//@ has foo/keyword.while.html +//@ hasraw search.index/name/*.js while +//@ !hasraw search.index/name/*.js w_keyword +#[doc(keyword = "while")] +mod w_keyword {} + +//@ has foo/primitive.u32.html +//@ hasraw search.index/name/*.js u32 +//@ !hasraw search.index/name/*.js u_primitive +#[rustc_doc_primitive = "u32"] +mod u_primitive {} + +//@ has foo/x_mod/index.html +//@ hasraw search.index/name/*.js x_mod +pub mod x_mod {} + +//@ hasraw foo/index.html y_crate +//@ hasraw search.index/name/*.js y_crate +#[doc(no_inline)] +pub extern crate core as y_crate; + +//@ hasraw foo/index.html z_import +//@ hasraw search.index/name/*.js z_import +#[doc(no_inline)] +pub use core::option as z_import; + +//@ has foo/struct.AStruct.html +//@ hasraw search.index/name/*.js AStruct +pub struct AStruct { + //@ hasraw foo/struct.AStruct.html a_structfield + //@ hasraw search.index/name/*.js a_structfield + pub a_structfield: i32, +} + +//@ has foo/enum.AEnum.html +//@ hasraw search.index/name/*.js AEnum +pub enum AEnum { + //@ hasraw foo/enum.AEnum.html AVariant + //@ hasraw search.index/name/*.js AVariant + AVariant, +} + +//@ has foo/fn.a_fn.html +//@ hasraw search.index/name/*.js a_fn +pub fn a_fn() {} + +//@ has foo/type.AType.html +//@ hasraw search.index/name/*.js AType +pub type AType = AStruct; + +//@ has foo/static.a_static.html +//@ hasraw search.index/name/*.js a_static +pub static a_static: i32 = 1; + +//@ has foo/trait.ATrait.html +//@ hasraw search.index/name/*.js ATrait +pub trait ATrait { + //@ hasraw foo/trait.ATrait.html a_tymethod + //@ hasraw search.index/name/*.js a_tymethod + fn a_tymethod(); + //@ hasraw foo/trait.ATrait.html AAssocType + //@ hasraw search.index/name/*.js AAssocType + type AAssocType; + //@ hasraw foo/trait.ATrait.html AAssocConst + //@ hasraw search.index/name/*.js AAssocConst + const AAssocConst: bool; +} + +// skip ItemType::Impl, since impls are anonymous +// and have no search entry + +impl AStruct { + //@ hasraw foo/struct.AStruct.html a_method + //@ hasraw search.index/name/*.js a_method + pub fn a_method() {} +} + +//@ has foo/macro.a_macro.html +//@ hasraw search.index/name/*.js a_macro +#[macro_export] +macro_rules! a_macro { + () => {}; +} + +//@ has foo/constant.A_CONSTANT.html +//@ hasraw search.index/name/*.js A_CONSTANT +pub const A_CONSTANT: i32 = 1; + +//@ has foo/union.AUnion.html +//@ hasraw search.index/name/*.js AUnion +pub union AUnion { + //@ hasraw foo/union.AUnion.html a_unionfield + //@ hasraw search.index/name/*.js a_unionfield + pub a_unionfield: i32, +} + +extern "C" { + //@ has foo/foreigntype.AForeignType.html + //@ hasraw search.index/name/*.js AForeignType + pub type AForeignType; +} + +// procattribute and procderive are defined in +// bar.rs, because they only work with proc_macro +// crate type. + +//@ has foo/traitalias.ATraitAlias.html +//@ hasraw search.index/name/*.js ATraitAlias +pub trait ATraitAlias = ATrait; + +//@ has foo/attribute.doc.html +//@ hasraw search.index/name/*.js doc +//@ !hasraw search.index/name/*.js aa_mod +#[doc(attribute = "doc")] +mod aa_mod {} diff --git a/tests/run-make/rustdoc-search-load-itemtype/rmake.rs b/tests/run-make/rustdoc-search-load-itemtype/rmake.rs new file mode 100644 index 0000000000000..a22a3bee41f00 --- /dev/null +++ b/tests/run-make/rustdoc-search-load-itemtype/rmake.rs @@ -0,0 +1,18 @@ +// Test that rustdoc can deserialize a search index with every itemtype. +// https://github.com/rust-lang/rust/pull/146117 + +use std::path::Path; + +use run_make_support::{htmldocck, rfs, rustdoc, source_root}; + +fn main() { + let out_dir = Path::new("rustdoc-search-load-itemtype"); + + rfs::create_dir_all(&out_dir); + rustdoc().out_dir(&out_dir).input("foo.rs").run(); + rustdoc().out_dir(&out_dir).input("bar.rs").arg("--crate-type=proc-macro").run(); + rustdoc().out_dir(&out_dir).input("baz.rs").run(); + htmldocck().arg(out_dir).arg("foo.rs").run(); + htmldocck().arg(out_dir).arg("bar.rs").run(); + htmldocck().arg(out_dir).arg("baz.rs").run(); +} From dd8df3bf5f4984226101b600be231132edd820e8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 2 Sep 2025 14:23:42 -0700 Subject: [PATCH 12/13] htmldocck: fix a bug in relative paths / globs This bug only shows up when you run htmldocck in a directory other than outdir, and also use globs. Never happened before, which is why we're only seeing it now. --- src/etc/htmldocck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 8d7f7341c2e65..46a3a1602ac71 100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -247,7 +247,7 @@ def get_absolute_path(self, path): paths = list(Path(self.root).glob(path)) if len(paths) != 1: raise FailedCheck("glob path does not resolve to one file") - path = str(paths[0]) + return str(paths[0]) return os.path.join(self.root, path) def get_file(self, path): From af0d6f129096dabeee42978c84596a3acb43c1b0 Mon Sep 17 00:00:00 2001 From: jeremyd2019 Date: Tue, 2 Sep 2025 16:27:45 -0700 Subject: [PATCH 13/13] compiletest: cygwin follows windows in using PATH for dynamic libraries --- src/tools/compiletest/src/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 1f16a672a98e7..558e9a58697e7 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -45,7 +45,7 @@ impl Utf8PathBufExt for Utf8PathBuf { /// The name of the environment variable that holds dynamic library locations. pub fn dylib_env_var() -> &'static str { - if cfg!(windows) { + if cfg!(any(windows, target_os = "cygwin")) { "PATH" } else if cfg!(target_vendor = "apple") { "DYLD_LIBRARY_PATH"