Skip to content

Commit 0784c72

Browse files
authored
Rollup merge of #142377 - Urgau:unremap-rustc-dev, r=jieyouxu
Try unremapping compiler sources See [#t-compiler/help > Span pointing to wrong file location (`rustc-dev` component)](https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/Span.20pointing.20to.20wrong.20file.20location.20.28.60rustc-dev.60.20component.29/with/521087083). This PR is a follow-up to #141751 regarding the compiler side. Specifically we now take into account the `CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR` env from #141751 when trying to unremap sources from `$sysroot/lib/rustlib/rustc-src/rust` (the `rustc-dev` component install directory). Best reviewed commit by commit. cc `@samueltardieu` r? `@jieyouxu`
2 parents ed4537b + 2341c7d commit 0784c72

File tree

8 files changed

+219
-82
lines changed

8 files changed

+219
-82
lines changed

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 123 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Decoding metadata from a single crate's metadata
22

33
use std::iter::TrustedLen;
4-
use std::path::Path;
4+
use std::path::{Path, PathBuf};
55
use std::sync::{Arc, OnceLock};
66
use std::{io, iter, mem};
77

@@ -1610,10 +1610,14 @@ impl<'a> CrateMetadataRef<'a> {
16101610
/// Proc macro crates don't currently export spans, so this function does not have
16111611
/// to work for them.
16121612
fn imported_source_file(self, source_file_index: u32, sess: &Session) -> ImportedSourceFile {
1613-
fn filter<'a>(sess: &Session, path: Option<&'a Path>) -> Option<&'a Path> {
1613+
fn filter<'a>(
1614+
sess: &Session,
1615+
real_source_base_dir: &Option<PathBuf>,
1616+
path: Option<&'a Path>,
1617+
) -> Option<&'a Path> {
16141618
path.filter(|_| {
16151619
// Only spend time on further checks if we have what to translate *to*.
1616-
sess.opts.real_rust_source_base_dir.is_some()
1620+
real_source_base_dir.is_some()
16171621
// Some tests need the translation to be always skipped.
16181622
&& sess.opts.unstable_opts.translate_remapped_path_to_local_path
16191623
})
@@ -1625,57 +1629,92 @@ impl<'a> CrateMetadataRef<'a> {
16251629
})
16261630
}
16271631

