diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 4aafcb2fb6dfe..ccb9f15b0f505 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -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( diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 92e4435565ee7..c12d6d0f14143 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -334,7 +334,9 @@ impl<'tcx> FunctionCx<'_, '_, '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, )); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 8578ab33ced68..9eb067706309e 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -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, ); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index dc8bc8d9cb741..61e54a76f29ba 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -64,7 +64,7 @@ impl<'tcx> DebugContext<'tcx> { // 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(); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 280d9a4d37021..5cf831475d464 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -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() { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index fd3f89a2aee96..72e9163b88e21 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1144,7 +1144,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 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, )); diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 6f365c07f6d30..577baec21f064 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -126,7 +126,8 @@ impl AnnotateSnippetEmitterWriter { } // owned: line source, line index, annotations type Owned = (String, usize, Vec); - 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 = annotated_files .into_iter() .flat_map(|annotated_file| { diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 61870eede1dd5..c4c15136cf82d 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1324,7 +1324,7 @@ impl EmitterWriter { 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 @@ impl EmitterWriter { 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 @@ impl EmitterWriter { }; 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 { diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 40277006462d2..5d175a3ade9a2 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -468,7 +468,7 @@ impl DiagnosticSpan { }); 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, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 0e966d0bf793d..e1c218c640851 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1084,13 +1084,18 @@ impl<'a> ExtCtxt<'a> { // 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() + ), )); } }; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 3347c93948ccc..f5c6bb3db6542 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -361,9 +361,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // 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(); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index f6645448fccbc..7bf6502c976ca 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -638,10 +638,11 @@ impl server::SourceFile for Rustc<'_> { 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/' 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.") { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 1cafb2fe1a24f..680f6af63f26c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1604,13 +1604,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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(), }; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 96dbdce1126ae..9005325f0b42d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -35,7 +35,6 @@ use rustc_session::output::{filename_for_input, filename_for_metadata}; 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 { 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())); } } }); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index fd13cb3d59acd..17dc6fd1d52ee 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -724,6 +724,7 @@ fn test_debugging_options_tracking_hash() { 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); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4a01731b51276..e2e523fad66c0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1651,9 +1651,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { 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 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { 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 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // containing the information we need. let rustc_span::SourceFile { mut name, - name_was_remapped, src_hash, start_pos, end_pos, @@ -1722,11 +1723,34 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .. } = 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 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let local_version = sess.source_map().new_imported_source_file( name, - name_was_remapped, src_hash, name_hash, source_length, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c61417f99981d..19c713665c782 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -28,9 +28,12 @@ use rustc_middle::ty::codec::TyEncoder; 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 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { 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 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) .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); diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 719bbf04c95bd..342cc9a7397b7 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -197,7 +197,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { 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) diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs index b93b25d6b5c9a..2d8f661ef59e9 100644 --- a/compiler/rustc_middle/src/ich/impls_syntax.rs +++ b/compiler/rustc_middle/src/ich/impls_syntax.rs @@ -61,8 +61,6 @@ impl<'a> HashStable> for SourceFile { 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 @@ impl<'a> HashStable> for SourceFile { } = *self; (name_hash as u64).hash_stable(hcx, hasher); - name_was_remapped.hash_stable(hcx, hasher); src_hash.hash_stable(hcx, hasher); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index de0c4f2e30e8b..1cc7f235d7d21 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2374,7 +2374,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { ) } 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); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 174ec481ae93d..cfb9cfd86f978 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -667,7 +667,12 @@ pub trait PrettyPrinter<'tcx>: 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 @@ pub trait PrettyPrinter<'tcx>: 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 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { if !self.empty_path { write!(self, "::")?; } - write!(self, "", self.tcx.sess.source_map().span_to_string(span))?; + write!( + self, + "", + // 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); diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs index 86d9db294bf71..5892ef37ebacb 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs @@ -76,7 +76,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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))?; diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 2d83d6cfbdc5e..e9dd7a3fe68f1 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -263,7 +263,13 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> { } 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(()) }) diff --git a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs index 4dfdc08b875c0..2b996cf62a3d3 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs @@ -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(), ) diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index aca11de451667..918d6ee4b0ccd 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -169,8 +169,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { "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( diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 3b88aec16b26a..955e85c944a5d 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -445,7 +445,10 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { 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 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { } 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() { diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs index 9abfa4a8dc68b..2103f2f093407 100644 --- a/compiler/rustc_mir/src/util/spanview.rs +++ b/compiler/rustc_mir/src/util/spanview.rs @@ -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!( diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 905077a48e25a..077b19fa95959 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -188,8 +188,10 @@ pub fn maybe_file_to_stream( override_span: Option, ) -> Result<(TokenStream, Vec), Vec> { 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) = diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index fa930471c2110..4ceefa17bcf3d 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -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(), } diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs index 14a373c59423f..c133f1a041719 100644 --- a/compiler/rustc_passes/src/region.rs +++ b/compiler/rustc_passes/src/region.rs @@ -717,7 +717,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'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 ); diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index bf69defb4e674..efa5d7e7b1139 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -3451,7 +3451,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { 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); diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 12c77e0c8a60d..54b6a12158581 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -190,7 +190,7 @@ impl<'tcx> DumpVisitor<'tcx> { }; 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 @@ impl<'tcx> DumpVisitor<'tcx> { name: String::new(), qualname, span, - value: filename.to_string(), + value: filename.prefer_remapped().to_string(), children, parent: None, decl_id: None, diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 7256e68b87adc..bcd125ae01dde 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -80,7 +80,7 @@ impl<'tcx> SaveContext<'tcx> { 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 @@ impl<'tcx> SaveContext<'tcx> { 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 diff --git a/compiler/rustc_save_analysis/src/span_utils.rs b/compiler/rustc_save_analysis/src/span_utils.rs index edcd492577374..1947b04f441c3 100644 --- a/compiler/rustc_save_analysis/src/span_utils.rs +++ b/compiler/rustc_save_analysis/src/span_utils.rs @@ -16,8 +16,7 @@ impl<'a> 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 @@ impl<'a> SpanUtils<'a> { .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(), } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ca8bb3af2ba69..d2145b2865b17 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1201,6 +1201,9 @@ options! { "whether ELF relocations can be relaxed"), relro_level: Option = (None, parse_relro_level, [TRACKED], "choose which RELRO level to use"), + simulate_remapped_rust_src_base: Option = (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], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 6d74723993bcd..1348b02b8780f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -23,8 +23,8 @@ use rustc_errors::registry::Registry; 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, - /// 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, 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() diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d56b434ca85ea..0301b3645913a 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -114,52 +114,112 @@ pub fn with_default_session_globals(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, /// `virtual_name` is the stable path rustc will store internally within /// build artifacts. virtual_name: PathBuf, }, } +impl Hash for RealFileName { + fn hash(&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 Encodable 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 { 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 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, ""), MacroExpansion(_) => write!(fmt, ""), @@ -212,10 +280,12 @@ impl std::fmt::Display for FileName { } } -impl From 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 @@ impl FileName { } } + 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., ``). 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, /// The complete source code. pub src: Option>, /// The source code's hash. @@ -1162,7 +1237,6 @@ impl Encodable 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 Decodable for SourceFile { fn decode(d: &mut D) -> Result { 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 @@ impl Decodable for SourceFile { 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 @@ impl Decodable for SourceFile { 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 @@ impl SourceFile { SourceFile { name, - name_was_remapped, - unmapped_path: Some(unmapped_path), src: Some(Lrc::new(src)), src_hash, external_src: Lock::new(ExternalSource::Unneeded), diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index e365844980b4b..0dadd4192004f 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -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, 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 `` 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 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 (filename, _) = self.path_mapping.map_filename_prefix(&filename); - 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) + } + + /// 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_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`?") + 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) -> 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), } diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 7d814f1d82c11..f13979941abee 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -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(), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index bca7a8cfcee09..7d802636bfac2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -164,7 +164,7 @@ impl ExternalCrate { 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(), }, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 03e3fe52f71ee..3a4d39e1d7f72 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -839,7 +839,7 @@ impl Collector { 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 @@ impl Collector { 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 @@ impl Tester for Collector { 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::(); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 666d9dfc3e9e4..8fd5d8b6b85b8 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -293,7 +293,7 @@ impl<'tcx> Context<'tcx> { // 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 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } = 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(), }, diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 57c33f94918d7..5e2a94fe6845f 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -56,7 +56,11 @@ impl DocFolder for SourceCollector<'_, '_> { 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 @@ impl SourceCollector<'_, 'tcx> { /// 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 @@ impl SourceCollector<'_, 'tcx> { 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", diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index e3f1c6b1e2dc4..e0e5db3b5634b 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -64,18 +64,17 @@ impl JsonRenderer<'_> { fn convert_span(&self, span: clean::Span) -> Option { 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, } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index e65fcf057f15c..26a22f5b30494 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -119,7 +119,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { &self .items .iter() - .map(|(k, v)| (k.to_string(), v)) + .map(|(k, v)| (k.prefer_local().to_string(), v)) .collect::>(), ) .expect("failed to convert JSON data to string") @@ -159,7 +159,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { 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 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { // 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, diff --git a/src/test/codegen/remap_path_prefix/issue-73167-remap-std.rs b/src/test/codegen/remap_path_prefix/issue-73167-remap-std.rs new file mode 100644 index 0000000000000..b66abc6bedf0f --- /dev/null +++ b/src/test/codegen/remap_path_prefix/issue-73167-remap-std.rs @@ -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"); + }); +} diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index ec03daff87b07..314bf11e2d666 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -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 @@ impl MacroUseImports { 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 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { .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 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { .push(rest.join("::")); check_dup.extend(rest.iter().map(ToString::to_string)); } - }, + } } } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index c606aa1dfbfd4..f4e16483d8c3a 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3650,6 +3650,12 @@ impl<'test> TestCx<'test> { .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();