Auto merge of #83813 - cbeuw:remap-std, r=michaelwoerister
Fix `--remap-path-prefix` not correctly remapping `rust-src` component paths and unify handling of path mapping with virtualized paths This PR fixes #73167 ("Binaries end up containing path to the rust-src component despite `--remap-path-prefix`") by preventing real local filesystem paths from reaching compilation output if the path is supposed to be remapped. `RealFileName::Named` introduced in #72767 is now renamed as `LocalPath`, because this variant wraps a (most likely) valid local filesystem path. `RealFileName::Devirtualized` is renamed as `Remapped` to be used for remapped path from a real path via `--remap-path-prefix` argument, as well as real path inferred from a virtualized (during compiler bootstrapping) `/rustc/...` path. The `local_path` field is now an `Option<PathBuf>`, as it will be set to `None` before serialisation, so it never reaches any build output. Attempting to serialise a non-`None` `local_path` will cause an assertion faliure. When a path is remapped, a `RealFileName::Remapped` variant is created. The original path is preserved in `local_path` field and the remapped path is saved in `virtual_name` field. Previously, the `local_path` is directly modified which goes against its purpose of "suitable for reading from the file system on the local host". `rustc_span::SourceFile`'s fields `unmapped_path` (introduced by #44940) and `name_was_remapped` (introduced by #41508 when `--remap-path-prefix` feature originally added) are removed, as these two pieces of information can be inferred from the `name` field: if it's anything other than a `FileName::Real(_)`, or if it is a `FileName::Real(RealFileName::LocalPath(_))`, then clearly `name_was_remapped` would've been false and `unmapped_path` would've been `None`. If it is a `FileName::Real(RealFileName::Remapped{local_path, virtual_name})`, then `name_was_remapped` would've been true and `unmapped_path` would've been `Some(local_path)`. cc `@eddyb` who implemented `/rustc/...` path devirtualisation
This commit is contained in:
commit
e1ff91f439
48 changed files with 442 additions and 265 deletions
|
@ -15,11 +15,11 @@ pub use crate::*;
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock};
|
||||
use std::cmp;
|
||||
use std::convert::TryFrom;
|
||||
use std::hash::Hash;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::{clone::Clone, cmp};
|
||||
use std::{convert::TryFrom, unreachable};
|
||||
|
||||
use std::fs;
|
||||
use std::io;
|
||||
|
@ -127,30 +127,13 @@ pub struct StableSourceFileId(u128);
|
|||
// StableSourceFileId, perhaps built atop source_file.name_hash.
|
||||
impl StableSourceFileId {
|
||||
pub fn new(source_file: &SourceFile) -> StableSourceFileId {
|
||||
StableSourceFileId::new_from_pieces(
|
||||
&source_file.name,
|
||||
source_file.name_was_remapped,
|
||||
source_file.unmapped_path.as_ref(),
|
||||
)
|
||||
StableSourceFileId::new_from_name(&source_file.name)
|
||||
}
|
||||
|
||||
fn new_from_pieces(
|
||||
name: &FileName,
|
||||
name_was_remapped: bool,
|
||||
unmapped_path: Option<&FileName>,
|
||||
) -> StableSourceFileId {
|
||||
fn new_from_name(name: &FileName) -> StableSourceFileId {
|
||||
let mut hasher = StableHasher::new();
|
||||
|
||||
if let FileName::Real(real_name) = name {
|
||||
// rust-lang/rust#70924: Use the stable (virtualized) name when
|
||||
// available. (We do not want artifacts from transient file system
|
||||
// paths for libstd to leak into our build artifacts.)
|
||||
real_name.stable_name().hash(&mut hasher)
|
||||
} else {
|
||||
name.hash(&mut hasher);
|
||||
}
|
||||
name_was_remapped.hash(&mut hasher);
|
||||
unmapped_path.hash(&mut hasher);
|
||||
name.hash(&mut hasher);
|
||||
|
||||
StableSourceFileId(hasher.finish())
|
||||
}
|
||||
|
@ -283,35 +266,15 @@ impl SourceMap {
|
|||
|
||||
fn try_new_source_file(
|
||||
&self,
|
||||
mut filename: FileName,
|
||||
filename: FileName,
|
||||
src: String,
|
||||
) -> Result<Lrc<SourceFile>, OffsetOverflowError> {
|
||||
// The path is used to determine the directory for loading submodules and
|
||||
// include files, so it must be before remapping.
|
||||
// Note that filename may not be a valid path, eg it may be `<anon>` etc,
|
||||
// but this is okay because the directory determined by `path.pop()` will
|
||||
// be empty, so the working directory will be used.
|
||||
let unmapped_path = filename.clone();
|
||||
let (filename, _) = self.path_mapping.map_filename_prefix(&filename);
|
||||
|
||||
let was_remapped;
|
||||
if let FileName::Real(real_filename) = &mut filename {
|
||||
match real_filename {
|
||||
RealFileName::Named(path_to_be_remapped)
|
||||
| RealFileName::Devirtualized {
|
||||
local_path: path_to_be_remapped,
|
||||
virtual_name: _,
|
||||
} => {
|
||||
let mapped = self.path_mapping.map_prefix(path_to_be_remapped.clone());
|
||||
was_remapped = mapped.1;
|
||||
*path_to_be_remapped = mapped.0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
was_remapped = false;
|
||||
}
|
||||
|
||||
let file_id =
|
||||
StableSourceFileId::new_from_pieces(&filename, was_remapped, Some(&unmapped_path));
|
||||
let file_id = StableSourceFileId::new_from_name(&filename);
|
||||
|
||||
let lrc_sf = match self.source_file_by_stable_id(file_id) {
|
||||
Some(lrc_sf) => lrc_sf,
|
||||
|
@ -320,8 +283,6 @@ impl SourceMap {
|
|||
|
||||
let source_file = Lrc::new(SourceFile::new(
|
||||
filename,
|
||||
was_remapped,
|
||||
unmapped_path,
|
||||
src,
|
||||
Pos::from_usize(start_pos),
|
||||
self.hash_kind,
|
||||
|
@ -345,7 +306,6 @@ impl SourceMap {
|
|||
pub fn new_imported_source_file(
|
||||
&self,
|
||||
filename: FileName,
|
||||
name_was_remapped: bool,
|
||||
src_hash: SourceFileHash,
|
||||
name_hash: u128,
|
||||
source_len: usize,
|
||||
|
@ -382,8 +342,6 @@ impl SourceMap {
|
|||
|
||||
let source_file = Lrc::new(SourceFile {
|
||||
name: filename,
|
||||
name_was_remapped,
|
||||
unmapped_path: None,
|
||||
src: None,
|
||||
src_hash,
|
||||
external_src: Lock::new(ExternalSource::Foreign {
|
||||
|
@ -411,11 +369,6 @@ impl SourceMap {
|
|||
source_file
|
||||
}
|
||||
|
||||
pub fn mk_substr_filename(&self, sp: Span) -> String {
|
||||
let pos = self.lookup_char_pos(sp.lo());
|
||||
format!("<{}:{}:{}>", pos.file.name, pos.line, pos.col.to_usize() + 1)
|
||||
}
|
||||
|
||||
// If there is a doctest offset, applies it to the line.
|
||||
pub fn doctest_offset_line(&self, file: &FileName, orig: usize) -> usize {
|
||||
match file {
|
||||
|
@ -453,7 +406,7 @@ impl SourceMap {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn span_to_string(&self, sp: Span) -> String {
|
||||
fn span_to_string(&self, sp: Span, prefer_local: bool) -> String {
|
||||
if self.files.borrow().source_files.is_empty() && sp.is_dummy() {
|
||||
return "no-location".to_string();
|
||||
}
|
||||
|
@ -462,7 +415,7 @@ impl SourceMap {
|
|||
let hi = self.lookup_char_pos(sp.hi());
|
||||
format!(
|
||||
"{}:{}:{}: {}:{}",
|
||||
lo.file.name,
|
||||
if prefer_local { lo.file.name.prefer_local() } else { lo.file.name.prefer_remapped() },
|
||||
lo.line,
|
||||
lo.col.to_usize() + 1,
|
||||
hi.line,
|
||||
|
@ -470,16 +423,20 @@ impl SourceMap {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn span_to_filename(&self, sp: Span) -> FileName {
|
||||
self.lookup_char_pos(sp.lo()).file.name.clone()
|
||||
/// Format the span location suitable for embedding in build artifacts
|
||||
pub fn span_to_embeddable_string(&self, sp: Span) -> String {
|
||||
self.span_to_string(sp, false)
|
||||
}
|
||||
|
||||
pub fn span_to_unmapped_path(&self, sp: Span) -> FileName {
|
||||
self.lookup_char_pos(sp.lo())
|
||||
.file
|
||||
.unmapped_path
|
||||
.clone()
|
||||
.expect("`SourceMap::span_to_unmapped_path` called for imported `SourceFile`?")
|
||||
/// Format the span location to be printed in diagnostics. Must not be emitted
|
||||
/// to build artifacts as this may leak local file paths. Use span_to_embeddable_string
|
||||
/// for string suitable for embedding.
|
||||
pub fn span_to_diagnostic_string(&self, sp: Span) -> String {
|
||||
self.span_to_string(sp, true)
|
||||
}
|
||||
|
||||
pub fn span_to_filename(&self, sp: Span) -> FileName {
|
||||
self.lookup_char_pos(sp.lo()).file.name.clone()
|
||||
}
|
||||
|
||||
pub fn is_multiline(&self, sp: Span) -> bool {
|
||||
|
@ -1001,7 +958,13 @@ impl SourceMap {
|
|||
}
|
||||
pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
|
||||
source_file.add_external_src(|| match source_file.name {
|
||||
FileName::Real(ref name) => self.file_loader.read_file(name.local_path()).ok(),
|
||||
FileName::Real(ref name) => {
|
||||
if let Some(local_path) = name.local_path() {
|
||||
self.file_loader.read_file(local_path).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
@ -1046,9 +1009,20 @@ impl FilePathMapping {
|
|||
fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
|
||||
match file {
|
||||
FileName::Real(realfile) => {
|
||||
let path = realfile.local_path();
|
||||
let (path, mapped) = self.map_prefix(path.to_path_buf());
|
||||
(FileName::Real(RealFileName::Named(path)), mapped)
|
||||
if let RealFileName::LocalPath(local_path) = realfile {
|
||||
let (mapped_path, mapped) = self.map_prefix(local_path.to_path_buf());
|
||||
let realfile = if mapped {
|
||||
RealFileName::Remapped {
|
||||
local_path: Some(local_path.clone()),
|
||||
virtual_name: mapped_path,
|
||||
}
|
||||
} else {
|
||||
realfile.clone()
|
||||
};
|
||||
(FileName::Real(realfile), mapped)
|
||||
} else {
|
||||
unreachable!("attempted to remap an already remapped filename");
|
||||
}
|
||||
}
|
||||
other => (other.clone(), false),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue