From 6a7996e30325e28215b318feb7cc56bcff0e2bb5 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 19 Apr 2025 11:52:18 +0200 Subject: [PATCH] Take into-account `-Zremap-path-scope` when embedding filenames --- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 - compiler/rustc_session/src/config.rs | 8 +- compiler/rustc_span/src/lib.rs | 34 +++----- compiler/rustc_span/src/source_map.rs | 80 ++++++++++--------- compiler/rustc_span/src/source_map/tests.rs | 73 +++++++++++++++++ .../run-make/remap-path-prefix-dwarf/rmake.rs | 53 ++++++++++++ .../src/print_value.rs | 7 ++ .../remap-path-prefix-dwarf/src/some_value.rs | 6 ++ tests/run-make/remap-path-prefix/rmake.rs | 6 +- 9 files changed, 205 insertions(+), 64 deletions(-) create mode 100644 tests/run-make/remap-path-prefix-dwarf/src/print_value.rs create mode 100644 tests/run-make/remap-path-prefix-dwarf/src/some_value.rs diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3ea61d1b40a60..e4cf58fccda2e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -551,8 +551,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match source_file.name { FileName::Real(ref original_file_name) => { - // FIXME: This should probably to conditionally remapped under - // a RemapPathScopeComponents but which one? let adapted_file_name = source_map .path_mapping() .to_embeddable_absolute_path(original_file_name.clone(), working_directory); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e2d36f6a4e2ff..ccb1e95096044 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -24,7 +24,8 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; use rustc_span::{ - FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm, Symbol, sym, + FileName, FileNameDisplayPreference, FileNameEmbeddablePreference, RealFileName, + SourceFileHashAlgorithm, Symbol, sym, }; use rustc_target::spec::{ FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple, @@ -1316,6 +1317,11 @@ fn file_path_mapping( } else { FileNameDisplayPreference::Local }, + if unstable_opts.remap_path_scope.is_all() { + FileNameEmbeddablePreference::RemappedOnly + } else { + FileNameEmbeddablePreference::LocalAndRemapped + }, ) } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9722031f209b5..6fcf77e31a22e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -224,7 +224,7 @@ pub fn with_metavar_spans(f: impl FnOnce(&MetavarSpansMap) -> R) -> R { // FIXME: We should use this enum or something like it to get rid of the // use of magic `/rust/1.x/...` paths across the board. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable)] +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable, Encodable)] pub enum RealFileName { LocalPath(PathBuf), /// For remapped paths (namely paths into libstd that have been mapped @@ -250,28 +250,6 @@ impl Hash for RealFileName { } } -// This is functionally identical to #[derive(Encodable)], with the exception of -// an added assert statement -impl Encodable for RealFileName { - fn encode(&self, encoder: &mut S) { - match *self { - RealFileName::LocalPath(ref local_path) => { - encoder.emit_u8(0); - local_path.encode(encoder); - } - - RealFileName::Remapped { ref local_path, ref virtual_name } => { - encoder.emit_u8(1); - // For privacy and build reproducibility, we must not embed host-dependant path - // in artifacts if they have been remapped by --remap-path-prefix - assert!(local_path.is_none()); - local_path.encode(encoder); - virtual_name.encode(encoder); - } - } - } -} - impl RealFileName { /// Returns the path suitable for reading from the file system on the local host, /// if this information exists. @@ -368,6 +346,16 @@ impl From for FileName { } } +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +pub enum FileNameEmbeddablePreference { + /// If a remapped path is available, only embed the `virtual_path` and omit the `local_path`. + /// + /// Otherwise embed the local-path into the `virtual_path`. + RemappedOnly, + /// Embed the original path as well as its remapped `virtual_path` component if available. + LocalAndRemapped, +} + #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] pub enum FileNameDisplayPreference { /// Display the path after the application of rewrite rules provided via `--remap-path-prefix`. diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 0273bb040f433..8a3644163caf3 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -1108,18 +1108,28 @@ pub fn get_source_map() -> Option> { pub struct FilePathMapping { mapping: Vec<(PathBuf, PathBuf)>, filename_display_for_diagnostics: FileNameDisplayPreference, + filename_embeddable_preference: FileNameEmbeddablePreference, } impl FilePathMapping { pub fn empty() -> FilePathMapping { - FilePathMapping::new(Vec::new(), FileNameDisplayPreference::Local) + FilePathMapping::new( + Vec::new(), + FileNameDisplayPreference::Local, + FileNameEmbeddablePreference::RemappedOnly, + ) } pub fn new( mapping: Vec<(PathBuf, PathBuf)>, filename_display_for_diagnostics: FileNameDisplayPreference, + filename_embeddable_preference: FileNameEmbeddablePreference, ) -> FilePathMapping { - FilePathMapping { mapping, filename_display_for_diagnostics } + FilePathMapping { + mapping, + filename_display_for_diagnostics, + filename_embeddable_preference, + } } /// Applies any path prefix substitution as defined by the mapping. @@ -1217,11 +1227,13 @@ impl FilePathMapping { ) -> RealFileName { match file_path { // Anything that's already remapped we don't modify, except for erasing - // the `local_path` portion. - RealFileName::Remapped { local_path: _, virtual_name } => { + // the `local_path` portion (if desired). + RealFileName::Remapped { local_path, virtual_name } => { RealFileName::Remapped { - // We do not want any local path to be exported into metadata - local_path: None, + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => local_path, + }, // We use the remapped name verbatim, even if it looks like a relative // path. The assumption is that the user doesn't want us to further // process paths that have gone through remapping. @@ -1231,12 +1243,18 @@ impl FilePathMapping { RealFileName::LocalPath(unmapped_file_path) => { // If no remapping has been applied yet, try to do so - let (new_path, was_remapped) = self.map_prefix(unmapped_file_path); + let (new_path, was_remapped) = self.map_prefix(&unmapped_file_path); if was_remapped { // It was remapped, so don't modify further return RealFileName::Remapped { - local_path: None, virtual_name: new_path.into_owned(), + // But still provide the local path if desired + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => { + Some(unmapped_file_path) + } + }, }; } @@ -1252,17 +1270,23 @@ impl FilePathMapping { match working_directory { RealFileName::LocalPath(unmapped_working_dir_abs) => { - let file_path_abs = unmapped_working_dir_abs.join(unmapped_file_path_rel); + let unmapped_file_path_abs = + unmapped_working_dir_abs.join(unmapped_file_path_rel); // Although neither `working_directory` nor the file name were subject // to path remapping, the concatenation between the two may be. Hence // we need to do a remapping here. - let (file_path_abs, was_remapped) = self.map_prefix(file_path_abs); + let (file_path_abs, was_remapped) = + self.map_prefix(&unmapped_file_path_abs); if was_remapped { RealFileName::Remapped { - // Erase the actual path - local_path: None, virtual_name: file_path_abs.into_owned(), + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => { + Some(unmapped_file_path_abs) + } + }, } } else { // No kind of remapping applied to this path, so @@ -1271,15 +1295,20 @@ impl FilePathMapping { } } RealFileName::Remapped { - local_path: _, + local_path, virtual_name: remapped_working_dir_abs, } => { // If working_directory has been remapped, then we emit // Remapped variant as the expanded path won't be valid RealFileName::Remapped { - local_path: None, virtual_name: Path::new(remapped_working_dir_abs) - .join(unmapped_file_path_rel), + .join(&unmapped_file_path_rel), + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => local_path + .as_ref() + .map(|local_path| local_path.join(unmapped_file_path_rel)), + }, } } } @@ -1287,27 +1316,6 @@ impl FilePathMapping { } } - /// Expand a relative path to an absolute path **without** remapping taken into account. - /// - /// The resulting `RealFileName` will have its `virtual_path` portion erased if - /// possible (i.e. if there's also a remapped path). - pub fn to_local_embeddable_absolute_path( - &self, - file_path: RealFileName, - working_directory: &RealFileName, - ) -> RealFileName { - let file_path = file_path.local_path_if_available(); - if file_path.is_absolute() { - // No remapping has applied to this path and it is absolute, - // so the working directory cannot influence it either, so - // we are done. - return RealFileName::LocalPath(file_path.to_path_buf()); - } - debug_assert!(file_path.is_relative()); - let working_directory = working_directory.local_path_if_available(); - RealFileName::LocalPath(Path::new(working_directory).join(file_path)) - } - /// Attempts to (heuristically) reverse a prefix mapping. /// /// Returns [`Some`] if there is exactly one mapping where the "to" part is diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 957f55e39138e..589c2a3635481 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -305,6 +305,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("abc/def"), path("foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("foo/src/main.rs")); @@ -316,6 +317,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("abc/def"), path("/foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("/foo/src/main.rs")); @@ -327,6 +329,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("/abc/def"), path("foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("foo/src/main.rs")); @@ -338,6 +341,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("/abc/def"), path("/foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("/foo/src/main.rs")); @@ -351,6 +355,7 @@ fn path_prefix_remapping_expand_to_absolute() { let mapping = &FilePathMapping::new( vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); let working_directory = path("/foo"); let working_directory = RealFileName::Remapped { @@ -448,6 +453,71 @@ fn path_prefix_remapping_expand_to_absolute() { ); } +#[test] +fn path_prefix_remapping_expand_to_absolute_and_local() { + // "virtual" working directory is relative path + let mapping = &FilePathMapping::new( + vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))], + FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::LocalAndRemapped, + ); + let working_directory = path("/foo"); + let working_directory = RealFileName::Remapped { + local_path: Some(working_directory.clone()), + virtual_name: mapping.map_prefix(working_directory).0.into_owned(), + }; + + assert_eq!(working_directory.remapped_path_if_available(), path("FOO")); + + // Unmapped absolute path + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::LocalPath(path("/foo/src/main.rs")), + &working_directory + ), + RealFileName::Remapped { + local_path: Some(path("/foo/src/main.rs")), + virtual_name: path("FOO/src/main.rs") + } + ); + + // Unmapped absolute path with unrelated working directory + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::LocalPath(path("/bar/src/main.rs")), + &working_directory + ), + RealFileName::Remapped { + local_path: Some(path("/bar/src/main.rs")), + virtual_name: path("BAR/src/main.rs") + } + ); + + // Already remapped absolute path, with unrelated working directory + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::Remapped { + local_path: Some(path("/bar/src/main.rs")), + virtual_name: path("BAR/src/main.rs"), + }, + &working_directory + ), + RealFileName::Remapped { + local_path: Some(path("/bar/src/main.rs")), + virtual_name: path("BAR/src/main.rs") + } + ); + + // Already remapped relative path + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }, + &working_directory + ), + RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") } + ); +} + #[test] fn path_prefix_remapping_reverse() { // Ignores options without alphanumeric chars. @@ -455,6 +525,7 @@ fn path_prefix_remapping_reverse() { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/")), (path("def"), path("."))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None); @@ -466,6 +537,7 @@ fn path_prefix_remapping_reverse() { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/redacted")), (path("def"), path("/redacted"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None); @@ -476,6 +548,7 @@ fn path_prefix_remapping_reverse() { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/redacted")), (path("def/ghi"), path("/fake/dir"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!( diff --git a/tests/run-make/remap-path-prefix-dwarf/rmake.rs b/tests/run-make/remap-path-prefix-dwarf/rmake.rs index ede1d61574257..3d6ca014fc2a5 100644 --- a/tests/run-make/remap-path-prefix-dwarf/rmake.rs +++ b/tests/run-make/remap-path-prefix-dwarf/rmake.rs @@ -91,6 +91,59 @@ fn main() { )), dwarf_test: DwarfDump::ParentTest, }); + + check_dwarf_deps("macro", DwarfDump::AvoidSrcPath); + check_dwarf_deps("diagnostics", DwarfDump::AvoidSrcPath); + check_dwarf_deps("macro,diagnostics", DwarfDump::AvoidSrcPath); + check_dwarf_deps("object", DwarfDump::ContainsSrcPath); +} + +#[track_caller] +fn check_dwarf_deps(scope: &str, dwarf_test: DwarfDump) { + // build some_value.rs + let mut rustc_sm = rustc(); + rustc_sm.input(cwd().join("src/some_value.rs")); + rustc_sm.arg("-Cdebuginfo=2"); + rustc_sm.arg(format!("-Zremap-path-scope={}", scope)); + rustc_sm.arg("--remap-path-prefix"); + rustc_sm.arg(format!("{}=/REMAPPED", cwd().display())); + rustc_sm.arg("-Csplit-debuginfo=off"); + rustc_sm.run(); + + // build print_value.rs + let print_value_rlib = rust_lib_name(&format!("print_value.{scope}")); + let mut rustc_pv = rustc(); + rustc_pv.input(cwd().join("src/print_value.rs")); + rustc_pv.output(&print_value_rlib); + rustc_pv.arg("-Cdebuginfo=2"); + rustc_pv.arg(format!("-Zremap-path-scope={}", scope)); + rustc_pv.arg("--remap-path-prefix"); + rustc_pv.arg(format!("{}=/REMAPPED", cwd().display())); + rustc_pv.arg("-Csplit-debuginfo=off"); + rustc_pv.run(); + + match dwarf_test { + DwarfDump::AvoidSrcPath => { + llvm_dwarfdump() + .input(print_value_rlib) + .run() + .assert_stdout_not_contains("REMAPPED/src/some_value.rs") + .assert_stdout_not_contains("REMAPPED/src/print_value.rs") + .assert_stdout_not_contains("REMAPPED/REMAPPED") + .assert_stdout_contains(cwd().join("src/some_value.rs").display().to_string()) + .assert_stdout_contains(cwd().join("src/print_value.rs").display().to_string()); + } + DwarfDump::ContainsSrcPath => { + llvm_dwarfdump() + .input(print_value_rlib) + .run() + .assert_stdout_contains("REMAPPED/src/some_value.rs") + .assert_stdout_contains("REMAPPED/src/print_value.rs") + .assert_stdout_not_contains(cwd().join("src/some_value.rs").display().to_string()) + .assert_stdout_not_contains(cwd().join("src/print_value.rs").display().to_string()); + } + _ => unreachable!(), + } } #[track_caller] diff --git a/tests/run-make/remap-path-prefix-dwarf/src/print_value.rs b/tests/run-make/remap-path-prefix-dwarf/src/print_value.rs new file mode 100644 index 0000000000000..f7653025ba5a8 --- /dev/null +++ b/tests/run-make/remap-path-prefix-dwarf/src/print_value.rs @@ -0,0 +1,7 @@ +#![crate_type = "rlib"] + +extern crate some_value; + +pub fn print_value() { + println!("{}", some_value::get_some_value()); +} diff --git a/tests/run-make/remap-path-prefix-dwarf/src/some_value.rs b/tests/run-make/remap-path-prefix-dwarf/src/some_value.rs new file mode 100644 index 0000000000000..aa95a1bdf73ba --- /dev/null +++ b/tests/run-make/remap-path-prefix-dwarf/src/some_value.rs @@ -0,0 +1,6 @@ +#![crate_type = "rlib"] + +#[inline] +pub fn get_some_value() -> i32 { + 42 +} diff --git a/tests/run-make/remap-path-prefix/rmake.rs b/tests/run-make/remap-path-prefix/rmake.rs index aeb30e72d5bf4..b4f7f4769b5ba 100644 --- a/tests/run-make/remap-path-prefix/rmake.rs +++ b/tests/run-make/remap-path-prefix/rmake.rs @@ -47,10 +47,10 @@ fn main() { out_object.run(); rmeta_contains("/the/aux/lib.rs"); - rmeta_not_contains("auxiliary"); + rmeta_contains("auxiliary"); out_macro.run(); rmeta_contains("/the/aux/lib.rs"); - rmeta_not_contains("auxiliary"); + rmeta_contains("auxiliary"); out_diagobj.run(); rmeta_contains("/the/aux/lib.rs"); rmeta_not_contains("auxiliary"); @@ -58,6 +58,7 @@ fn main() { //FIXME(Oneirical): These could be generalized into run_make_support // helper functions. +#[track_caller] fn rmeta_contains(expected: &str) { // Normalize to account for path differences in Windows. if !bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) { @@ -69,6 +70,7 @@ fn rmeta_contains(expected: &str) { } } +#[track_caller] fn rmeta_not_contains(expected: &str) { // Normalize to account for path differences in Windows. if bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) {