Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions compiler/rustc_session/src/config.rs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for driving the stabilization!

There are outstanding bugs regarding --remap-path-scope.

"There are no outstanding bugs" probably?

Nightly use

Do any known nightly users use this feature? Counting instances of #![feature(FEATURE_NAME)] on GitHub with grep might be informative.

Except for Cargo unstable trim-paths there doesn't appear any committed use on GitHub.

Don't want to block the stabilization. However, this sounds a bit odd that there is no major use cases beyond Cargo and rustc is heading toward stabilization alone. That may imply t-cargo should review again whether --remap-path-scope is useful and cover what they want at least (of course this is on me as I worked on Cargo side of this)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"There are no outstanding bugs" probably?

As far as I know --remap-path-scope has no bugs. We have test for all the scopes, with/without dependency and with mixed scopes between crates.

However, this sounds a bit odd that there is no major use cases beyond Cargo and rustc is heading toward stabilization alone.

It doesn't really surprises me that there are no public use of it. It's quite a pain currently to setup --remap-path-prefix and -Zremap-path-scope in Cargo, as there is currently no support for it, which is what we are trying to solve. I suspect most users are using RUSTFLAGS which I don't think is typically committed.

That may imply t-cargo should review again whether --remap-path-scope is useful

Well, be able to see the not-remapped paths in diagnostics is quite nice thing.

The RFC specifically states that the default should be object for the release profile.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"There are no outstanding bugs" probably?

I meant the "no" is missing in the original PR description.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other thing is that do we want to stabilize all options all at once. I remember that the RFC said we could optionally stabilize some of them. I am not sure whether macros and debuginfo standalone are useful, as well as diagnostics. The most useful thing as you mentioned is probably object and the original behavior all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know that macros or debuginfo would need to be useful on their own to be worth stabilising, we're able to support them relatively straightforwardly and they may be useful in combination with other options.

Original file line number Diff line number Diff line change
Expand Up @@ -1384,6 +1384,28 @@ bitflags::bitflags! {
}
}

pub(crate) fn parse_remap_path_scope(
early_dcx: &EarlyDiagCtxt,
matches: &getopts::Matches,
) -> RemapPathScopeComponents {
if let Some(v) = matches.opt_str("remap-path-scope") {
let mut slot = RemapPathScopeComponents::empty();
for s in v.split(',') {
slot |= match s {
"macro" => RemapPathScopeComponents::MACRO,
"diagnostics" => RemapPathScopeComponents::DIAGNOSTICS,
"debuginfo" => RemapPathScopeComponents::DEBUGINFO,
"object" => RemapPathScopeComponents::OBJECT,
"all" => RemapPathScopeComponents::all(),
_ => early_dcx.early_fatal("argument for `--remap-path-scope` must be a comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `object`, `all`"),
Comment on lines +1395 to +1400
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: hm, all is always an interesting case -- is it possible that we many have more scopes in the future? That all might become all := { new_remap_scope, ..old_all }?

Copy link
Member Author

@Urgau Urgau Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That all might become all := { new_remap_scope, ..old_all }?

I think so, otherwise --remap-path-prefix=old=new alone and --remap-path-prefix=old=new --remap-path-scope=all would be different which imo would be unexpected.

Copy link
Member

@weihanglo weihanglo Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have at least two options here:

  • Don't offer the all option to users. --remap-path-prefix implies all already by default.
  • Offer the all option but say it always includes all possible scopes even the future one.

Either way, we need to be clear that the it is going to remap as many thing as possible, not just equivalent to some subset of options.

Copy link
Member Author

@Urgau Urgau Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the documentation is already clear about what all does:

  • all (default) - an alias for all of the above, also equivalent to supplying only --remap-path-prefix without --remap-path-scope.

It's true that all doesn't offer much currently. However one way I could see it useful would be for override, --remap-path-scope=object --remap-path-scope=all (which is not possible right now but could easily be allowed).

}
}
slot
} else {
RemapPathScopeComponents::all()
}
}

