From 7dbdb29f5f56c000e33f207cc8f12d471c3cfd06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 26 Feb 2026 13:18:24 +0100 Subject: [PATCH 1/4] Remove unnecessary Arc from `FilesIndex` --- compiler/rustc_session/src/search_paths.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index 3e1fb4df4c3a..c5795fe4a496 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -16,7 +16,7 @@ pub struct SearchPath { /// [FilesIndex] contains paths that can be efficiently looked up with (prefix, suffix) pairs. #[derive(Clone, Debug)] -pub struct FilesIndex(Vec<(Arc, SearchPathFile)>); +pub struct FilesIndex(Vec); impl FilesIndex { /// Look up [SearchPathFile] by (prefix, suffix) pair. @@ -25,15 +25,15 @@ pub fn query<'s>( prefix: &str, suffix: &str, ) -> Option> { - let start = self.0.partition_point(|(k, _)| **k < *prefix); + let start = self.0.partition_point(|v| *v.file_name_str < *prefix); if start == self.0.len() { return None; } - let end = self.0[start..].partition_point(|(k, _)| k.starts_with(prefix)); + let end = self.0[start..].partition_point(|v| v.file_name_str.starts_with(prefix)); let prefixed_items = &self.0[start..][..end]; - let ret = prefixed_items.into_iter().filter_map(move |(k, v)| { - k.ends_with(suffix).then(|| { + let ret = prefixed_items.into_iter().filter_map(move |v| { + v.file_name_str.ends_with(suffix).then(|| { ( String::from( &v.file_name_str[prefix.len()..v.file_name_str.len() - suffix.len()], @@ -45,7 +45,7 @@ pub fn query<'s>( Some(ret) } pub fn retain(&mut self, prefixes: &[&str]) { - self.0.retain(|(k, _)| prefixes.iter().any(|prefix| k.starts_with(prefix))); + self.0.retain(|v| prefixes.iter().any(|prefix| v.file_name_str.starts_with(prefix))); } } /// The obvious implementation of `SearchPath::files` is a `Vec`. But @@ -136,10 +136,7 @@ pub fn new(kind: PathKind, dir: PathBuf) -> Self { e.ok().and_then(|e| { e.file_name().to_str().map(|s| { let file_name_str: Arc = s.into(); - ( - Arc::clone(&file_name_str), - SearchPathFile { path: e.path().into(), file_name_str }, - ) + SearchPathFile { path: e.path().into(), file_name_str } }) }) }) @@ -147,7 +144,7 @@ pub fn new(kind: PathKind, dir: PathBuf) -> Self { Err(..) => Default::default(), }; - files.sort_by(|(lhs, _), (rhs, _)| lhs.cmp(rhs)); + files.sort_by(|lhs, rhs| lhs.file_name_str.cmp(&rhs.file_name_str)); let files = FilesIndex(files); SearchPath { kind, dir, files } } From 516bd8ccb55dbb96f80b7b470b1490ca3ca252fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 26 Feb 2026 13:20:35 +0100 Subject: [PATCH 2/4] Use unstable sort for sorting paths in a search index --- compiler/rustc_session/src/search_paths.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index c5795fe4a496..5cc5ee3d9745 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -144,7 +144,7 @@ pub fn new(kind: PathKind, dir: PathBuf) -> Self { Err(..) => Default::default(), }; - files.sort_by(|lhs, rhs| lhs.file_name_str.cmp(&rhs.file_name_str)); + files.sort_unstable_by(|lhs, rhs| lhs.file_name_str.cmp(&rhs.file_name_str)); let files = FilesIndex(files); SearchPath { kind, dir, files } } From 1c3449db00185d9f5744de4dfeafb5cdc5b77af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 26 Feb 2026 13:32:34 +0100 Subject: [PATCH 3/4] Do not store copy of the full path for each `SearchPathFile` --- compiler/rustc_metadata/src/locator.rs | 23 +++++++++++----------- compiler/rustc_session/src/search_paths.rs | 17 ++++++++++++---- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 004d73da8cbd..af44ae3cc4fd 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -438,7 +438,8 @@ fn find_library_crate( } if let Some(matches) = spf.query(prefix, suffix) { for (hash, spf) in matches { - info!("lib candidate: {}", spf.path.display()); + let spf_path = spf.path(); + info!("lib candidate: {}", spf_path.display()); let (rlibs, rmetas, dylibs, interfaces) = candidates.entry(hash).or_default(); @@ -447,8 +448,8 @@ fn find_library_crate( // ones we've already seen. This allows us to ignore crates // we know are exactual equal to ones we've already found. // Going to the same crate through different symlinks does not change the result. - let path = try_canonicalize(&spf.path) - .unwrap_or_else(|_| spf.path.to_path_buf()); + let path = + try_canonicalize(&spf_path).unwrap_or_else(|_| spf_path.clone()); if seen_paths.contains(&path) { continue; }; @@ -456,12 +457,11 @@ fn find_library_crate( } // Use the original path (potentially with unresolved symlinks), // filesystem code should not care, but this is nicer for diagnostics. - let path = spf.path.to_path_buf(); match kind { - CrateFlavor::Rlib => rlibs.insert(path), - CrateFlavor::Rmeta => rmetas.insert(path), - CrateFlavor::Dylib => dylibs.insert(path), - CrateFlavor::SDylib => interfaces.insert(path), + CrateFlavor::Rlib => rlibs.insert(spf_path), + CrateFlavor::Rmeta => rmetas.insert(spf_path), + CrateFlavor::Dylib => dylibs.insert(spf_path), + CrateFlavor::SDylib => interfaces.insert(spf_path), }; } } @@ -471,10 +471,9 @@ fn find_library_crate( .flatten() { for (_, spf) in static_matches { - crate_rejections.via_kind.push(CrateMismatch { - path: spf.path.to_path_buf(), - got: "static".to_string(), - }); + crate_rejections + .via_kind + .push(CrateMismatch { path: spf.path(), got: "static".to_string() }); } } } diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index 5cc5ee3d9745..e92f355a9e4d 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -61,8 +61,16 @@ pub fn retain(&mut self, prefixes: &[&str]) { /// UTF-8, and so a non-UTF-8 filename couldn't be one we're looking for.) #[derive(Clone, Debug)] pub struct SearchPathFile { - pub path: Arc, - pub file_name_str: Arc, + // We store the directory in a shared Arc, as many files can share the same directory. + dir: Arc, + file_name_str: Arc, +} + +impl SearchPathFile { + /// Constructs the full path to the file. + pub fn path(&self) -> PathBuf { + self.dir.join(&*self.file_name_str) + } } #[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable, HashStable_Generic)] @@ -129,6 +137,7 @@ pub fn from_sysroot_and_triple(sysroot: &Path, triple: &str) -> Self { } pub fn new(kind: PathKind, dir: PathBuf) -> Self { + let dir_file: Arc = dir.clone().into(); // Get the files within the directory. let mut files = match std::fs::read_dir(&dir) { Ok(files) => files @@ -136,11 +145,11 @@ pub fn new(kind: PathKind, dir: PathBuf) -> Self { e.ok().and_then(|e| { e.file_name().to_str().map(|s| { let file_name_str: Arc = s.into(); - SearchPathFile { path: e.path().into(), file_name_str } + SearchPathFile { dir: dir_file.clone(), file_name_str } }) }) }) - .collect::>(), + .collect::>(), Err(..) => Default::default(), }; From f45028939bf939c13e735409e76ebb0961ef61d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 26 Feb 2026 13:35:03 +0100 Subject: [PATCH 4/4] Do not store directory at all in `SearchPathFile` --- compiler/rustc_metadata/src/locator.rs | 9 +++++---- compiler/rustc_session/src/search_paths.rs | 12 +++--------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index af44ae3cc4fd..5af60e9f19da 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -438,7 +438,7 @@ fn find_library_crate( } if let Some(matches) = spf.query(prefix, suffix) { for (hash, spf) in matches { - let spf_path = spf.path(); + let spf_path = spf.path(&search_path.dir); info!("lib candidate: {}", spf_path.display()); let (rlibs, rmetas, dylibs, interfaces) = @@ -471,9 +471,10 @@ fn find_library_crate( .flatten() { for (_, spf) in static_matches { - crate_rejections - .via_kind - .push(CrateMismatch { path: spf.path(), got: "static".to_string() }); + crate_rejections.via_kind.push(CrateMismatch { + path: spf.path(&search_path.dir), + got: "static".to_string(), + }); } } } diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index e92f355a9e4d..c9c7b8a4d782 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -61,15 +61,13 @@ pub fn retain(&mut self, prefixes: &[&str]) { /// UTF-8, and so a non-UTF-8 filename couldn't be one we're looking for.) #[derive(Clone, Debug)] pub struct SearchPathFile { - // We store the directory in a shared Arc, as many files can share the same directory. - dir: Arc, file_name_str: Arc, } impl SearchPathFile { /// Constructs the full path to the file. - pub fn path(&self) -> PathBuf { - self.dir.join(&*self.file_name_str) + pub fn path(&self, dir: &Path) -> PathBuf { + dir.join(&*self.file_name_str) } } @@ -137,16 +135,12 @@ pub fn from_sysroot_and_triple(sysroot: &Path, triple: &str) -> Self { } pub fn new(kind: PathKind, dir: PathBuf) -> Self { - let dir_file: Arc = dir.clone().into(); // Get the files within the directory. let mut files = match std::fs::read_dir(&dir) { Ok(files) => files .filter_map(|e| { e.ok().and_then(|e| { - e.file_name().to_str().map(|s| { - let file_name_str: Arc = s.into(); - SearchPathFile { dir: dir_file.clone(), file_name_str } - }) + e.file_name().to_str().map(|s| SearchPathFile { file_name_str: s.into() }) }) }) .collect::>(),