1628-
let try_to_translate_virtual_to_real = |name: &mut rustc_span::FileName| {
1629-
// Translate the virtual `/rustc/$hash` prefix back to a real directory
1630-
// that should hold actual sources, where possible.
1631-
//
1632-
// NOTE: if you update this, you might need to also update bootstrap's code for generating
1633-
// the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`.
1634-
let virtual_rust_source_base_dir = [
1635-
filter(sess, option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(Path::new)),
1636-
filter(sess, sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref()),
1637-
];
1632+
let try_to_translate_virtual_to_real =
1633+
|virtual_source_base_dir: Option<&str>,
1634+
real_source_base_dir: &Option<PathBuf>,
1635+
name: &mut rustc_span::FileName| {
1636+
let virtual_source_base_dir = [
1637+
filter(sess, real_source_base_dir, virtual_source_base_dir.map(Path::new)),
1638+
filter(
1639+
sess,
1640+
real_source_base_dir,
1641+
sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref(),
1642+
),
1643+
];
16381644

1639-
debug!(
1640-
"try_to_translate_virtual_to_real(name={:?}): \
1641-
virtual_rust_source_base_dir={:?}, real_rust_source_base_dir={:?}",
1642-
name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir,
1643-
);
1645+
debug!(
1646+
"try_to_translate_virtual_to_real(name={:?}): \
1647+
virtual_source_base_dir={:?}, real_source_base_dir={:?}",
1648+
name, virtual_source_base_dir, real_source_base_dir,
1649+
);
16441650

1645-
for virtual_dir in virtual_rust_source_base_dir.iter().flatten() {
1646-
if let Some(real_dir) = &sess.opts.real_rust_source_base_dir
1651+
for virtual_dir in virtual_source_base_dir.iter().flatten() {
1652+
if let Some(real_dir) = &real_source_base_dir
1653+
&& let rustc_span::FileName::Real(old_name) = name
1654+
&& let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
1655+
old_name
1656+
&& let Ok(rest) = virtual_name.strip_prefix(virtual_dir)
1657+
{
1658+
let new_path = real_dir.join(rest);
1659+
1660+
debug!(
1661+
"try_to_translate_virtual_to_real: `{}` -> `{}`",
1662+
virtual_name.display(),
1663+
new_path.display(),
1664+
);
1665+
1666+
// Check if the translated real path is affected by any user-requested
1667+
// remaps via --remap-path-prefix. Apply them if so.
1668+
// Note that this is a special case for imported rust-src paths specified by
1669+
// https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths.
1670+
// Other imported paths are not currently remapped (see #66251).
1671+
let (user_remapped, applied) =
1672+
sess.source_map().path_mapping().map_prefix(&new_path);
1673+
let new_name = if applied {
1674+
rustc_span::RealFileName::Remapped {
1675+
local_path: Some(new_path.clone()),
1676+
virtual_name: user_remapped.to_path_buf(),
1677+
}
1678+
} else {
1679+
rustc_span::RealFileName::LocalPath(new_path)
1680+
};
1681+
*old_name = new_name;
1682+
}
1683+
}
1684+
};
1685+
1686+
let try_to_translate_real_to_virtual =
1687+
|virtual_source_base_dir: Option<&str>,
1688+
real_source_base_dir: &Option<PathBuf>,
1689+
subdir: &str,
1690+
name: &mut rustc_span::FileName| {
1691+
if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base
1692+
&& let Some(real_dir) = real_source_base_dir
16471693
&& let rustc_span::FileName::Real(old_name) = name
1648-
&& let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
1649-
old_name
1650-
&& let Ok(rest) = virtual_name.strip_prefix(virtual_dir)
16511694
{
1652-
let new_path = real_dir.join(rest);
1653-
1654-
debug!(
1655-
"try_to_translate_virtual_to_real: `{}` -> `{}`",
1656-
virtual_name.display(),
1657-
new_path.display(),
1658-
);
1659-
1660-
// Check if the translated real path is affected by any user-requested
1661-
// remaps via --remap-path-prefix. Apply them if so.
1662-
// Note that this is a special case for imported rust-src paths specified by
1663-
// https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths.
1664-
// Other imported paths are not currently remapped (see #66251).
1665-
let (user_remapped, applied) =
1666-
sess.source_map().path_mapping().map_prefix(&new_path);
1667-
let new_name = if applied {
1668-
rustc_span::RealFileName::Remapped {
1669-
local_path: Some(new_path.clone()),
1670-
virtual_name: user_remapped.to_path_buf(),
1695+
let relative_path = match old_name {
1696+
rustc_span::RealFileName::LocalPath(local) => {
1697+
local.strip_prefix(real_dir).ok()
1698+
}
1699+
rustc_span::RealFileName::Remapped { virtual_name, .. } => {
1700+
virtual_source_base_dir
1701+
.and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok())
16711702
}
1672-
} else {
1673-
rustc_span::RealFileName::LocalPath(new_path)
16741703
};
1675-
*old_name = new_name;
1704+
debug!(
1705+
?relative_path,
1706+
?virtual_dir,
1707+
?subdir,
1708+
"simulate_remapped_rust_src_base"
1709+
);
1710+
if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok()) {
1711+
*old_name = rustc_span::RealFileName::Remapped {
1712+
local_path: None,
1713+
virtual_name: virtual_dir.join(subdir).join(rest),
1714+
};
1715+
}
16761716
}
1677-
}
1678-
};
1717+
};
16791718

16801719
let mut import_info = self.cdata.source_map_import_info.lock();
16811720
for _ in import_info.len()..=(source_file_index as usize) {
@@ -1713,36 +1752,45 @@ impl<'a> CrateMetadataRef<'a> {
17131752
// This is useful for testing so that tests about the effects of
17141753
// `try_to_translate_virtual_to_real` don't have to worry about how the
17151754
// compiler is bootstrapped.
1716-
if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base
1717-
&& let Some(real_dir) = &sess.opts.real_rust_source_base_dir
1718-
&& let rustc_span::FileName::Real(ref mut old_name) = name
1719-
{
1720-
let relative_path = match old_name {
1721-
rustc_span::RealFileName::LocalPath(local) => {
1722-
local.strip_prefix(real_dir).ok()
1723-
}
1724-
rustc_span::RealFileName::Remapped { virtual_name, .. } => {
1725-
option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR")
1726-
.and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok())
1727-
}
1728-
};
1729-
debug!(?relative_path, ?virtual_dir, "simulate_remapped_rust_src_base");
1730-
for subdir in ["library", "compiler"] {
1731-
if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok())
1732-
{
1733-
*old_name = rustc_span::RealFileName::Remapped {
1734-
local_path: None, // FIXME: maybe we should preserve this?
1735-
virtual_name: virtual_dir.join(subdir).join(rest),
1736-
};
1737-
break;
1738-
}
1739-
}
1740-
}
1755+
try_to_translate_real_to_virtual(
1756+
option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR"),
1757+
&sess.opts.real_rust_source_base_dir,
1758+
"library",
1759+
&mut name,
1760+
);
1761+
1762+
// If this file is under $sysroot/lib/rustlib/rustc-src/
1763+
// and the user wish to simulate remapping with -Z simulate-remapped-rust-src-base,
1764+
// then we change `name` to a similar state as if the rust was bootstrapped
1765+
// with `remap-debuginfo = true`.
1766+
try_to_translate_real_to_virtual(
1767+
option_env!("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR"),
1768+
&sess.opts.real_rustc_dev_source_base_dir,
1769+
"compiler",
1770+
&mut name,
1771+
);
17411772