#[derive(Clone, Debug)]
pub struct Sysroot {
pub explicit: Option<PathBuf>,
Expand Down Expand Up @@ -1420,18 +1442,18 @@ pub fn host_tuple() -> &'static str {

fn file_path_mapping(
remap_path_prefix: Vec<(PathBuf, PathBuf)>,
unstable_opts: &UnstableOptions,
remap_path_scope: &RemapPathScopeComponents,
) -> FilePathMapping {
FilePathMapping::new(
remap_path_prefix.clone(),
if unstable_opts.remap_path_scope.contains(RemapPathScopeComponents::DIAGNOSTICS)
if remap_path_scope.contains(RemapPathScopeComponents::DIAGNOSTICS)
&& !remap_path_prefix.is_empty()
{
FileNameDisplayPreference::Remapped
} else {
FileNameDisplayPreference::Local
},
if unstable_opts.remap_path_scope.is_all() {
if remap_path_scope.is_all() {
FileNameEmbeddablePreference::RemappedOnly
} else {
FileNameEmbeddablePreference::LocalAndRemapped
Expand Down Expand Up @@ -1473,6 +1495,7 @@ impl Default for Options {
cli_forced_codegen_units: None,
cli_forced_local_thinlto_off: false,
remap_path_prefix: Vec::new(),
remap_path_scope: RemapPathScopeComponents::all(),
real_rust_source_base_dir: None,
real_rustc_dev_source_base_dir: None,
edition: DEFAULT_EDITION,
Expand All @@ -1499,7 +1522,7 @@ impl Options {
}

pub fn file_path_mapping(&self) -> FilePathMapping {
file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts)
file_path_mapping(self.remap_path_prefix.clone(), &self.remap_path_scope)
}

/// Returns `true` if there will be an output file generated.
Expand Down Expand Up @@ -1940,6 +1963,14 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
"Remap source names in all output (compiler messages and output files)",
"<FROM>=<TO>",
),
opt(
Stable,
Opt,
"",
"remap-path-scope",
"Defines which scopes of paths should be remapped by `--remap-path-prefix`",
"<macro,diagnostics,debuginfo,object,all>",
),
opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "<VAR>=<VALUE>"),
];
options.extend(verbose_only.into_iter().map(|mut opt| {
Expand Down Expand Up @@ -2838,6 +2869,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
let externs = parse_externs(early_dcx, matches, &unstable_opts);

let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts);
let remap_path_scope = parse_remap_path_scope(early_dcx, matches);

let pretty = parse_pretty(early_dcx, &unstable_opts);

Expand Down Expand Up @@ -2901,7 +2933,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
early_dcx.early_fatal(format!("Current directory is invalid: {e}"));
});

let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts);
let file_mapping = file_path_mapping(remap_path_prefix.clone(), &remap_path_scope);
let working_dir = file_mapping.to_real_filename(&working_dir);

let verbose = matches.opt_present("verbose") || unstable_opts.verbose_internals;
Expand Down Expand Up @@ -2938,6 +2970,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
cli_forced_codegen_units: codegen_units,
cli_forced_local_thinlto_off: disable_local_thinlto,
remap_path_prefix,
remap_path_scope,
real_rust_source_base_dir,
real_rustc_dev_source_base_dir,
edition,
Expand Down
28 changes: 2 additions & 26 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,8 @@ top_level_options!(

/// Remap source path prefixes in all output (messages, object files, debug, etc.).
remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH],
/// Defines which scopes of paths should be remapped by `--remap-path-prefix`.
remap_path_scope: RemapPathScopeComponents [TRACKED_NO_CRATE_HASH],

/// Base directory containing the `library/` directory for the Rust standard library.
/// Right now it's always `$sysroot/lib/rustlib/src/rust`
Expand Down Expand Up @@ -869,8 +871,6 @@ mod desc {
pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)";
pub(crate) const parse_proc_macro_execution_strategy: &str =
"one of supported execution strategies (`same-thread`, or `cross-thread`)";
pub(crate) const parse_remap_path_scope: &str =
"comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `object`, `all`";
pub(crate) const parse_inlining_threshold: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number";
pub(crate) const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)";
Expand Down Expand Up @@ -1694,28 +1694,6 @@ pub mod parse {
true
}

