diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index f15b76fa85c95..bb974e4645ea6 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -168,8 +168,11 @@ fn main() { } } - if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { - cmd.arg("--remap-path-prefix").arg(&map); + // The remap flags for the compiler and standard library sources. + if let Ok(maps) = env::var("RUSTC_DEBUGINFO_MAP") { + for map in maps.split('\t') { + cmd.arg("--remap-path-prefix").arg(map); + } } // The remap flags for Cargo registry sources need to be passed after the remapping for the // Rust source code directory, to handle cases when $CARGO_HOME is inside the source directory. diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7ca6ae46a8f89..a58739c9e65cb 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2257,6 +2257,10 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--with-std-debug-assertions"); } + if builder.config.rust_remap_debuginfo { + cmd.arg("--with-std-remap-debuginfo"); + } + let mut llvm_components_passed = false; let mut copts_passed = false; if builder.config.llvm_enabled(test_compiler.host) { diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 4697de7ffe0de..b0a8ce77efe78 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -1025,15 +1025,26 @@ impl Builder<'_> { if let Some(ref map_to) = self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler) { + // Tell the compiler which prefix was used for remapping the standard library cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to); } if let Some(ref map_to) = self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::Compiler) { - // When building compiler sources, we want to apply the compiler remap scheme. - cargo.env("RUSTC_DEBUGINFO_MAP", format!("compiler/={map_to}/compiler")); + // Tell the compiler which prefix was used for remapping the compiler it-self cargo.env("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR", map_to); + + // When building compiler sources, we want to apply the compiler remap scheme. + let map = [ + // Cargo use relative paths for workspace members, so let's remap those. + format!("compiler/={map_to}/compiler"), + // rustc creates absolute paths (in part bc of the `rust-src` unremap + // and for working directory) so let's remap the build directory as well. + format!("{}={map_to}", self.build.src.display()), + ] + .join("\t"); + cargo.env("RUSTC_DEBUGINFO_MAP", map); } } Mode::Std @@ -1044,7 +1055,16 @@ impl Builder<'_> { if let Some(ref map_to) = self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler) { - cargo.env("RUSTC_DEBUGINFO_MAP", format!("library/={map_to}/library")); + // When building the standard library sources, we want to apply the std remap scheme. + let map = [ + // Cargo use relative paths for workspace members, so let's remap those. + format!("library/={map_to}/library"), + // rustc creates absolute paths (in part bc of the `rust-src` unremap + // and for working directory) so let's remap the build directory as well. + format!("{}={map_to}", self.build.src.display()), + ] + .join("\t"); + cargo.env("RUSTC_DEBUGINFO_MAP", map); } } } diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 7cf5869b719cc..c8b0072dc1010 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -189,6 +189,10 @@ settings: assertions. - `needs-std-debug-assertions` — ignores if std was not built with debug assertions. +- `ignore-std-remap-debuginfo` — ignores if std was built with remapping of + it's sources. +- `needs-std-remap-debugino` — ignores if std was not built with remapping of + it's sources. - `ignore-rustc-debug-assertions` — ignores if rustc was built with debug assertions. - `needs-rustc-debug-assertions` — ignores if rustc was not built with debug diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index cd0e79f5ab3fa..9473e51688cbb 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -438,6 +438,11 @@ pub struct Config { /// FIXME: make it clearer that this refers to the staged `std`, not stage 0 `std`. pub with_std_debug_assertions: bool, + /// Whether *staged* `std` was built with remapping of debuginfo. + /// + /// FIXME: make it clearer that this refers to the staged `std`, not stage 0 `std`. + pub with_std_remap_debuginfo: bool, + /// Only run tests that match these filters (using `libtest` "test name contains" filter logic). /// /// FIXME(#139660): the current hand-rolled test executor intentionally mimics the `libtest` diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 62d10f14b98f2..e89c1330f4670 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -202,6 +202,11 @@ pub(crate) fn prepare_conditions(config: &Config) -> PreparedConditions { config.with_std_debug_assertions, "when std is built with debug assertions", ); + builder.cond( + "std-remap-debuginfo", + config.with_std_remap_debuginfo, + "when std is built with remapping of debuginfo", + ); for &debugger in Debugger::STR_VARIANTS { builder.cond( diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index e9824edfef601..282e2a131d932 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -184,6 +184,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-sanitizer-support", "needs-sanitizer-thread", "needs-std-debug-assertions", + "needs-std-remap-debuginfo", "needs-subprocess", "needs-symlink", "needs-target-has-atomic", diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index 92b596c70ae91..36c2ca62cd87a 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -181,6 +181,11 @@ pub(super) fn handle_needs( condition: config.with_std_debug_assertions, ignore_reason: "ignored if std wasn't built with debug assertions", }, + Need { + name: "needs-std-remap-debuginfo", + condition: config.with_std_remap_debuginfo, + ignore_reason: "ignored if std wasn't built with remapping of debuginfo", + }, Need { name: "needs-target-std", condition: build_helper::targets::target_supports_std(&config.target), diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 90e2cb77e304c..93f1041a8f416 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -117,6 +117,7 @@ struct ConfigBuilder { profiler_runtime: bool, rustc_debug_assertions: bool, std_debug_assertions: bool, + std_remap_debuginfo: bool, } impl ConfigBuilder { @@ -185,6 +186,11 @@ impl ConfigBuilder { self } + fn std_remap_debuginfo(&mut self, is_enabled: bool) -> &mut Self { + self.std_remap_debuginfo = is_enabled; + self + } + fn build(&mut self) -> Config { let args = &[ "compiletest", @@ -246,6 +252,9 @@ impl ConfigBuilder { if self.std_debug_assertions { args.push("--with-std-debug-assertions".to_owned()); } + if self.std_remap_debuginfo { + args.push("--with-std-remap-debuginfo".to_owned()); + } args.push("--rustc-path".to_string()); args.push(std::env::var("TEST_RUSTC").expect("must be configured by bootstrap")); @@ -400,6 +409,19 @@ fn std_debug_assertions() { assert!(check_ignore(&config, "//@ ignore-std-debug-assertions")); } +#[test] +fn std_remap_debuginfo() { + let config: Config = cfg().std_remap_debuginfo(false).build(); + + assert!(check_ignore(&config, "//@ needs-std-remap-debuginfo")); + assert!(!check_ignore(&config, "//@ ignore-std-remap-debuginfo")); + + let config: Config = cfg().std_remap_debuginfo(true).build(); + + assert!(!check_ignore(&config, "//@ needs-std-remap-debuginfo")); + assert!(check_ignore(&config, "//@ ignore-std-remap-debuginfo")); +} + #[test] fn stage() { let config: Config = cfg().stage(1).stage_id("stage1-x86_64-unknown-linux-gnu").build(); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 90b1c10308a27..83aee865e0102 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -106,6 +106,7 @@ fn parse_config(args: Vec) -> Config { .optflag("", "has-enzyme", "run tests that require enzyme") .optflag("", "with-rustc-debug-assertions", "whether rustc was built with debug assertions") .optflag("", "with-std-debug-assertions", "whether std was built with debug assertions") + .optflag("", "with-std-remap-debuginfo", "whether std was built with remapping") .optmulti( "", "skip", @@ -295,6 +296,7 @@ fn parse_config(args: Vec) -> Config { let run_ignored = matches.opt_present("ignored"); let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions"); let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions"); + let with_std_remap_debuginfo = matches.opt_present("with-std-remap-debuginfo"); let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); let has_enzyme = matches.opt_present("has-enzyme"); let filters = if mode == TestMode::RunMake { @@ -402,6 +404,7 @@ fn parse_config(args: Vec) -> Config { run_ignored, with_rustc_debug_assertions, with_std_debug_assertions, + with_std_remap_debuginfo, filters, skip: matches.opt_strs("skip"), filter_exact: matches.opt_present("exact"), diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 68574eb4bfd69..ba3a123473671 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -243,6 +243,12 @@ impl TestCx<'_> { cmd.env("__STD_DEBUG_ASSERTIONS_ENABLED", "1"); } + cmd.env_remove("__STD_REMAP_DEBUGINFO_ENABLED"); + if self.config.with_std_remap_debuginfo { + // Used for `run_make_support::env::std_remap_debuginfo_enabled`. + cmd.env("__STD_REMAP_DEBUGINFO_ENABLED", "1"); + } + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index c30f3d1e10ea8..2b057bb35519a 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -83,6 +83,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { run_ignored: Default::default(), with_rustc_debug_assertions: Default::default(), with_std_debug_assertions: Default::default(), + with_std_remap_debuginfo: Default::default(), filters: Default::default(), skip: Default::default(), filter_exact: Default::default(), diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs index cf1a6f7351a7f..507d51471df01 100644 --- a/src/tools/run-make-support/src/env.rs +++ b/src/tools/run-make-support/src/env.rs @@ -34,6 +34,14 @@ pub fn std_debug_assertions_enabled() -> bool { std::env::var_os("__STD_DEBUG_ASSERTIONS_ENABLED").is_some() } +/// Check if staged `std`-under-test was built with remapping of it's sources. +#[track_caller] +#[must_use] +pub fn std_remap_debuginfo_enabled() -> bool { + // Note: we assume this env var is set when the test recipe is being executed. + std::env::var_os("__STD_REMAP_DEBUGINFO_ENABLED").is_some() +} + /// A wrapper around [`std::env::set_current_dir`] which includes the directory /// path in the panic message. #[track_caller] diff --git a/tests/run-make/remap-path-prefix-std/rmake.rs b/tests/run-make/remap-path-prefix-std/rmake.rs new file mode 100644 index 0000000000000..f5179038a9b11 --- /dev/null +++ b/tests/run-make/remap-path-prefix-std/rmake.rs @@ -0,0 +1,53 @@ +// This test makes sure that we do not leak paths to the checkout +// (ie. /checkout in CI) in the distributed `libstd` debuginfo. +// +// This test only runs on Linux and dist builder (or with `rust.remap-debuginfo = true` +// set in your `bootstrap.toml`). + +//@ needs-std-remap-debuginfo +//@ only-linux + +use std::path::PathBuf; + +use run_make_support::{llvm_dwarfdump, rfs, rustc, shallow_find_files, source_root}; + +fn main() { + // Find the target libdir for the current target + let target_libdir = { + let output = rustc().print("target-libdir").run(); + let stdout = output.stdout_utf8(); + let path = PathBuf::from(stdout.trim()); + + // Assert that the target-libdir path exists + assert!(path.exists(), "target-libdir: {path:?} does not exists"); + + path + }; + + // Find all the `libstd-.*.rlib` files under the libdir + let libstd_rlibs = shallow_find_files(&target_libdir, |p| { + if let Some(filename) = p.file_name() + && let filename = filename.to_string_lossy() + { + filename.starts_with("libstd-") && filename.ends_with(".rlib") + } else { + false + } + }); + + // Assert that there is only one rlib for the `libstd` + let [libstd_rlib] = &libstd_rlibs[..] else { + unreachable!("multiple libstd rlib: {libstd_rlibs:?} in {target_libdir:?}"); + }; + + // Symlink the libstd rlib here to avoid absolute paths from llvm-dwarfdump own output + // and not from the debuginfo it-self + rfs::symlink_file(libstd_rlib, "libstd.rlib"); + + // Check that there is only `/rustc/` paths and no `/checkout`, `/home`, or whatever + llvm_dwarfdump() + .input("libstd.rlib") + .run() + .assert_stdout_contains("/rustc/") + .assert_stdout_not_contains(source_root().to_string_lossy()); +}