17421773
// If this file's path has been remapped to `/rustc/$hash`,
1743-
// we might be able to reverse that (also see comments above,
1744-
// on `try_to_translate_virtual_to_real`).
1745-
try_to_translate_virtual_to_real(&mut name);
1774+
// we might be able to reverse that.
1775+
//
1776+
// NOTE: if you update this, you might need to also update bootstrap's code for generating
1777+
// the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`.
1778+
try_to_translate_virtual_to_real(
1779+
option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR"),
1780+
&sess.opts.real_rust_source_base_dir,
1781+
&mut name,
1782+
);
1783+
1784+
// If this file's path has been remapped to `/rustc-dev/$hash`,
1785+
// we might be able to reverse that.
1786+
//
1787+
// NOTE: if you update this, you might need to also update bootstrap's code for generating
1788+
// the `rustc-dev` component in `Src::run` in `src/bootstrap/dist.rs`.
1789+
try_to_translate_virtual_to_real(
1790+
option_env!("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR"),
1791+
&sess.opts.real_rustc_dev_source_base_dir,
1792+
&mut name,
1793+
);
17461794

17471795
let local_version = sess.source_map().new_imported_source_file(
17481796
name,

compiler/rustc_session/src/config.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,7 @@ impl Default for Options {
13641364
cli_forced_local_thinlto_off: false,
13651365
remap_path_prefix: Vec::new(),
13661366
real_rust_source_base_dir: None,
1367+
real_rustc_dev_source_base_dir: None,
13671368
edition: DEFAULT_EDITION,
13681369
json_artifact_notifications: false,
13691370
json_unused_externs: JsonUnusedExterns::No,
@@ -2701,9 +2702,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
27012702

27022703
let sysroot = filesearch::materialize_sysroot(sysroot_opt);
27032704

2704-
let real_rust_source_base_dir = {
2705-
// This is the location used by the `rust-src` `rustup` component.
2706-
let mut candidate = sysroot.join("lib/rustlib/src/rust");
2705+
let real_source_base_dir = |suffix: &str, confirm: &str| {
2706+
let mut candidate = sysroot.join(suffix);
27072707
if let Ok(metadata) = candidate.symlink_metadata() {
27082708
// Replace the symlink bootstrap creates, with its destination.
27092709
// We could try to use `fs::canonicalize` instead, but that might
@@ -2716,9 +2716,17 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
27162716
}
27172717

27182718
// Only use this directory if it has a file we can expect to always find.
2719-
candidate.join("library/std/src/lib.rs").is_file().then_some(candidate)
2719+
candidate.join(confirm).is_file().then_some(candidate)
27202720
};
27212721

2722+
let real_rust_source_base_dir =
2723+
// This is the location used by the `rust-src` `rustup` component.
2724+
real_source_base_dir("lib/rustlib/src/rust", "library/std/src/lib.rs");
2725+
2726+
let real_rustc_dev_source_base_dir =
2727+
// This is the location used by the `rustc-dev` `rustup` component.
2728+
real_source_base_dir("lib/rustlib/rustc-src/rust", "compiler/rustc/src/main.rs");
2729+
27222730
let mut search_paths = vec![];
27232731
for s in &matches.opt_strs("L") {
27242732
search_paths.push(SearchPath::from_cli_opt(
@@ -2772,6 +2780,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
27722780
cli_forced_local_thinlto_off: disable_local_thinlto,
27732781
remap_path_prefix,
27742782
real_rust_source_base_dir,
2783+
real_rustc_dev_source_base_dir,
27752784
edition,
27762785
json_artifact_notifications,
27772786
json_unused_externs,

compiler/rustc_session/src/options.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,15 +395,25 @@ top_level_options!(
395395

396396
/// Remap source path prefixes in all output (messages, object files, debug, etc.).
397397
remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH],
398-
/// Base directory containing the `src/` for the Rust standard library, and
399-
/// potentially `rustc` as well, if we can find it. Right now it's always
400-
/// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component).
398+
399+
/// Base directory containing the `library/` directory for the Rust standard library.
400+
/// Right now it's always `$sysroot/lib/rustlib/src/rust`
401+
/// (i.e. the `rustup` `rust-src` component).
401402
///
402403
/// This directory is what the virtual `/rustc/$hash` is translated back to,
403404
/// if Rust was built with path remapping to `/rustc/$hash` enabled
404405
/// (the `rust.remap-debuginfo` option in `bootstrap.toml`).
405406
real_rust_source_base_dir: Option<PathBuf> [TRACKED_NO_CRATE_HASH],
406407

408+
/// Base directory containing the `compiler/` directory for the rustc sources.
409+
/// Right now it's always `$sysroot/lib/rustlib/rustc-src/rust`
410+
/// (i.e. the `rustup` `rustc-dev` component).
411+
///
412+
/// This directory is what the virtual `/rustc-dev/$hash` is translated back to,
413+
/// if Rust was built with path remapping to `/rustc/$hash` enabled
414+
/// (the `rust.remap-debuginfo` option in `bootstrap.toml`).
415+
real_rustc_dev_source_base_dir: Option<PathBuf> [TRACKED_NO_CRATE_HASH],
416+
407417
edition: Edition [TRACKED],
408418

409419
/// `true` if we're emitting JSON blobs about each artifact produced

src/doc/rustc-dev-guide/src/tests/ui.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ Compiletest makes the following replacements on the compiler output:
113113
- The base directory where the test's output goes is replaced with
114114
`$TEST_BUILD_DIR`. This only comes up in a few rare circumstances. Example:
115115
`/path/to/rust/build/x86_64-unknown-linux-gnu/test/ui`
116+
- The real directory to the standard library source is replaced with `$SRC_DIR_REAL`.
117+
- The real directory to the compiler source is replaced with `$COMPILER_DIR_REAL`.
116118
- Tabs are replaced with `\t`.
117119
- Backslashes (`\`) are converted to forward slashes (`/`) within paths (using a
118120
heuristic). This helps normalize differences with Windows-style paths.

src/tools/compiletest/src/runtest.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,6 +2371,12 @@ impl<'test> TestCx<'test> {
23712371
let rust_src_dir = rust_src_dir.read_link_utf8().unwrap_or(rust_src_dir.to_path_buf());
23722372
normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL");
23732373

2374+
// Real paths into the compiler
2375+
let rustc_src_dir = &self.config.sysroot_base.join("lib/rustlib/rustc-src/rust");
2376+
rustc_src_dir.try_exists().expect(&*format!("{} should exists", rustc_src_dir));
2377+
let rustc_src_dir = rustc_src_dir.read_link_utf8().unwrap_or(rustc_src_dir.to_path_buf());
2378+
normalize_path(&rustc_src_dir.join("compiler"), "$COMPILER_DIR_REAL");
2379+
23742380
// eg.
23752381
// /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui/<test_dir>/$name.$revision.$mode/
23762382
normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR");
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisfied
2+
--> $DIR/rustc-dev-remap.rs:LL:COL
3+
|
4+
LL | type Result = NotAValidResultType;
5+
| ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType`
6+
|
7+
= help: the following other types implement trait `VisitorResult`:
8+
()
9+
ControlFlow<T>
10+
note: required by a bound in `rustc_ast::visit::Visitor::Result`
11+
--> /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL
12+
13+
error: aborting due to 1 previous error
14+
15+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisfied
2+
--> $DIR/rustc-dev-remap.rs:LL:COL
3+
|
4+
LL | type Result = NotAValidResultType;
5+
| ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType`
6+
|
7+
= help: the following other types implement trait `VisitorResult`:
8+
()
9+
ControlFlow<T>
10+
note: required by a bound in `rustc_ast::visit::Visitor::Result`
11+
--> $COMPILER_DIR_REAL/rustc_ast/src/visit.rs:LL:COL
12+
|
13+
LL | type Result: VisitorResult = ();
14+
| ^^^^^^^^^^^^^ required by this bound in `Visitor::Result`
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0277`.

tests/ui-fulldeps/rustc-dev-remap.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ check-fail
2+
//
3+
//@ ignore-cross-compile
4+
//@ ignore-remote
5+
//
6+
//@ revisions: only-remap remap-unremap
7+
//@ compile-flags: -Z simulate-remapped-rust-src-base=/rustc-dev/xyz
8+
//@ [remap-unremap]compile-flags: -Ztranslate-remapped-path-to-local-path=yes
9+
10+
// The $SRC_DIR*.rs:LL:COL normalisation doesn't kick in automatically
11+
// as the remapped revision will begin with $COMPILER_DIR_REAL,
12+
// so we have to do it ourselves.
13+
//@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:COL"
14+
15+
#![feature(rustc_private)]
16+
17+
extern crate rustc_ast;
18+
19+
use rustc_ast::visit::Visitor;
20+
21+
struct MyStruct;
22+
struct NotAValidResultType;
23+
24+
impl Visitor<'_> for MyStruct {
25+
type Result = NotAValidResultType;
26+
//~^ ERROR the trait bound `NotAValidResultType: VisitorResult` is not satisfied
27+
}
28+
29+
fn main() {}

0 commit comments

Comments
 (0)