pub(crate) fn parse_remap_path_scope(
slot: &mut RemapPathScopeComponents,
v: Option<&str>,
) -> bool {
if let Some(v) = v {
*slot = RemapPathScopeComponents::empty();
for s in v.split(',') {
*slot |= match s {
"macro" => RemapPathScopeComponents::MACRO,
"diagnostics" => RemapPathScopeComponents::DIAGNOSTICS,
"debuginfo" => RemapPathScopeComponents::DEBUGINFO,
"object" => RemapPathScopeComponents::OBJECT,
"all" => RemapPathScopeComponents::all(),
_ => return false,
}
}
true
} else {
false
}
}

pub(crate) fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
match v.and_then(|s| RelocModel::from_str(s).ok()) {
Some(relocation_model) => *slot = Some(relocation_model),
Expand Down Expand Up @@ -2565,8 +2543,6 @@ options! {
"whether ELF relocations can be relaxed"),
remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
"remap paths under the current working directory to this path prefix"),
remap_path_scope: RemapPathScopeComponents = (RemapPathScopeComponents::all(), parse_remap_path_scope, [TRACKED],
"remap path scope (default: all)"),
remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"directory into which to write optimization remarks (if not specified, they will be \
written to standard error output)"),
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ impl Session {
scope.bits().count_ones() == 1,
"one and only one scope should be passed to `Session::filename_display_preference`"
);
if self.opts.unstable_opts.remap_path_scope.contains(scope) {
if self.opts.remap_path_scope.contains(scope) {
FileNameDisplayPreference::Remapped
} else {
FileNameDisplayPreference::Local
Expand Down Expand Up @@ -1534,7 +1534,7 @@ impl RemapFileNameExt for rustc_span::FileName {
scope.bits().count_ones() == 1,
"one and only one scope should be passed to for_scope"
);
if sess.opts.unstable_opts.remap_path_scope.contains(scope) {
if sess.opts.remap_path_scope.contains(scope) {
self.prefer_remapped_unconditionally()
} else {
self.prefer_local()
Expand All @@ -1550,7 +1550,7 @@ impl RemapFileNameExt for rustc_span::RealFileName {
scope.bits().count_ones() == 1,
"one and only one scope should be passed to for_scope"
);
if sess.opts.unstable_opts.remap_path_scope.contains(scope) {
if sess.opts.remap_path_scope.contains(scope) {
self.remapped_path_if_available()
} else {
self.local_path_if_available()
Expand Down
8 changes: 8 additions & 0 deletions src/doc/rustc/src/command-line-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,14 @@ specified multiple times.
Refer to the [Remap source paths](remap-source-paths.md) section of this book for
further details and explanation.

<a id="option-remap-path-scope"></a>
## `--remap-path-scope`: remap source paths in output

Defines which scopes of paths should be remapped by `--remap-path-prefix`.

Refer to the [Remap source paths](remap-source-paths.md) section of this book for
further details and explanation.

<a id="option-json"></a>
## `--json`: configure json messages printed by the compiler

Expand Down
24 changes: 23 additions & 1 deletion src/doc/rustc/src/remap-source-paths.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ output, including compiler diagnostics, debugging information, macro expansions,
This is useful for normalizing build products, for example by removing the current directory
out of the paths emitted into object files.

The remapping is done via the `--remap-path-prefix` option.
The remapping is done via the `--remap-path-prefix` flag and can be customized via the `--remap-path-scope` flag.

## `--remap-path-prefix`

Expand All @@ -25,6 +25,28 @@ rustc --remap-path-prefix "/home/user/project=/redacted"

This example replaces all occurrences of `/home/user/project` in emitted paths with `/redacted`.

## `--remap-path-scope`

Defines which scopes of paths should be remapped by `--remap-path-prefix`.

This flag accepts a comma-separated list of values and may be specified multiple times, in which case the scopes are aggregated together.

The valid scopes are:

- `macro` - apply remappings to the expansion of `std::file!()` macro. This is where paths in embedded panic messages come from
- `diagnostics` - apply remappings to printed compiler diagnostics
- `debuginfo` - apply remappings to debug informations
- `object` - apply remappings to all paths in compiled executables or libraries, but not elsewhere. Currently an alias for `macro,debuginfo`.
- `all` (default) - an alias for all of the above, also equivalent to supplying only `--remap-path-prefix` without `--remap-path-scope`.

The scopes accepted by `--remap-path-scope` are not exhaustive - new scopes may be added in future releases for eventual stabilisation.
### Example

```sh
# With `object` scope only the build outputs will be remapped, the diagnostics won't be remapped.
rustc --remap-path-prefix=$(PWD)=/remapped --remap-path-scope=object main.rs
```

## Caveats and Limitations

### Linkers generated paths
Expand Down
22 changes: 0 additions & 22 deletions src/doc/unstable-book/src/compiler-flags/remap-path-scope.md

This file was deleted.

8 changes: 4 additions & 4 deletions tests/run-make/remap-path-prefix-dwarf/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ fn check_dwarf_deps(scope: &str, dwarf_test: DwarfDump) {
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(format!("--remap-path-scope={}", scope));
rustc_sm.arg("--remap-path-prefix");
rustc_sm.arg(format!("{}=/REMAPPED", cwd().display()));
rustc_sm.arg("-Csplit-debuginfo=off");
Expand All @@ -117,7 +117,7 @@ fn check_dwarf_deps(scope: &str, dwarf_test: DwarfDump) {
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(format!("--remap-path-scope={}", scope));
rustc_pv.arg("--remap-path-prefix");
rustc_pv.arg(format!("{}=/REMAPPED", cwd().display()));
rustc_pv.arg("-Csplit-debuginfo=off");
Expand Down Expand Up @@ -158,8 +158,8 @@ fn check_dwarf(test: DwarfTest) {
rustc.arg("-Cdebuginfo=2");
if let Some(scope) = test.scope {
match scope {
ScopeType::Object => rustc.arg("-Zremap-path-scope=object"),
ScopeType::Diagnostics => rustc.arg("-Zremap-path-scope=diagnostics"),
ScopeType::Object => rustc.arg("--remap-path-scope=object"),
ScopeType::Diagnostics => rustc.arg("--remap-path-scope=diagnostics"),
};
if is_darwin() {
rustc.arg("-Csplit-debuginfo=off");
Expand Down
6 changes: 3 additions & 3 deletions tests/run-make/remap-path-prefix/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ fn main() {
rmeta_contains("/the/aux/lib.rs");
rmeta_not_contains("auxiliary");

out_object.arg("-Zremap-path-scope=object");
out_macro.arg("-Zremap-path-scope=macro");
out_diagobj.arg("-Zremap-path-scope=diagnostics,object");
out_object.arg("--remap-path-scope=object");
out_macro.arg("--remap-path-scope=macro");
out_diagobj.arg("--remap-path-scope=diagnostics,object");
if is_darwin() {
out_object.arg("-Csplit-debuginfo=off");
out_macro.arg("-Csplit-debuginfo=off");
Expand Down
5 changes: 4 additions & 1 deletion tests/run-make/rustc-help/help-v.diff
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@@ -65,10 +65,28 @@
@@ -65,10 +65,31 @@
Set a codegen option
-V, --version Print version info and exit
-v, --verbose Use verbose output
Expand All @@ -20,6 +20,9 @@
+ --remap-path-prefix <FROM>=<TO>
+ Remap source names in all output (compiler messages
+ and output files)
+ --remap-path-scope <macro,diagnostics,debuginfo,object,all>
+ Defines which scopes of paths should be remapped by
+ `--remap-path-prefix`
+ @path Read newline separated options from `path`

Additional help:
Expand Down
3 changes: 3 additions & 0 deletions tests/run-make/rustc-help/help-v.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ Options:
--remap-path-prefix <FROM>=<TO>
Remap source names in all output (compiler messages
and output files)
--remap-path-scope <macro,diagnostics,debuginfo,object,all>
Defines which scopes of paths should be remapped by
`--remap-path-prefix`
@path Read newline separated options from `path`

Additional help:
Expand Down
13 changes: 6 additions & 7 deletions tests/run-make/split-debuginfo/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ enum RemapPathPrefix {
Unspecified,
}

/// `-Zremap-path-scope`. See
/// <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/remap-path-scope.html#remap-path-scope>.
/// `--remap-path-scope`
#[derive(Debug, Clone)]
enum RemapPathScope {
/// Comma-separated list of remap scopes: `macro`, `diagnostics`, `debuginfo`, `object`, `all`.
Expand Down Expand Up @@ -921,7 +920,7 @@ mod shared_linux_other_tests {
.debuginfo(level.cli_value())
.arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value()))
.remap_path_prefix(cwd(), remapped_prefix)
.arg(format!("-Zremap-path-scope={scope}"))
.arg(format!("--remap-path-scope={scope}"))
.run();
let found_files = cwd_filenames();
FileAssertions { expected_files: BTreeSet::from(["foo", "foo.dwp"]) }
Expand Down Expand Up @@ -950,7 +949,7 @@ mod shared_linux_other_tests {
.debuginfo(level.cli_value())
.arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value()))
.remap_path_prefix(cwd(), remapped_prefix)
.arg(format!("-Zremap-path-scope={scope}"))
.arg(format!("--remap-path-scope={scope}"))
.run();
let found_files = cwd_filenames();
FileAssertions { expected_files: BTreeSet::from(["foo", "foo.dwp"]) }
Expand Down Expand Up @@ -1202,7 +1201,7 @@ mod shared_linux_other_tests {
.debuginfo(level.cli_value())
.arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value()))
.remap_path_prefix(cwd(), remapped_prefix)
.arg(format!("-Zremap-path-scope={scope}"))
.arg(format!("--remap-path-scope={scope}"))
.run();

let found_files = cwd_filenames();
Expand Down Expand Up @@ -1242,7 +1241,7 @@ mod shared_linux_other_tests {
.debuginfo(level.cli_value())
.arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value()))
.remap_path_prefix(cwd(), remapped_prefix)
.arg(format!("-Zremap-path-scope={scope}"))
.arg(format!("--remap-path-scope={scope}"))
.run();

let found_files = cwd_filenames();
Expand Down Expand Up @@ -1356,7 +1355,7 @@ fn main() {
// NOTE: these combinations are not exhaustive, because while porting to rmake.rs initially I
// tried to preserve the existing test behavior closely. Notably, no attempt was made to
// exhaustively cover all cases in the 6-fold Cartesian product of `{,-Csplit=debuginfo=...}` x
// `{,-Cdebuginfo=...}` x `{,--remap-path-prefix}` x `{,-Zremap-path-scope=...}` x
// `{,-Cdebuginfo=...}` x `{,--remap-path-prefix}` x `{,--remap-path-scope=...}` x
// `{,-Zsplit-dwarf-kind=...}` x `{,-Clinker-plugin-lto}`. If you really want to, you can
// identify which combination isn't exercised with a 6-layers nested for loop iterating through
// each of the cli flag enum variants.
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/errors/auxiliary/file-debuginfo.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@ compile-flags: --remap-path-prefix={{src-base}}=remapped
//@ compile-flags: -Zremap-path-scope=debuginfo
//@ compile-flags: --remap-path-scope=debuginfo

#[macro_export]
macro_rules! my_file {
Expand Down
Loading
Loading