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:
bors 2021-05-12 11:05:56 +00:00
commit e1ff91f439
48 changed files with 442 additions and 265 deletions

View file

@ -61,7 +61,9 @@ pub fn expand_file(
let topmost = cx.expansion_cause().unwrap_or(sp);
let loc = cx.source_map().lookup_char_pos(topmost.lo());
base::MacEager::expr(cx.expr_str(topmost, Symbol::intern(&loc.file.name.to_string())))
base::MacEager::expr(
cx.expr_str(topmost, Symbol::intern(&loc.file.name.prefer_remapped().to_string_lossy())),
)
}
pub fn expand_stringify(

View file

@ -334,7 +334,9 @@ pub(crate) fn get_caller_location(&mut self, span: Span) -> CValue<'tcx> {
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
let const_loc = self.tcx.const_caller_location((
rustc_span::symbol::Symbol::intern(&caller.file.name.to_string()),
rustc_span::symbol::Symbol::intern(
&caller.file.name.prefer_remapped().to_string_lossy(),
),
caller.line as u32,
caller.col_display as u32 + 1,
));

View file

@ -66,7 +66,7 @@ fn line_program_add_file(
) -> FileId {
match &file.name {
FileName::Real(path) => {
let (dir_path, file_name) = split_path_dir_and_file(path.stable_name());
let (dir_path, file_name) = split_path_dir_and_file(path.remapped_path_if_available());
let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
let file_name = osstr_as_utf8_bytes(file_name);
@ -87,7 +87,7 @@ fn line_program_add_file(
filename => {
let dir_id = line_program.default_directory();
let dummy_file_name = LineString::new(
filename.to_string().into_bytes(),
filename.prefer_remapped().to_string().into_bytes(),
line_program.encoding(),
line_strings,
);

View file

@ -64,7 +64,7 @@ pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self {
// FIXME: how to get version when building out of tree?
// Normally this would use option_env!("CFG_VERSION").
let producer = format!("cg_clif (rustc {})", "unknown version");
let comp_dir = tcx.sess.working_dir.0.to_string_lossy().into_owned();
let comp_dir = tcx.sess.working_dir.to_string_lossy(false).into_owned();
let (name, file_info) = match tcx.sess.local_crate_source_file.clone() {
Some(path) => {
let name = path.to_string_lossy().into_owned();

View file

@ -760,12 +760,12 @@ fn hex_encode(data: &[u8]) -> String {
}
pub fn file_metadata(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile {
debug!("file_metadata: file_name: {}", source_file.name);
debug!("file_metadata: file_name: {:?}", source_file.name);
let hash = Some(&source_file.src_hash);
let file_name = Some(source_file.name.to_string());
let file_name = Some(source_file.name.prefer_remapped().to_string());
let directory = if source_file.is_real_file() && !source_file.is_imported() {
Some(cx.sess().working_dir.0.to_string_lossy().to_string())
Some(cx.sess().working_dir.to_string_lossy(false).to_string())
} else {
// If the path comes from an upstream crate we assume it has been made
// independent of the compiler's working directory one way or another.
@ -993,7 +993,7 @@ pub fn compile_unit_metadata(
let producer = format!("clang LLVM ({})", rustc_producer);
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
let work_dir = tcx.sess.working_dir.0.to_string_lossy();
let work_dir = tcx.sess.working_dir.to_string_lossy(false);
let flags = "\0";
let out_dir = &tcx.output_filenames(LOCAL_CRATE).out_directory;
let split_name = if tcx.sess.target_can_use_split_dwarf() {

View file

@ -1144,7 +1144,7 @@ fn get_caller_location(
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = tcx.sess.source_map().lookup_char_pos(topmost.lo());
let const_loc = tcx.const_caller_location((
Symbol::intern(&caller.file.name.to_string()),
Symbol::intern(&caller.file.name.prefer_remapped().to_string_lossy()),
caller.line as u32,
caller.col_display as u32 + 1,
));

View file

@ -126,7 +126,8 @@ fn emit_messages_default(
}
// owned: line source, line index, annotations
type Owned = (String, usize, Vec<crate::snippet::Annotation>);
let origin = primary_lo.file.name.to_string();
let filename = primary_lo.file.name.prefer_local();
let origin = filename.to_string_lossy();
let annotated_files: Vec<Owned> = annotated_files
.into_iter()
.flat_map(|annotated_file| {

View file

@ -1324,7 +1324,7 @@ fn emit_message_default(
buffer_msg_line_offset,
&format!(
"{}:{}:{}",
loc.file.name,
loc.file.name.prefer_local(),
sm.doctest_offset_line(&loc.file.name, loc.line),
loc.col.0 + 1,
),
@ -1338,7 +1338,7 @@ fn emit_message_default(
0,
&format!(
"{}:{}:{}: ",
loc.file.name,
loc.file.name.prefer_local(),
sm.doctest_offset_line(&loc.file.name, loc.line),
loc.col.0 + 1,
),
@ -1362,12 +1362,12 @@ fn emit_message_default(
};
format!(
"{}:{}{}",
annotated_file.file.name,
annotated_file.file.name.prefer_local(),
sm.doctest_offset_line(&annotated_file.file.name, first_line.line_index),
col
)
} else {
annotated_file.file.name.to_string()
format!("{}", annotated_file.file.name.prefer_local())
};
buffer.append(buffer_msg_line_offset + 1, &loc, Style::LineAndColumn);
for _ in 0..max_line_num_len {

View file

@ -468,7 +468,7 @@ fn from_span_full(
});
DiagnosticSpan {
file_name: start.file.name.to_string(),
file_name: start.file.name.prefer_local().to_string(),
byte_start: start.file.original_relative_byte_pos(span.lo()).0,
byte_end: start.file.original_relative_byte_pos(span.hi()).0,
line_start: start.line,

View file

@ -1084,13 +1084,18 @@ pub fn resolve_path(
// after macro expansion (that is, they are unhygienic).
if !path.is_absolute() {
let callsite = span.source_callsite();
let mut result = match self.source_map().span_to_unmapped_path(callsite) {
FileName::Real(name) => name.into_local_path(),
let mut result = match self.source_map().span_to_filename(callsite) {
FileName::Real(name) => name
.into_local_path()
.expect("attempting to resolve a file path in an external file"),
FileName::DocTest(path, _) => path,
other => {
return Err(self.struct_span_err(
span,
&format!("cannot resolve relative path in non-file source `{}`", other),
&format!(
"cannot resolve relative path in non-file source `{}`",
other.prefer_local()
),
));
}
};

View file

@ -361,9 +361,11 @@ pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
// FIXME: Avoid visiting the crate as a `Mod` item,
// make crate a first class expansion target instead.
pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
let file_path = match self.cx.source_map().span_to_unmapped_path(krate.span) {
FileName::Real(name) => name.into_local_path(),
other => PathBuf::from(other.to_string()),
let file_path = match self.cx.source_map().span_to_filename(krate.span) {
FileName::Real(name) => name
.into_local_path()
.expect("attempting to resolve a file path in an external file"),
other => PathBuf::from(other.prefer_local().to_string()),
};
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
self.cx.root_path = dir_path.clone();

View file

@ -638,10 +638,11 @@ fn path(&mut self, file: &Self::SourceFile) -> String {
match file.name {
FileName::Real(ref name) => name
.local_path()
.expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
.to_str()
.expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
.to_string(),
_ => file.name.to_string(),
_ => file.name.prefer_local().to_string(),
}
}
fn is_real(&mut self, file: &Self::SourceFile) -> bool {
@ -785,7 +786,7 @@ fn ident_name_compatibility_hack(
if let ExpnKind::Macro { name: macro_name, .. } = orig_span.ctxt().outer_expn_data().kind {
let source_map = rustc.sess.source_map();
let filename = source_map.span_to_filename(orig_span);
if let FileName::Real(RealFileName::Named(path)) = filename {
if let FileName::Real(RealFileName::LocalPath(path)) = filename {
let matches_prefix = |prefix, filename| {
// Check for a path that ends with 'prefix*/src/<filename>'
let mut iter = path.components().rev();
@ -848,7 +849,7 @@ fn ident_name_compatibility_hack(
if macro_name == sym::tuple_from_req && matches_prefix("actix-web", "extract.rs") {
let snippet = source_map.span_to_snippet(orig_span);
if snippet.as_deref() == Ok("$T") {
if let FileName::Real(RealFileName::Named(macro_path)) =
if let FileName::Real(RealFileName::LocalPath(macro_path)) =
source_map.span_to_filename(rustc.def_site)
{
if macro_path.to_string_lossy().contains("pin-project-internal-0.") {

View file

@ -1604,13 +1604,19 @@ enum Mismatch<'a> {
match (&terr, expected == found) {
(TypeError::Sorts(values), extra) => {
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
(true, ty::Opaque(def_id, _)) => format!(
" (opaque type at {})",
self.tcx
(true, ty::Opaque(def_id, _)) => {
let pos = self
.tcx
.sess
.source_map()
.mk_substr_filename(self.tcx.def_span(*def_id)),
),
.lookup_char_pos(self.tcx.def_span(*def_id).lo());
format!(
" (opaque type at <{}:{}:{}>)",
pos.file.name.prefer_local(),
pos.line,
pos.col.to_usize() + 1,
)
}
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
(false, _) => "".to_string(),
};

View file

@ -35,7 +35,6 @@
use rustc_session::search_paths::PathKind;
use rustc_session::Session;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{FileName, RealFileName};
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
use tracing::{info, warn};
@ -531,10 +530,10 @@ fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
check_output(output_paths, check)
}
fn escape_dep_filename(filename: &FileName) -> String {
fn escape_dep_filename(filename: &String) -> String {
// Apparently clang and gcc *only* escape spaces:
// http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
filename.to_string().replace(" ", "\\ ")
filename.replace(" ", "\\ ")
}
// Makefile comments only need escaping newlines and `\`.
@ -574,7 +573,7 @@ fn write_out_deps(
.iter()
.filter(|fmap| fmap.is_real_file())
.filter(|fmap| !fmap.is_imported())
.map(|fmap| escape_dep_filename(&fmap.unmapped_path.as_ref().unwrap_or(&fmap.name)))
.map(|fmap| escape_dep_filename(&fmap.name.prefer_local().to_string()))
.collect();
if let Some(ref backend) = sess.opts.debugging_opts.codegen_backend {
@ -586,16 +585,13 @@ fn write_out_deps(
for cnum in resolver.cstore().crates_untracked() {
let source = resolver.cstore().crate_source_untracked(cnum);
if let Some((path, _)) = source.dylib {
let file_name = FileName::Real(RealFileName::Named(path));
files.push(escape_dep_filename(&file_name));
files.push(escape_dep_filename(&path.display().to_string()));
}
if let Some((path, _)) = source.rlib {
let file_name = FileName::Real(RealFileName::Named(path));
files.push(escape_dep_filename(&file_name));
files.push(escape_dep_filename(&path.display().to_string()));
}
if let Some((path, _)) = source.rmeta {
let file_name = FileName::Real(RealFileName::Named(path));
files.push(escape_dep_filename(&file_name));
files.push(escape_dep_filename(&path.display().to_string()));
}
}
});

View file

@ -724,6 +724,7 @@ macro_rules! tracked {
tracked!(profile_emit, Some(PathBuf::from("abc")));
tracked!(relax_elf_relocations, Some(true));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
tracked!(report_delayed_bugs, true);
tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(sanitizer_memory_track_origins, 2);

View file

@ -1651,9 +1651,11 @@ fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
if let Some(virtual_dir) = virtual_rust_source_base_dir {
if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
if let rustc_span::FileName::Real(old_name) = name {
if let rustc_span::RealFileName::Named(one_path) = old_name {
if let Ok(rest) = one_path.strip_prefix(virtual_dir) {
let virtual_name = one_path.clone();
if let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
old_name
{
if let Ok(rest) = virtual_name.strip_prefix(virtual_dir) {
let virtual_name = virtual_name.clone();
// The std library crates are in
// `$sysroot/lib/rustlib/src/rust/library`, whereas other crates
@ -1689,8 +1691,8 @@ fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
virtual_name.display(),
new_path.display(),
);
let new_name = rustc_span::RealFileName::Devirtualized {
local_path: new_path,
let new_name = rustc_span::RealFileName::Remapped {
local_path: Some(new_path),
virtual_name,
};
*old_name = new_name;
@ -1710,7 +1712,6 @@ fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
// containing the information we need.
let rustc_span::SourceFile {
mut name,
name_was_remapped,
src_hash,
start_pos,
end_pos,
@ -1722,11 +1723,34 @@ fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
..
} = source_file_to_import;
// If this file is under $sysroot/lib/rustlib/src/ but has not been remapped
// during rust bootstrapping by `remap-debuginfo = true`, and the user
// wish to simulate that behaviour by -Z simulate-remapped-rust-src-base,
// then we change `name` to a similar state as if the rust was bootstrapped
// with `remap-debuginfo = true`.
// This is useful for testing so that tests about the effects of
// `try_to_translate_virtual_to_real` don't have to worry about how the
// compiler is bootstrapped.
if let Some(virtual_dir) =
&sess.opts.debugging_opts.simulate_remapped_rust_src_base
{
if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
if let rustc_span::FileName::Real(ref mut old_name) = name {
if let rustc_span::RealFileName::LocalPath(local) = old_name {
if let Ok(rest) = local.strip_prefix(real_dir) {
*old_name = rustc_span::RealFileName::Remapped {
local_path: None,
virtual_name: virtual_dir.join(rest),
};
}
}
}
}
}
// If this file's path has been remapped to `/rustc/$hash`,
// we might be able to reverse that (also see comments above,
// on `try_to_translate_virtual_to_real`).
// FIXME(eddyb) we could check `name_was_remapped` here,
// but in practice it seems to be always `false`.
try_to_translate_virtual_to_real(&mut name);
let source_length = (end_pos - start_pos).to_usize();
@ -1751,7 +1775,6 @@ fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
let local_version = sess.source_map().new_imported_source_file(
name,
name_was_remapped,
src_hash,
name_hash,
source_length,

View file

@ -28,9 +28,12 @@
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_serialize::{opaque, Encodable, Encoder};
use rustc_session::config::CrateType;
use rustc_span::hygiene::{ExpnDataEncodeMode, HygieneEncodeContext, MacroKind};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
use rustc_span::{
hygiene::{ExpnDataEncodeMode, HygieneEncodeContext, MacroKind},
RealFileName,
};
use rustc_target::abi::VariantIdx;
use std::hash::Hash;
use std::num::NonZeroUsize;
@ -466,7 +469,6 @@ fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
let source_map = self.tcx.sess.source_map();
let all_source_files = source_map.files();
let (working_dir, _cwd_remapped) = self.tcx.sess.working_dir.clone();
// By replacing the `Option` with `None`, we ensure that we can't
// accidentally serialize any more `Span`s after the source map encoding
// is done.
@ -485,18 +487,41 @@ fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
})
.map(|(_, source_file)| {
let mut adapted = match source_file.name {
// This path of this SourceFile has been modified by
// path-remapping, so we use it verbatim (and avoid
// cloning the whole map in the process).
_ if source_file.name_was_remapped => source_file.clone(),
// Otherwise expand all paths to absolute paths because
// any relative paths are potentially relative to a
// wrong directory.
FileName::Real(ref name) => {
let name = name.stable_name();
FileName::Real(ref realname) => {
let mut adapted = (**source_file).clone();
adapted.name = Path::new(&working_dir).join(name).into();
adapted.name = FileName::Real(match realname {
RealFileName::LocalPath(path_to_file) => {
// Prepend path of working directory onto potentially
// relative paths, because they could become relative
// to a wrong directory.
let working_dir = &self.tcx.sess.working_dir;
match working_dir {
RealFileName::LocalPath(absolute) => {
// If working_dir has not been remapped, then we emit a
// LocalPath variant as it's likely to be a valid path
RealFileName::LocalPath(
Path::new(absolute).join(path_to_file),
)
}
RealFileName::Remapped { local_path: _, virtual_name } => {
// If working_dir has been remapped, then we emit
// Remapped variant as the expanded path won't be valid
RealFileName::Remapped {
local_path: None,
virtual_name: Path::new(virtual_name)
.join(path_to_file),
}
}
}
}
RealFileName::Remapped { local_path: _, virtual_name } => {
RealFileName::Remapped {
// We do not want any local path to be exported into metadata
local_path: None,
virtual_name: virtual_name.clone(),
}
}
});
adapted.name_hash = {
let mut hasher: StableHasher = StableHasher::new();
adapted.name.hash(&mut hasher);

View file

@ -197,7 +197,7 @@ fn insert_with_hash(&mut self, span: Span, hir_id: HirId, node: Node<'hir>, hash
span,
"inconsistent DepNode at `{:?}` for `{}`: \
current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
self.source_map.span_to_string(span),
self.source_map.span_to_diagnostic_string(span),
node_str,
self.definitions
.def_path(self.current_dep_node_owner)

View file

@ -61,8 +61,6 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
let SourceFile {
name: _, // We hash the smaller name_hash instead of this
name_hash,
name_was_remapped,
unmapped_path: _,
cnum,
// Do not hash the source as it is not encoded
src: _,
@ -77,7 +75,6 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
} = *self;
(name_hash as u64).hash_stable(hcx, hasher);
name_was_remapped.hash_stable(hcx, hasher);
src_hash.hash_stable(hcx, hasher);

View file

@ -2374,7 +2374,10 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
)
} else {
let span = tcx.hir().span(hir_id);
format!("[closure@{}]", tcx.sess.source_map().span_to_string(span))
format!(
"[closure@{}]",
tcx.sess.source_map().span_to_diagnostic_string(span)
)
};
let mut struct_fmt = fmt.debug_struct(&name);

View file

@ -667,7 +667,12 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
if let Some(did) = did.as_local() {
let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
let span = self.tcx().hir().span(hir_id);
p!(write("@{}", self.tcx().sess.source_map().span_to_string(span)));
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
// into MIR. Hence we use the remapped path if available
self.tcx().sess.source_map().span_to_embeddable_string(span)
));
} else {
p!(write("@"), print_def_path(did, substs));
}
@ -702,7 +707,12 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
p!("@", print_def_path(did.to_def_id(), substs));
} else {
let span = self.tcx().hir().span(hir_id);
p!(write("@{}", self.tcx().sess.source_map().span_to_string(span)));
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
// into MIR. Hence we use the remapped path if available
self.tcx().sess.source_map().span_to_embeddable_string(span)
));
}
} else {
p!(write("@"), print_def_path(did, substs));
@ -1407,7 +1417,13 @@ fn print_def_path(
if !self.empty_path {
write!(self, "::")?;
}
write!(self, "<impl at {}>", self.tcx.sess.source_map().span_to_string(span))?;
write!(
self,
"<impl at {}>",
// This may end up in stderr diagnostics but it may also be emitted
// into MIR. Hence we use the remapped path if available
self.tcx.sess.source_map().span_to_embeddable_string(span)
)?;
self.empty_path = false;
return Ok(self);

View file

@ -76,7 +76,9 @@ fn for_each_constraint(
for constraint in &constraints {
let OutlivesConstraint { sup, sub, locations, category } = constraint;
let (name, arg) = match locations {
Locations::All(span) => ("All", tcx.sess.source_map().span_to_string(*span)),
Locations::All(span) => {
("All", tcx.sess.source_map().span_to_embeddable_string(*span))
}
Locations::Single(loc) => ("Single", format!("{:?}", loc)),
};
with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?;

View file

@ -263,7 +263,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
if !self.span.is_dummy() {
let lo = tcx.sess.source_map().lookup_char_pos(self.span.lo());
write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
write!(
f,
" at {}:{}:{}",
lo.file.name.prefer_local(),
lo.line,
lo.col.to_usize() + 1
)?;
}
Ok(())
})

View file

@ -106,7 +106,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
(
Symbol::intern(&caller.file.name.to_string()),
Symbol::intern(&caller.file.name.prefer_remapped().to_string_lossy()),
u32::try_from(caller.line).unwrap(),
u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(),
)

View file

@ -169,8 +169,8 @@ fn inject_counters(&'a mut self) {
debug!(
"instrumenting {:?}, fn sig span: {}, body span: {}",
def_id,
source_map.span_to_string(fn_sig_span),
source_map.span_to_string(body_span)
source_map.span_to_diagnostic_string(fn_sig_span),
source_map.span_to_diagnostic_string(body_span)
);
let mut graphviz_data = debug::GraphvizData::new();
@ -311,7 +311,7 @@ fn inject_coverage_span_counters(
let tcx = self.tcx;
let source_map = tcx.sess.source_map();
let body_span = self.body_span;
let file_name = Symbol::intern(&self.source_file.name.to_string());
let file_name = Symbol::intern(&self.source_file.name.prefer_remapped().to_string_lossy());
let mut bcb_counters = IndexVec::from_elem_n(None, self.basic_coverage_blocks.num_nodes());
for covspan in coverage_spans {
@ -332,8 +332,8 @@ fn inject_coverage_span_counters(
"Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})",
file_name,
self.source_file,
source_map.span_to_string(span),
source_map.span_to_string(body_span)
source_map.span_to_diagnostic_string(span),
source_map.span_to_diagnostic_string(body_span)
);
inject_statement(

View file

@ -445,7 +445,10 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
ty::Tuple(tys) if tys.is_empty() => {}
_ => {
self.push("mir::Constant");
self.push(&format!("+ span: {}", self.tcx.sess.source_map().span_to_string(*span)));
self.push(&format!(
"+ span: {}",
self.tcx.sess.source_map().span_to_embeddable_string(*span)
));
if let Some(user_ty) = user_ty {
self.push(&format!("+ user_ty: {:?}", user_ty));
}
@ -516,7 +519,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
}
fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String {
format!("scope {} at {}", scope.index(), tcx.sess.source_map().span_to_string(span))
format!("scope {} at {}", scope.index(), tcx.sess.source_map().span_to_embeddable_string(span))
}
/// Prints local variables in a scope tree.
@ -617,7 +620,7 @@ fn write_scope_tree(
"{0:1$} // at {2}",
indented_header,
ALIGN,
tcx.sess.source_map().span_to_string(span),
tcx.sess.source_map().span_to_embeddable_string(span),
)?;
} else {
writeln!(w, "{}", indented_header)?;
@ -1004,7 +1007,7 @@ fn write_user_type_annotations(
"| {:?}: {:?} at {}",
index.index(),
annotation.user_ty,
tcx.sess.source_map().span_to_string(annotation.span)
tcx.sess.source_map().span_to_embeddable_string(annotation.span)
)?;
}
if !body.user_type_annotations.is_empty() {

View file

@ -628,7 +628,7 @@ fn tooltip<'tcx>(
) -> String {
let source_map = tcx.sess.source_map();
let mut text = Vec::new();
text.push(format!("{}: {}:", spanview_id, &source_map.span_to_string(span)));
text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span)));
for statement in statements {
let source_range = source_range_no_file(tcx, &statement.source_info.span);
text.push(format!(

View file

@ -188,8 +188,10 @@ pub fn maybe_file_to_stream(
override_span: Option<Span>,
) -> Result<(TokenStream, Vec<lexer::UnmatchedBrace>), Vec<Diagnostic>> {
let src = source_file.src.as_ref().unwrap_or_else(|| {
sess.span_diagnostic
.bug(&format!("cannot lex `source_file` without source: {}", source_file.name));
sess.span_diagnostic.bug(&format!(
"cannot lex `source_file` without source: {}",
source_file.name.prefer_local()
));
});
let (token_trees, unmatched_braces) =

View file

@ -132,9 +132,9 @@ enum LiveNodeKind {
fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
let sm = tcx.sess.source_map();
match lnk {
UpvarNode(s) => format!("Upvar node [{}]", sm.span_to_string(s)),
ExprNode(s) => format!("Expr node [{}]", sm.span_to_string(s)),
VarDefNode(s) => format!("Var def node [{}]", sm.span_to_string(s)),
UpvarNode(s) => format!("Upvar node [{}]", sm.span_to_diagnostic_string(s)),
ExprNode(s) => format!("Expr node [{}]", sm.span_to_diagnostic_string(s)),
VarDefNode(s) => format!("Var def node [{}]", sm.span_to_diagnostic_string(s)),
ClosureNode => "Closure node".to_owned(),
ExitNode => "Exit node".to_owned(),
}

View file

@ -717,7 +717,7 @@ fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
debug!(
"visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
owner_id,
self.tcx.sess.source_map().span_to_string(body.value.span),
self.tcx.sess.source_map().span_to_diagnostic_string(body.value.span),
body_id,
self.cx.parent
);

View file

@ -3451,7 +3451,7 @@ fn track_lifetime_uses(&self) -> bool {
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
debug!(
node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id),
span = ?self.tcx.sess.source_map().span_to_string(lifetime_ref.span)
span = ?self.tcx.sess.source_map().span_to_diagnostic_string(lifetime_ref.span)
);
self.map.defs.insert(lifetime_ref.hir_id, def);

View file

@ -190,7 +190,7 @@ pub fn dump_compilation_options(&mut self, input: &Input, crate_name: &str) {
};
let data = CompilationOptions {
directory: self.tcx.sess.working_dir.0.clone(),
directory: self.tcx.sess.working_dir.remapped_path_if_available().into(),
program,
arguments,
output: self.save_ctxt.compilation_output(crate_name),
@ -1112,7 +1112,7 @@ pub(crate) fn process_crate(&mut self, krate: &'tcx hir::Crate<'tcx>) {
name: String::new(),
qualname,
span,
value: filename.to_string(),
value: filename.prefer_remapped().to_string(),
children,
parent: None,
decl_id: None,

View file

@ -80,7 +80,7 @@ fn span_from_span(&self, span: Span) -> SpanData {
let end = sm.lookup_char_pos(span.hi());
SpanData {
file_name: start.file.name.to_string().into(),
file_name: start.file.name.prefer_remapped().to_string().into(),
byte_start: span.lo().0,
byte_end: span.hi().0,
line_start: Row::new_one_indexed(start.line as u32),
@ -290,7 +290,7 @@ pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
name: item.ident.to_string(),
qualname,
span: self.span_from_span(item.ident.span),
value: filename.to_string(),
value: filename.prefer_remapped().to_string(),
parent: None,
children: m
.item_ids

View file

@ -16,8 +16,7 @@ pub fn new(sess: &'a Session) -> SpanUtils<'a> {
pub fn make_filename_string(&self, file: &SourceFile) -> String {
match &file.name {
FileName::Real(name) if !file.name_was_remapped => {
let path = name.local_path();
FileName::Real(RealFileName::LocalPath(path)) => {
if path.is_absolute() {
self.sess
.source_map()
@ -27,12 +26,15 @@ pub fn make_filename_string(&self, file: &SourceFile) -> String {
.display()
.to_string()
} else {
self.sess.working_dir.0.join(&path).display().to_string()
self.sess
.working_dir
.remapped_path_if_available()
.join(&path)
.display()
.to_string()
}
}
// If the file name is already remapped, we assume the user
// configured it the way they wanted to, so use that directly
filename => filename.to_string(),
filename => filename.prefer_remapped().to_string(),
}
}

View file

@ -1201,6 +1201,9 @@ mod parse {
"whether ELF relocations can be relaxed"),
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
"choose which RELRO level to use"),
simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
"simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
to rust's source base directory. only meant for testing purposes"),
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
"immediately print bugs registered with `delay_span_bug` (default: no)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],

View file

@ -23,8 +23,8 @@
use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported};
use rustc_lint_defs::FutureBreakage;
pub use rustc_span::crate_disambiguator::CrateDisambiguator;
use rustc_span::edition::Edition;
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
use rustc_span::{edition::Edition, RealFileName};
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
@ -125,9 +125,8 @@ pub struct Session {
/// The name of the root source file of the crate, in the local file system.
/// `None` means that there is no source file.
pub local_crate_source_file: Option<PathBuf>,
/// The directory the compiler has been executed in plus a flag indicating
/// if the value stored here has been affected by path remapping.
pub working_dir: (PathBuf, bool),
/// The directory the compiler has been executed in
pub working_dir: RealFileName,
/// Set of `(DiagnosticId, Option<Span>, message)` tuples tracking
/// (sub)diagnostics that have been set once, but should not be set again,
@ -1356,7 +1355,12 @@ pub fn build_session(
let working_dir = env::current_dir().unwrap_or_else(|e| {
parse_sess.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)).raise()
});
let working_dir = file_path_mapping.map_prefix(working_dir);
let (path, remapped) = file_path_mapping.map_prefix(working_dir.clone());
let working_dir = if remapped {
RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
} else {
RealFileName::LocalPath(path)
};
let cgu_reuse_tracker = if sopts.debugging_opts.query_dep_graph {
CguReuseTracker::new()

View file

@ -114,52 +114,112 @@ pub fn with_default_session_globals<R>(f: impl FnOnce() -> R) -> R {
// deserialization.
scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
// FIXME: Perhaps this should not implement Rustc{Decodable, Encodable}
//
// FIXME: We should use this enum or something like it to get rid of the
// use of magic `/rust/1.x/...` paths across the board.
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
#[derive(HashStable_Generic, Decodable, Encodable)]
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)]
#[derive(HashStable_Generic, Decodable)]
pub enum RealFileName {
Named(PathBuf),
/// For de-virtualized paths (namely paths into libstd that have been mapped
/// to the appropriate spot on the local host's file system),
Devirtualized {
/// `local_path` is the (host-dependent) local path to the file.
local_path: PathBuf,
LocalPath(PathBuf),
/// For remapped paths (namely paths into libstd that have been mapped
/// to the appropriate spot on the local host's file system, and local file
/// system paths that have been remapped with `FilePathMapping`),
Remapped {
/// `local_path` is the (host-dependent) local path to the file. This is
/// None if the file was imported from another crate
local_path: Option<PathBuf>,
/// `virtual_name` is the stable path rustc will store internally within
/// build artifacts.
virtual_name: PathBuf,
},
}
impl Hash for RealFileName {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
// To prevent #70924 from happening again we should only hash the
// remapped (virtualized) path if that exists. This is because
// virtualized paths to sysroot crates (/rust/$hash or /rust/$version)
// remain stable even if the corresponding local_path changes
self.remapped_path_if_available().hash(state)
}
}
// This is functionally identical to #[derive(Encodable)], with the exception of
// an added assert statement
impl<S: Encoder> Encodable<S> for RealFileName {
fn encode(&self, encoder: &mut S) -> Result<(), S::Error> {
encoder.emit_enum("RealFileName", |encoder| match *self {
RealFileName::LocalPath(ref local_path) => {
encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
Ok({
encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?;
})
})
}
RealFileName::Remapped { ref local_path, ref virtual_name } => encoder
.emit_enum_variant("Remapped", 1, 2, |encoder| {
// For privacy and build reproducibility, we must not embed host-dependant path in artifacts
// if they have been remapped by --remap-path-prefix
assert!(local_path.is_none());
Ok({
encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?;
encoder.emit_enum_variant_arg(1, |encoder| virtual_name.encode(encoder))?;
})
}),
})
}
}
impl RealFileName {
/// Returns the path suitable for reading from the file system on the local host.
/// Avoid embedding this in build artifacts; see `stable_name()` for that.
pub fn local_path(&self) -> &Path {
/// Returns the path suitable for reading from the file system on the local host,
/// if this information exists.
/// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
pub fn local_path(&self) -> Option<&Path> {
match self {
RealFileName::Named(p)
| RealFileName::Devirtualized { local_path: p, virtual_name: _ } => &p,
RealFileName::LocalPath(p) => Some(p),
RealFileName::Remapped { local_path: p, virtual_name: _ } => {
p.as_ref().map(PathBuf::as_path)
}
}
}
/// Returns the path suitable for reading from the file system on the local host.
/// Avoid embedding this in build artifacts; see `stable_name()` for that.
pub fn into_local_path(self) -> PathBuf {
/// Returns the path suitable for reading from the file system on the local host,
/// if this information exists.
/// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
pub fn into_local_path(self) -> Option<PathBuf> {
match self {
RealFileName::Named(p)
| RealFileName::Devirtualized { local_path: p, virtual_name: _ } => p,
RealFileName::LocalPath(p) => Some(p),
RealFileName::Remapped { local_path: p, virtual_name: _ } => p,
}
}
/// Returns the path suitable for embedding into build artifacts. Note that
/// a virtualized path will not correspond to a valid file system path; see
/// `local_path()` for something that is more likely to return paths into the
/// local host file system.
pub fn stable_name(&self) -> &Path {
/// Returns the path suitable for embedding into build artifacts. This would still
/// be a local path if it has not been remapped. A remapped path will not correspond
/// to a valid file system path: see `local_path_if_available()` for something that
/// is more likely to return paths into the local host file system.
pub fn remapped_path_if_available(&self) -> &Path {
match self {
RealFileName::Named(p)
| RealFileName::Devirtualized { local_path: _, virtual_name: p } => &p,
RealFileName::LocalPath(p)
| RealFileName::Remapped { local_path: _, virtual_name: p } => &p,
}
}
/// Returns the path suitable for reading from the file system on the local host,
/// if this information exists. Otherwise returns the remapped name.
/// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that.
pub fn local_path_if_available(&self) -> &Path {
match self {
RealFileName::LocalPath(path)
| RealFileName::Remapped { local_path: None, virtual_name: path }
| RealFileName::Remapped { local_path: Some(path), virtual_name: _ } => path,
}
}
pub fn to_string_lossy(&self, prefer_local: bool) -> Cow<'_, str> {
if prefer_local {
self.local_path_if_available().to_string_lossy()
} else {
self.remapped_path_if_available().to_string_lossy()
}
}
}
@ -188,16 +248,24 @@ pub enum FileName {
InlineAsm(u64),
}
impl std::fmt::Display for FileName {
impl From<PathBuf> for FileName {
fn from(p: PathBuf) -> Self {
assert!(!p.to_string_lossy().ends_with('>'));
FileName::Real(RealFileName::LocalPath(p))
}
}
pub struct FileNameDisplay<'a> {
inner: &'a FileName,
prefer_local: bool,
}
impl fmt::Display for FileNameDisplay<'_> {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use FileName::*;
match *self {
Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()),
// FIXME: might be nice to display both components of Devirtualized.
// But for now (to backport fix for issue #70924), best to not
// perturb diagnostics so its obvious test suite still works.
Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => {
write!(fmt, "{}", local_path.display())
match *self.inner {
Real(ref name) => {
write!(fmt, "{}", name.to_string_lossy(self.prefer_local))
}
QuoteExpansion(_) => write!(fmt, "<quote expansion>"),
MacroExpansion(_) => write!(fmt, "<macro expansion>"),
@ -212,10 +280,12 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
}
}
impl From<PathBuf> for FileName {
fn from(p: PathBuf) -> Self {
assert!(!p.to_string_lossy().ends_with('>'));
FileName::Real(RealFileName::Named(p))
impl FileNameDisplay<'_> {
pub fn to_string_lossy(&self) -> Cow<'_, str> {
match self.inner {
FileName::Real(ref inner) => inner.to_string_lossy(self.prefer_local),
_ => Cow::from(format!("{}", self)),
}
}
}
@ -236,6 +306,16 @@ pub fn is_real(&self) -> bool {
}
}
pub fn prefer_remapped(&self) -> FileNameDisplay<'_> {
FileNameDisplay { inner: self, prefer_local: false }
}
// This may include transient local filesystem information.
// Must not be embedded in build outputs.
pub fn prefer_local(&self) -> FileNameDisplay<'_> {
FileNameDisplay { inner: self, prefer_local: true }
}
pub fn macro_expansion_source_code(src: &str) -> FileName {
let mut hasher = StableHasher::new();
src.hash(&mut hasher);
@ -796,7 +876,7 @@ pub fn debug_with_source_map(
f: &mut fmt::Formatter<'_>,
source_map: &SourceMap,
) -> fmt::Result {
write!(f, "{} ({:?})", source_map.span_to_string(span), span.ctxt())
write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(span), span.ctxt())
}
pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -1128,11 +1208,6 @@ pub struct SourceFile {
/// originate from files has names between angle brackets by convention
/// (e.g., `<anon>`).
pub name: FileName,
/// `true` if the `name` field above has been modified by `--remap-path-prefix`.
pub name_was_remapped: bool,
/// The unmapped path of the file that the source came from.
/// Set to `None` if the `SourceFile` was imported from an external crate.
pub unmapped_path: Option<FileName>,
/// The complete source code.
pub src: Option<Lrc<String>>,
/// The source code's hash.
@ -1162,7 +1237,6 @@ impl<S: Encoder> Encodable<S> for SourceFile {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_struct("SourceFile", 8, |s| {
s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?;
s.emit_struct_field("start_pos", 3, |s| self.start_pos.encode(s))?;
s.emit_struct_field("end_pos", 4, |s| self.end_pos.encode(s))?;
@ -1237,8 +1311,6 @@ impl<D: Decoder> Decodable<D> for SourceFile {
fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
d.read_struct("SourceFile", 8, |d| {
let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
let name_was_remapped: bool =
d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?;
let src_hash: SourceFileHash =
d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
let start_pos: BytePos =
@ -1282,8 +1354,6 @@ fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
let cnum: CrateNum = d.read_struct_field("cnum", 10, |d| Decodable::decode(d))?;
Ok(SourceFile {
name,
name_was_remapped,
unmapped_path: None,
start_pos,
end_pos,
src: None,
@ -1304,15 +1374,13 @@ fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
impl fmt::Debug for SourceFile {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "SourceFile({})", self.name)
write!(fmt, "SourceFile({:?})", self.name)
}
}
impl SourceFile {
pub fn new(
name: FileName,
name_was_remapped: bool,
unmapped_path: FileName,
mut src: String,
start_pos: BytePos,
hash_kind: SourceFileHashAlgorithm,
@ -1334,8 +1402,6 @@ pub fn new(
SourceFile {
name,
name_was_remapped,
unmapped_path: Some(unmapped_path),
src: Some(Lrc::new(src)),
src_hash,
external_src: Lock::new(ExternalSource::Unneeded),

View file

@ -15,11 +15,11 @@
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 @@ fn read_file(&self, path: &Path) -> io::Result<String> {
// 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 @@ pub fn new_source_file(&self, filename: FileName, src: String) -> Lrc<SourceFile
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 @@ fn try_new_source_file(
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 @@ fn try_new_source_file(
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 @@ pub fn new_imported_source_file(
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 @@ pub fn new_imported_source_file(
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 @@ pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Lrc<SourceF
}
}
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 @@ pub fn span_to_string(&self, sp: Span) -> String {
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 @@ pub fn span_to_string(&self, sp: Span) -> String {
)
}
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 @@ pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, Str
}
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 @@ pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) {
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),
}

View file

@ -193,7 +193,7 @@ fn t8() {
fn t9() {
let sm = init_source_map();
let span = Span::with_root_ctxt(BytePos(12), BytePos(23));
let sstr = sm.span_to_string(span);
let sstr = sm.span_to_diagnostic_string(span);
assert_eq!(sstr, "blork.rs:2:1: 2:12");
}
@ -229,7 +229,6 @@ fn t10() {
let SourceFile {
name,
name_was_remapped,
src_hash,
start_pos,
end_pos,
@ -243,7 +242,6 @@ fn t10() {
let imported_src_file = sm.new_imported_source_file(
name,
name_was_remapped,
src_hash,
name_hash,
(end_pos - start_pos).to_usize(),

View file

@ -164,7 +164,7 @@ fn def_id(&self) -> DefId {
crate fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
match self.src(tcx) {
FileName::Real(ref p) => match p.local_path().parent() {
FileName::Real(ref p) => match p.local_path_if_available().parent() {
Some(p) => p.to_path_buf(),
None => PathBuf::new(),
},

View file

@ -839,7 +839,7 @@ fn generate_name(&self, line: usize, filename: &FileName) -> String {
if !item_path.is_empty() {
item_path.push(' ');
}
format!("{} - {}(line {})", filename, item_path, line)
format!("{} - {}(line {})", filename.prefer_local(), item_path, line)
}
crate fn set_position(&mut self, position: Span) {
@ -851,8 +851,10 @@ fn get_filename(&self) -> FileName {
let filename = source_map.span_to_filename(self.position);
if let FileName::Real(ref filename) = filename {
if let Ok(cur_dir) = env::current_dir() {
if let Ok(path) = filename.local_path().strip_prefix(&cur_dir) {
return path.to_owned().into();
if let Some(local_path) = filename.local_path() {
if let Ok(path) = local_path.strip_prefix(&cur_dir) {
return path.to_owned().into();
}
}
}
}
@ -882,16 +884,22 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
self.compiling_test_count.fetch_add(1, Ordering::SeqCst);
}
// FIXME(#44940): if doctests ever support path remapping, then this filename
// needs to be the result of `SourceMap::span_to_unmapped_path`.
let path = match &filename {
FileName::Real(path) => path.local_path().to_path_buf(),
FileName::Real(path) => {
if let Some(local_path) = path.local_path() {
local_path.to_path_buf()
} else {
// Somehow we got the filename from the metadata of another crate, should never happen
unreachable!("doctest from a different crate");
}
}
_ => PathBuf::from(r"doctest.rs"),
};
// For example `module/file.rs` would become `module_file_rs`
let file = filename
.to_string()
.prefer_local()
.to_string_lossy()
.chars()
.map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
.collect::<String>();

View file

@ -293,7 +293,7 @@ pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
// We can safely ignore synthetic `SourceFile`s.
let file = match item.span(self.tcx()).filename(self.sess()) {
FileName::Real(ref path) => path.local_path().to_path_buf(),
FileName::Real(ref path) => path.local_path_if_available().to_path_buf(),
_ => return None,
};
let file = &file;
@ -380,7 +380,7 @@ fn init(
} = options;
let src_root = match krate.src {
FileName::Real(ref p) => match p.local_path().parent() {
FileName::Real(ref p) => match p.local_path_if_available().parent() {
Some(p) => p.to_path_buf(),
None => PathBuf::new(),
},

View file

@ -56,7 +56,11 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
Err(e) => {
self.scx.tcx.sess.span_err(
item.span(self.scx.tcx).inner(),
&format!("failed to render source code for `{}`: {}", filename, e),
&format!(
"failed to render source code for `{}`: {}",
filename.prefer_local(),
e
),
);
false
}
@ -76,7 +80,13 @@ fn sess(&self) -> &'tcx Session {
/// Renders the given filename into its corresponding HTML source file.
fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
let p = match *filename {
FileName::Real(ref file) => file.local_path().to_path_buf(),
FileName::Real(ref file) => {
if let Some(local_path) = file.local_path() {
local_path.to_path_buf()
} else {
unreachable!("only the current crate should have sources emitted");
}
}
_ => return Ok(()),
};
if self.scx.local_sources.contains_key(&*p) {
@ -113,7 +123,7 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
href.push_str(&fname.to_string_lossy());
let title = format!("{} - source", src_fname.to_string_lossy());
let desc = format!("Source of the Rust file `{}`.", filename);
let desc = format!("Source of the Rust file `{}`.", filename.prefer_remapped());
let page = layout::Page {
title: &title,
css_class: "source",

View file

@ -64,18 +64,17 @@ pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
fn convert_span(&self, span: clean::Span) -> Option<Span> {
match span.filename(self.sess()) {
rustc_span::FileName::Real(name) => {
let hi = span.hi(self.sess());
let lo = span.lo(self.sess());
Some(Span {
filename: match name {
rustc_span::RealFileName::Named(path) => path,
rustc_span::RealFileName::Devirtualized { local_path, virtual_name: _ } => {
local_path
}
},
begin: (lo.line, lo.col.to_usize()),
end: (hi.line, hi.col.to_usize()),
})
if let Some(local_path) = name.into_local_path() {
let hi = span.hi(self.sess());
let lo = span.lo(self.sess());
Some(Span {
filename: local_path,
begin: (lo.line, lo.col.to_usize()),
end: (hi.line, hi.col.to_usize()),
})
} else {
None
}
}
_ => None,
}

View file

@ -119,7 +119,7 @@ fn to_json(&self) -> String {
&self
.items
.iter()
.map(|(k, v)| (k.to_string(), v))
.map(|(k, v)| (k.prefer_local().to_string(), v))
.collect::<BTreeMap<String, &ItemCount>>(),
)
.expect("failed to convert JSON data to string")
@ -159,7 +159,7 @@ fn print_table_record(
for (file, &count) in &self.items {
if let Some(percentage) = count.percentage() {
print_table_record(
&limit_filename_len(file.to_string()),
&limit_filename_len(file.prefer_local().to_string_lossy().into()),
count,
percentage,
count.examples_percentage().unwrap_or(0.),
@ -225,7 +225,7 @@ fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
// unless the user had an explicit `allow`
let should_have_docs =
level != lint::Level::Allow || matches!(source, LintLevelSource::Default);
debug!("counting {:?} {:?} in {}", i.type_(), i.name, filename);
debug!("counting {:?} {:?} in {:?}", i.type_(), i.name, filename);
self.items.entry(filename).or_default().count_item(
has_docs,
has_doc_example,

View file

@ -0,0 +1,15 @@
// ignore-windows
// compile-flags: -g -C no-prepopulate-passes -Z simulate-remapped-rust-src-base=/rustc/xyz
// Here we check that importing std will not cause real path to std source files
// to leak. If rustc was compiled with remap-debuginfo = true, this should be
// true automatically. If paths to std library hasn't been remapped, we use the
// above simulate-remapped-rust-src-base option to do it temporarily
// CHECK: !DIFile(filename: "{{/rustc/.*/library/std/src/panic.rs}}"
fn main() {
std::thread::spawn(|| {
println!("hello");
});
}

View file

@ -47,7 +47,7 @@ pub struct MacroRefData {
impl MacroRefData {
pub fn new(name: String, callee: Span, cx: &LateContext<'_>) -> Self {
let mut path = cx.sess().source_map().span_to_filename(callee).to_string();
let mut path = cx.sess().source_map().span_to_filename(callee).prefer_local().to_string();
// std lib paths are <::std::module::file type>
// so remove brackets, space and type.
@ -96,8 +96,7 @@ fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_>, span: Span) {
let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
if let Some(callee) = span.source_callee() {
if !self.collected.contains(&call_site) {
self.mac_refs
.push(MacroRefData::new(name.to_string(), callee.def_site, cx));
self.mac_refs.push(MacroRefData::new(name.to_string(), callee.def_site, cx));
self.collected.insert(call_site);
}
}
@ -175,7 +174,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'_>, _krate: &hir::Crate<'_>) {
.push((*item).to_string());
check_dup.push((*item).to_string());
}
},
}
[root, rest @ ..] => {
if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) {
let filtered = rest
@ -199,7 +198,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'_>, _krate: &hir::Crate<'_>) {
.push(rest.join("::"));
check_dup.extend(rest.iter().map(ToString::to_string));
}
},
}
}
}
}

View file

@ -3650,6 +3650,12 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
.join("library");
normalize_path(&src_dir, "$SRC_DIR");
if let Some(virtual_rust_source_base_dir) =
option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
{
normalize_path(&virtual_rust_source_base_dir.join("library"), "$SRC_DIR");
}
// Paths into the build directory
let test_build_dir = &self.config.build_base;
let parent_build_dir = test_build_dir.parent().unwrap().parent().unwrap().parent().unwrap();