Skip to content

Commit c53e4b3

Browse files
committed
Auto merge of #70642 - eddyb:remap-sysroot-src, r=Mark-Simulacrum
Translate the virtual `/rustc/$hash` prefix back to a real directory. Closes #53486 and fixes #53081, by undoing the remapping to `/rustc/$hash` on the fly, when appropriate (e.g. our testsuites, or user crates that depend on `libstd`), but not during the Rust build itself (as that could leak the absolute build directory into the artifacts, breaking deterministic builds). Tested locally by setting `remap-debuginfo = true` in `config.toml`, which without these changes, was causing 56 tests to fail (see #53081 (comment) for more details). cc @Mark-Simulacrum @alexcrichton @ehuss
2 parents c520802 + 8deff18 commit c53e4b3

File tree

170 files changed

+350
-603
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

170 files changed

+350
-603
lines changed

src/bootstrap/builder.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1022,8 +1022,13 @@ impl<'a> Builder<'a> {
10221022
cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
10231023
}
10241024

1025-
if let Some(map) = self.build.debuginfo_map(GitRepo::Rustc) {
1025+
if let Some(map_to) = self.build.debuginfo_map_to(GitRepo::Rustc) {
1026+
let map = format!("{}={}", self.build.src.display(), map_to);
10261027
cargo.env("RUSTC_DEBUGINFO_MAP", map);
1028+
1029+
// `rustc` needs to know the virtual `/rustc/$hash` we're mapping to,
1030+
// in order to opportunistically reverse it later.
1031+
cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to);
10271032
}
10281033

10291034
// Enable usage of unstable features

src/bootstrap/compile.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use serde::Deserialize;
2222
use crate::builder::Cargo;
2323
use crate::dist;
2424
use crate::native;
25-
use crate::util::{exe, is_dylib};
25+
use crate::util::{exe, is_dylib, symlink_dir};
2626
use crate::{Compiler, GitRepo, Mode};
2727

2828
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
@@ -633,6 +633,30 @@ impl Step for Sysroot {
633633
};
634634
let _ = fs::remove_dir_all(&sysroot);
635635
t!(fs::create_dir_all(&sysroot));
636+
637+
// Symlink the source root into the same location inside the sysroot,
638+
// where `rust-src` component would go (`$sysroot/lib/rustlib/src/rust`),
639+
// so that any tools relying on `rust-src` also work for local builds,
640+
// and also for translating the virtual `/rustc/$hash` back to the real
641+
// directory (for running tests with `rust.remap-debuginfo = true`).
642+
let sysroot_lib_rustlib_src = sysroot.join("lib/rustlib/src");
643+
t!(fs::create_dir_all(&sysroot_lib_rustlib_src));
644+
let sysroot_lib_rustlib_src_rust = sysroot_lib_rustlib_src.join("rust");
645+
if let Err(e) = symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_src_rust) {
646+
eprintln!(
647+
"warning: creating symbolic link `{}` to `{}` failed with {}",
648+
sysroot_lib_rustlib_src_rust.display(),
649+
builder.src.display(),
650+
e,
651+
);
652+
if builder.config.rust_remap_debuginfo {
653+
eprintln!(
654+
"warning: some `src/test/ui` tests will fail when lacking `{}`",
655+
sysroot_lib_rustlib_src_rust.display(),
656+
);
657+
}
658+
}
659+
636660
INTERNER.intern_path(sysroot)
637661
}
638662
}

src/bootstrap/lib.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -740,19 +740,18 @@ impl Build {
740740
self.config.jobs.unwrap_or_else(|| num_cpus::get() as u32)
741741
}
742742

743-
fn debuginfo_map(&self, which: GitRepo) -> Option<String> {
743+
fn debuginfo_map_to(&self, which: GitRepo) -> Option<String> {
744744
if !self.config.rust_remap_debuginfo {
745745
return None;
746746
}
747747

748-
let path = match which {
748+
match which {
749749
GitRepo::Rustc => {
750750
let sha = self.rust_sha().unwrap_or(channel::CFG_RELEASE_NUM);
751-
format!("/rustc/{}", sha)
751+
Some(format!("/rustc/{}", sha))
752752
}
753-
GitRepo::Llvm => String::from("/rustc/llvm"),
754-
};
755-
Some(format!("{}={}", self.src.display(), path))
753+
GitRepo::Llvm => Some(String::from("/rustc/llvm")),
754+
}
756755
}
757756

758757
/// Returns the path to the C compiler for the target specified.
@@ -787,7 +786,8 @@ impl Build {
787786
base.push("-fno-omit-frame-pointer".into());
788787
}
789788

790-
if let Some(map) = self.debuginfo_map(which) {
789+
if let Some(map_to) = self.debuginfo_map_to(which) {
790+
let map = format!("{}={}", self.src.display(), map_to);
791791
let cc = self.cc(target);
792792
if cc.ends_with("clang") || cc.ends_with("gcc") {
793793
base.push(format!("-fdebug-prefix-map={}", map));

src/etc/generate-deriving-span-tests.py

-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
os.path.join(os.path.dirname(__file__), '../test/ui/derives/'))
1616

1717
TEMPLATE = """\
18-
// FIXME: missing sysroot spans (#53081)
19-
// ignore-i586-unknown-linux-gnu
20-
// ignore-i586-unknown-linux-musl
2118
// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py'
2219
2320
{error_deriving}

src/librustc_metadata/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
fn main() {
22
println!("cargo:rerun-if-changed=build.rs");
33
println!("cargo:rerun-if-env-changed=CFG_VERSION");
4+
println!("cargo:rerun-if-env-changed=CFG_VIRTUAL_RUST_SOURCE_BASE_DIR");
45
}

src/librustc_metadata/rmeta/decoder.rs

+52-9
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
3232
use rustc_middle::util::common::record_time;
3333
use rustc_serialize::{opaque, Decodable, Decoder, SpecializedDecoder};
3434
use rustc_session::Session;
35-
use rustc_span::source_map::{self, respan, Spanned};
35+
use rustc_span::source_map::{respan, Spanned};
3636
use rustc_span::symbol::{sym, Symbol};
3737
use rustc_span::{self, hygiene::MacroKind, BytePos, Pos, Span, DUMMY_SP};
3838

@@ -41,6 +41,7 @@ use proc_macro::bridge::client::ProcMacro;
4141
use std::io;
4242
use std::mem;
4343
use std::num::NonZeroUsize;
44+
use std::path::Path;
4445
use std::u32;
4546

4647
pub use cstore_impl::{provide, provide_extern};
@@ -427,7 +428,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
427428
// we can call `imported_source_files` for the proper crate, and binary search
428429
// through the returned slice using our span.
429430
let imported_source_files = if tag == TAG_VALID_SPAN_LOCAL {
430-
self.cdata().imported_source_files(sess.source_map())
431+
self.cdata().imported_source_files(sess)
431432
} else {
432433
// FIXME: We don't decode dependencies of proc-macros.
433434
// Remove this once #69976 is merged
@@ -457,7 +458,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
457458
self.last_source_file_index = 0;
458459

459460
let foreign_data = self.cdata().cstore.get_crate_data(cnum);
460-
foreign_data.imported_source_files(sess.source_map())
461+
foreign_data.imported_source_files(sess)
461462
};
462463

463464
let source_file = {
@@ -1460,10 +1461,45 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
14601461
///
14611462
/// Proc macro crates don't currently export spans, so this function does not have
14621463
/// to work for them.
1463-
fn imported_source_files(
1464-
&self,
1465-
local_source_map: &source_map::SourceMap,
1466-
) -> &'a [ImportedSourceFile] {
1464+
fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
1465+
// Translate the virtual `/rustc/$hash` prefix back to a real directory
1466+
// that should hold actual sources, where possible.
1467+
let virtual_rust_source_base_dir = option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR")
1468+
.map(Path::new)
1469+
.filter(|_| {
1470+
// Only spend time on further checks if we have what to translate *to*.
1471+
sess.real_rust_source_base_dir.is_some()
1472+
})
1473+
.filter(|virtual_dir| {
1474+
// Don't translate away `/rustc/$hash` if we're still remapping to it,
1475+
// since that means we're still building `std`/`rustc` that need it,
1476+
// and we don't want the real path to leak into codegen/debuginfo.
1477+
!sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir)
1478+
});
1479+
let try_to_translate_virtual_to_real = |name: &mut rustc_span::FileName| {
1480+
debug!(
1481+
"try_to_translate_virtual_to_real(name={:?}): \
1482+
virtual_rust_source_base_dir={:?}, real_rust_source_base_dir={:?}",
1483+
name, virtual_rust_source_base_dir, sess.real_rust_source_base_dir,
1484+
);
1485+
1486+
if let Some(virtual_dir) = virtual_rust_source_base_dir {
1487+
if let Some(real_dir) = &sess.real_rust_source_base_dir {
1488+
if let rustc_span::FileName::Real(path) = name {
1489+
if let Ok(rest) = path.strip_prefix(virtual_dir) {
1490+
let new_path = real_dir.join(rest);
1491+
debug!(
1492+
"try_to_translate_virtual_to_real: `{}` -> `{}`",
1493+
path.display(),
1494+
new_path.display(),
1495+
);
1496+
*path = new_path;
1497+
}
1498+
}
1499+
}
1500+
}
1501+
};
1502+
14671503
self.cdata.source_map_import_info.init_locking(|| {
14681504
let external_source_map = self.root.source_map.decode(self);
14691505

@@ -1472,7 +1508,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
14721508
// We can't reuse an existing SourceFile, so allocate a new one
14731509
// containing the information we need.
14741510
let rustc_span::SourceFile {
1475-
name,
1511+
mut name,
14761512
name_was_remapped,
14771513
src_hash,
14781514
start_pos,
@@ -1485,6 +1521,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
14851521
..
14861522
} = source_file_to_import;
14871523

1524+
// If this file's path has been remapped to `/rustc/$hash`,
1525+
// we might be able to reverse that (also see comments above,
1526+
// on `try_to_translate_virtual_to_real`).
1527+
// FIXME(eddyb) we could check `name_was_remapped` here,
1528+
// but in practice it seems to be always `false`.
1529+
try_to_translate_virtual_to_real(&mut name);
1530+
14881531
let source_length = (end_pos - start_pos).to_usize();
14891532

14901533
// Translate line-start positions and multibyte character
@@ -1505,7 +1548,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
15051548
np.pos = np.pos - start_pos;
15061549
}
15071550

1508-
let local_version = local_source_map.new_imported_source_file(
1551+
let local_version = sess.source_map().new_imported_source_file(
15091552
name,
15101553
name_was_remapped,
15111554
src_hash,

src/librustc_session/session.rs

+30
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,15 @@ pub struct Session {
140140
/// Options range from returning the error without a backtrace to returning an error
141141
/// and immediately printing the backtrace to stderr.
142142
pub ctfe_backtrace: Lock<CtfeBacktrace>,
143+
144+
/// Base directory containing the `src/` for the Rust standard library, and
145+
/// potentially `rustc` as well, if we can can find it. Right now it's always
146+
/// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component).
147+
///
148+
/// This directory is what the virtual `/rustc/$hash` is translated back to,
149+
/// if Rust was built with path remapping to `/rustc/$hash` enabled
150+
/// (the `rust.remap-debuginfo` option in `config.toml`).
151+
pub real_rust_source_base_dir: Option<PathBuf>,
143152
}
144153

145154
pub struct PerfStats {
@@ -1056,6 +1065,26 @@ fn build_session_(
10561065
_ => CtfeBacktrace::Disabled,
10571066
});
10581067

1068+
// Try to find a directory containing the Rust `src`, for more details see
1069+
// the doc comment on the `real_rust_source_base_dir` field.
1070+
let real_rust_source_base_dir = {
1071+
// This is the location used by the `rust-src` `rustup` component.
1072+
let mut candidate = sysroot.join("lib/rustlib/src/rust");
1073+
if let Ok(metadata) = candidate.symlink_metadata() {
1074+
// Replace the symlink rustbuild creates, with its destination.
1075+
// We could try to use `fs::canonicalize` instead, but that might
1076+
// produce unnecessarily verbose path.
1077+
if metadata.file_type().is_symlink() {
1078+
if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
1079+
candidate = symlink_dest;
1080+
}
1081+
}
1082+
}
1083+
1084+
// Only use this directory if it has a file we can expect to always find.
1085+
if candidate.join("src/libstd/lib.rs").is_file() { Some(candidate) } else { None }
1086+
};
1087+
10591088
let sess = Session {
10601089
target: target_cfg,
10611090
host,
@@ -1094,6 +1123,7 @@ fn build_session_(
10941123
confused_type_with_std_module: Lock::new(Default::default()),
10951124
system_library_path: OneThread::new(RefCell::new(Default::default())),
10961125
ctfe_backtrace,
1126+
real_rust_source_base_dir,
10971127
};
10981128

10991129
validate_commandline_args_with_session_available(&sess);

src/test/ui/async-await/issues/issue-62009-1.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
// edition:2018
2-
// FIXME: missing sysroot spans (#53081)
3-
// ignore-i586-unknown-linux-gnu
4-
// ignore-i586-unknown-linux-musl
5-
// ignore-i686-unknown-linux-musl
62

73
async fn print_dur() {}
84

src/test/ui/async-await/issues/issue-62009-1.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error[E0728]: `await` is only allowed inside `async` functions and blocks
2-
--> $DIR/issue-62009-1.rs:10:5
2+
--> $DIR/issue-62009-1.rs:6:5
33
|
44
LL | fn main() {
55
| ---- this is not `async`
66
LL | async { let (); }.await;
77
| ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
88

99
error[E0728]: `await` is only allowed inside `async` functions and blocks
10-
--> $DIR/issue-62009-1.rs:12:5
10+
--> $DIR/issue-62009-1.rs:8:5
1111
|
1212
LL | fn main() {
1313
| ---- this is not `async`
@@ -19,19 +19,19 @@ LL | | }.await;
1919
| |___________^ only allowed inside `async` functions and blocks
2020

2121
error[E0728]: `await` is only allowed inside `async` functions and blocks
22-
--> $DIR/issue-62009-1.rs:16:5
22+
--> $DIR/issue-62009-1.rs:12:5
2323
|
2424
LL | fn main() {
2525
| ---- this is not `async`
2626
...
2727
LL | (|_| 2333).await;
2828
| ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
2929

30-
error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:16:5: 16:15]: std::future::Future` is not satisfied
31-
--> $DIR/issue-62009-1.rs:16:5
30+
error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]: std::future::Future` is not satisfied
31+
--> $DIR/issue-62009-1.rs:12:5
3232
|
3333
LL | (|_| 2333).await;
34-
| ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:16:5: 16:15]`
34+
| ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
3535
|
3636
::: $SRC_DIR/libcore/future/mod.rs:LL:COL
3737
|

src/test/ui/closures/closure-move-sync.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
// FIXME: missing sysroot spans (#53081)
2-
// ignore-i586-unknown-linux-gnu
3-
// ignore-i586-unknown-linux-musl
4-
// ignore-i686-unknown-linux-musl
51
use std::thread;
62
use std::sync::mpsc::channel;
73

src/test/ui/closures/closure-move-sync.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely
2-
--> $DIR/closure-move-sync.rs:10:13
2+
--> $DIR/closure-move-sync.rs:6:13
33
|
44
LL | let t = thread::spawn(|| {
55
| ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely
@@ -11,10 +11,10 @@ LL | F: Send + 'static,
1111
|
1212
= help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<()>`
1313
= note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Receiver<()>`
14-
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:10:27: 13:6 recv:&std::sync::mpsc::Receiver<()>]`
14+
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6 recv:&std::sync::mpsc::Receiver<()>]`
1515

1616
error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads safely
17-
--> $DIR/closure-move-sync.rs:22:5
17+
--> $DIR/closure-move-sync.rs:18:5
1818
|
1919
LL | thread::spawn(|| tx.send(()).unwrap());
2020
| ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared between threads safely
@@ -26,7 +26,7 @@ LL | F: Send + 'static,
2626
|
2727
= help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>`
2828
= note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<()>`
29-
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:22:19: 22:42 tx:&std::sync::mpsc::Sender<()>]`
29+
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42 tx:&std::sync::mpsc::Sender<()>]`
3030

3131
error: aborting due to 2 previous errors
3232

src/test/ui/consts/const-size_of-cycle.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
// FIXME: missing sysroot spans (#53081)
2-
// ignore-i586-unknown-linux-gnu
3-
// ignore-i586-unknown-linux-musl
4-
// ignore-i686-unknown-linux-musl
51
// error-pattern: cycle detected
62

73
struct Foo {

src/test/ui/consts/const-size_of-cycle.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}#0`
2-
--> $DIR/const-size_of-cycle.rs:8:17
2+
--> $DIR/const-size_of-cycle.rs:4:17
33
|
44
LL | bytes: [u8; std::mem::size_of::<Foo>()]
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
77
note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`...
8-
--> $DIR/const-size_of-cycle.rs:8:17
8+
--> $DIR/const-size_of-cycle.rs:4:17
99
|
1010
LL | bytes: [u8; std::mem::size_of::<Foo>()]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
1212
note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`...
13-
--> $DIR/const-size_of-cycle.rs:8:17
13+
--> $DIR/const-size_of-cycle.rs:4:17
1414
|
1515
LL | bytes: [u8; std::mem::size_of::<Foo>()]
1616
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL | pub fn size_of<T>() -> usize;
2828
= note: ...which requires normalizing `[u8; _]`...
2929
= note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
3030
note: cycle used when processing `Foo`
31-
--> $DIR/const-size_of-cycle.rs:7:1
31+
--> $DIR/const-size_of-cycle.rs:3:1
3232
|
3333
LL | struct Foo {
3434
| ^^^^^^^^^^

0 commit comments

Comments
 (0)