From 90187d4223710d71f4d6236b69f6e866634f6919 Mon Sep 17 00:00:00 2001 From: arferreira Date: Mon, 20 Apr 2026 13:14:29 -0400 Subject: [PATCH 1/6] Normalize .. and . in diagnostic file paths --- compiler/rustc_span/src/lib.rs | 35 ++++++++++++++----- compiler/rustc_span/src/source_map.rs | 2 +- compiler/rustc_span/src/source_map/tests.rs | 11 ++++++ src/tools/compiletest/src/runtest.rs | 10 ++++++ tests/ui/README.md | 4 +++ .../generic_arg_infer/issue-91614.stderr | 4 +-- tests/ui/diagnostics/auxiliary/helper.rs | 3 ++ tests/ui/diagnostics/auxiliary/sub/mod.rs | 2 ++ tests/ui/diagnostics/normalize-path.rs | 9 +++++ tests/ui/diagnostics/normalize-path.stderr | 11 ++++++ 10 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 tests/ui/diagnostics/auxiliary/helper.rs create mode 100644 tests/ui/diagnostics/auxiliary/sub/mod.rs create mode 100644 tests/ui/diagnostics/normalize-path.rs create mode 100644 tests/ui/diagnostics/normalize-path.stderr diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f048fb04af45a..36b1ced63fd4b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -23,6 +23,7 @@ #![feature(diagnostic_on_unknown)] #![feature(map_try_insert)] #![feature(negative_impls)] +#![feature(normalize_lexically)] #![feature(read_buf)] #![feature(rustc_attrs)] // tidy-alphabetical-end @@ -500,6 +501,15 @@ impl RealFileName { .file_name() .map_or_else(|| "".into(), |f| f.to_string_lossy()), FileNameDisplayPreference::Scope(scope) => self.path(scope).to_string_lossy(), + FileNameDisplayPreference::Diagnostics(scope) => { + let path = self.path(scope); + match path.normalize_lexically() { + Ok(normalized) => { + Cow::Owned(normalized.into_os_string().to_string_lossy().into_owned()) + } + Err(_) => path.to_string_lossy(), + } + } } } } @@ -538,6 +548,16 @@ enum FileNameDisplayPreference { Local, Short, Scope(RemapPathScopeComponents), + Diagnostics(RemapPathScopeComponents), +} + +impl<'a> FileNameDisplay<'a> { + pub fn to_string_lossy(&self) -> Cow<'a, str> { + match self.inner { + FileName::Real(inner) => inner.to_string_lossy(self.display_pref), + _ => Cow::from(self.to_string()), + } + } } impl fmt::Display for FileNameDisplay<'_> { @@ -558,15 +578,6 @@ impl fmt::Display for FileNameDisplay<'_> { } } -impl<'a> FileNameDisplay<'a> { - pub fn to_string_lossy(&self) -> Cow<'a, str> { - match self.inner { - FileName::Real(inner) => inner.to_string_lossy(self.display_pref), - _ => Cow::from(self.to_string()), - } - } -} - impl FileName { pub fn is_real(&self) -> bool { use FileName::*; @@ -613,6 +624,12 @@ impl FileName { FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Scope(scope) } } + /// Like `display`, but with `.` and `..` resolved lexically. See #51349. + #[inline] + pub fn display_normalized(&self, scope: RemapPathScopeComponents) -> FileNameDisplay<'_> { + FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Diagnostics(scope) } + } + pub fn macro_expansion_source_code(src: &str) -> FileName { let mut hasher = StableHasher::new(); src.hash(&mut hasher); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index f394765ab9f8e..2d1752f0edd07 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -521,7 +521,7 @@ impl SourceMap { } pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> { - filename.display(RemapPathScopeComponents::DIAGNOSTICS) + filename.display_normalized(RemapPathScopeComponents::DIAGNOSTICS) } pub fn is_multiline(&self, sp: Span) -> bool { diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 4cc243667f224..acc186a007fca 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -797,3 +797,14 @@ fn read_binary_file_handles_lying_stat() { let bin = RealFileLoader.read_binary_file(kernel_max).unwrap(); assert_eq!(&real[..], &bin[..]); } + +#[test] +fn filename_for_diagnostics_resolves_parent_dir() { + let sm = SourceMap::new(FilePathMapping::empty()); + + let with_parent = filename(&sm, "tests/sub/../helper.rs"); + assert_eq!(sm.filename_for_diagnostics(&with_parent).to_string(), path_str("tests/helper.rs")); + + let clean = filename(&sm, "tests/clean.rs"); + assert_eq!(sm.filename_for_diagnostics(&clean).to_string(), path_str("tests/clean.rs")); +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index b7453adc31331..c6b744dd1bce3 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2552,12 +2552,22 @@ impl<'test> TestCx<'test> { let parent_dir = self.testpaths.file.parent().unwrap(); normalize_path(parent_dir, "$DIR"); + // After #51349, rustc normalizes `tests/x/y/../aux/foo.rs` to + // `tests/x/aux/foo.rs`. Replace the grandparent with `$DIR/..` so + // stderrs keep the pre-normalization form. + if let Some(grandparent_dir) = parent_dir.parent() { + normalize_path(grandparent_dir, "$DIR/.."); + } + if self.props.remap_src_base { let mut remapped_parent_dir = Utf8PathBuf::from(FAKE_SRC_BASE); if self.testpaths.relative_dir != Utf8Path::new("") { remapped_parent_dir.push(&self.testpaths.relative_dir); } normalize_path(&remapped_parent_dir, "$DIR"); + if let Some(remapped_grandparent) = remapped_parent_dir.parent() { + normalize_path(remapped_grandparent, "$DIR/.."); + } } let base_dir = Utf8Path::new("/rustc/FAKE_PREFIX"); diff --git a/tests/ui/README.md b/tests/ui/README.md index 27995e0ab4cd5..de6c2c62d75c7 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -445,6 +445,10 @@ Everything to do with `--diagnostic-width`. Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic attribute namespace](https://rust-lang.github.io/rfcs/3368-diagnostic-attribute-namespace.html). +## `tests/ui/diagnostics/` + +Tests for diagnostic output quality, such as path normalization in error messages. + ## `tests/ui/did_you_mean/` Tests for miscellaneous suggestions. diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index 164bcc7111ca6..6a2952604587e 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -5,7 +5,7 @@ LL | let y = Mask::<_, _>::splat(false); | ^ ------------ type must be known at this point | note: required by a const generic parameter in `Mask` - --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL + --> $SRC_DIR/portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the value of const parameter `N` is specified | LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); @@ -18,7 +18,7 @@ LL | let y = Mask::<_, _>::splat(false); | ^ -------------------------- type must be known at this point | note: required by a const generic parameter in `Mask::::splat` - --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL + --> $SRC_DIR/portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the value of const parameter `N` is specified | LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); diff --git a/tests/ui/diagnostics/auxiliary/helper.rs b/tests/ui/diagnostics/auxiliary/helper.rs new file mode 100644 index 0000000000000..83103ab7bd71f --- /dev/null +++ b/tests/ui/diagnostics/auxiliary/helper.rs @@ -0,0 +1,3 @@ +pub fn foo() -> u32 { + "not a u32" +} diff --git a/tests/ui/diagnostics/auxiliary/sub/mod.rs b/tests/ui/diagnostics/auxiliary/sub/mod.rs new file mode 100644 index 0000000000000..dd531abbce552 --- /dev/null +++ b/tests/ui/diagnostics/auxiliary/sub/mod.rs @@ -0,0 +1,2 @@ +#[path = "../helper.rs"] +mod helper; diff --git a/tests/ui/diagnostics/normalize-path.rs b/tests/ui/diagnostics/normalize-path.rs new file mode 100644 index 0000000000000..1b1fb998abf01 --- /dev/null +++ b/tests/ui/diagnostics/normalize-path.rs @@ -0,0 +1,9 @@ +// Verify that diagnostic file paths are lexically normalized. +// Without the fix for #51349, the error location would show +// `auxiliary/sub/../helper.rs` instead of `auxiliary/helper.rs`. +#[path = "auxiliary/sub/mod.rs"] +mod sub; + +fn main() {} + +//~? ERROR mismatched types diff --git a/tests/ui/diagnostics/normalize-path.stderr b/tests/ui/diagnostics/normalize-path.stderr new file mode 100644 index 0000000000000..9eb92e54853e1 --- /dev/null +++ b/tests/ui/diagnostics/normalize-path.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/auxiliary/helper.rs:2:5 + | +LL | pub fn foo() -> u32 { + | --- expected `u32` because of return type +LL | "not a u32" + | ^^^^^^^^^^^ expected `u32`, found `&str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From 9e00810a42202c7c7436f3f24539f2c0fb050a6f Mon Sep 17 00:00:00 2001 From: arferreira Date: Thu, 13 Aug 2026 19:41:20 -0400 Subject: [PATCH 2/6] Print unnormalized diagnostic paths under --verbose Signed-off-by: arferreira --- compiler/rustc_interface/src/interface.rs | 8 +++++++- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_span/src/source_map.rs | 20 +++++++++++++++++-- compiler/rustc_span/src/source_map/tests.rs | 17 ++++++++++++++++ .../ui/diagnostics/normalize-path-verbose.rs | 10 ++++++++++ .../diagnostics/normalize-path-verbose.stderr | 11 ++++++++++ tests/ui/diagnostics/normalize-path.rs | 6 +++--- 7 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 tests/ui/diagnostics/normalize-path-verbose.rs create mode 100644 tests/ui/diagnostics/normalize-path-verbose.stderr diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 7a6a49f37278a..7d1947f4c4d1c 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -410,7 +410,13 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.opts.edition, jobs, &config.extra_symbols, - SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }, + SourceMapInputs { + file_loader, + path_mapping, + hash_kind, + checksum_hash_kind, + verbose: config.opts.verbose, + }, |current_gcx| { // The previous `early_dcx` can't be reused here because it doesn't // impl `Send`. Creating a new one is fine. diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 34ac92faef88c..44d4bb6c8e075 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -56,6 +56,7 @@ where path_mapping: sessopts.file_path_mapping(), hash_kind, checksum_hash_kind, + verbose: sessopts.verbose, }); rustc_span::create_session_globals_then(DEFAULT_EDITION, &[], sm_inputs, || { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 2d1752f0edd07..5869a4bd34ed8 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -192,6 +192,7 @@ pub struct SourceMapInputs { pub path_mapping: FilePathMapping, pub hash_kind: SourceFileHashAlgorithm, pub checksum_hash_kind: Option, + pub verbose: bool, } pub struct SourceMap { @@ -213,6 +214,10 @@ pub struct SourceMap { /// /// If this is equal to `hash_kind` then the checksum won't be computed twice. checksum_hash_kind: Option, + + /// Whether `--verbose` was passed. Diagnostics then print paths without + /// lexical normalization. + verbose: bool, } impl std::fmt::Debug for SourceMap { @@ -224,6 +229,7 @@ impl std::fmt::Debug for SourceMap { working_dir, hash_kind, checksum_hash_kind, + verbose, } = self; f.debug_struct("SourceMap") @@ -233,6 +239,7 @@ impl std::fmt::Debug for SourceMap { .field("working_dir", working_dir) .field("hash_kind", hash_kind) .field("checksum_hash_kind", checksum_hash_kind) + .field("verbose", verbose) .finish() } } @@ -244,11 +251,12 @@ impl SourceMap { path_mapping, hash_kind: SourceFileHashAlgorithm::Md5, checksum_hash_kind: None, + verbose: false, }) } pub fn with_inputs( - SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }: SourceMapInputs, + SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind, verbose }: SourceMapInputs, ) -> SourceMap { let cwd = file_loader .current_directory() @@ -262,6 +270,7 @@ impl SourceMap { path_mapping, hash_kind, checksum_hash_kind, + verbose, } } @@ -520,8 +529,15 @@ impl SourceMap { self.lookup_char_pos(sp.lo()).file.name.clone() } + /// Paths are normalized lexically, which can name the wrong file if a + /// component is a symlink. `--verbose` skips normalization and prints the + /// path as given. pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> { - filename.display_normalized(RemapPathScopeComponents::DIAGNOSTICS) + if self.verbose { + filename.display(RemapPathScopeComponents::DIAGNOSTICS) + } else { + filename.display_normalized(RemapPathScopeComponents::DIAGNOSTICS) + } } pub fn is_multiline(&self, sp: Span) -> bool { diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index acc186a007fca..b97c96787a96b 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -808,3 +808,20 @@ fn filename_for_diagnostics_resolves_parent_dir() { let clean = filename(&sm, "tests/clean.rs"); assert_eq!(sm.filename_for_diagnostics(&clean).to_string(), path_str("tests/clean.rs")); } + +#[test] +fn filename_for_diagnostics_verbose_keeps_parent_dir() { + let sm = SourceMap::with_inputs(SourceMapInputs { + file_loader: Box::new(RealFileLoader), + path_mapping: FilePathMapping::empty(), + hash_kind: SourceFileHashAlgorithm::Md5, + checksum_hash_kind: None, + verbose: true, + }); + + let with_parent = filename(&sm, "tests/sub/../helper.rs"); + assert_eq!( + sm.filename_for_diagnostics(&with_parent).to_string(), + path_str("tests/sub/../helper.rs"), + ); +} diff --git a/tests/ui/diagnostics/normalize-path-verbose.rs b/tests/ui/diagnostics/normalize-path-verbose.rs new file mode 100644 index 0000000000000..8955ce10da98b --- /dev/null +++ b/tests/ui/diagnostics/normalize-path-verbose.rs @@ -0,0 +1,10 @@ +//@ compile-flags: --verbose + +// Check that `--verbose` prints diagnostic paths as given, without lexical +// normalization. See #51349. +#[path = "auxiliary/sub/mod.rs"] +mod sub; + +fn main() {} + +//~? ERROR mismatched types diff --git a/tests/ui/diagnostics/normalize-path-verbose.stderr b/tests/ui/diagnostics/normalize-path-verbose.stderr new file mode 100644 index 0000000000000..ef1c9416f46c1 --- /dev/null +++ b/tests/ui/diagnostics/normalize-path-verbose.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/auxiliary/sub/../helper.rs:2:5 + | +LL | pub fn foo() -> u32 { + | --- expected `u32` because of return type +LL | "not a u32" + | ^^^^^^^^^^^ expected `u32`, found `&str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostics/normalize-path.rs b/tests/ui/diagnostics/normalize-path.rs index 1b1fb998abf01..bc041c790e529 100644 --- a/tests/ui/diagnostics/normalize-path.rs +++ b/tests/ui/diagnostics/normalize-path.rs @@ -1,6 +1,6 @@ -// Verify that diagnostic file paths are lexically normalized. -// Without the fix for #51349, the error location would show -// `auxiliary/sub/../helper.rs` instead of `auxiliary/helper.rs`. +// Check that diagnostic file paths are lexically normalized: +// the error below points at `auxiliary/helper.rs`, not `auxiliary/sub/../helper.rs`. +// See #51349. #[path = "auxiliary/sub/mod.rs"] mod sub; From ff3c1596f0a5c469dbbd6a47633e90370734faa0 Mon Sep 17 00:00:00 2001 From: arferreira Date: Fri, 16 Oct 2026 18:10:02 -0400 Subject: [PATCH 3/6] Skip path normalization for paths without dot segments --- compiler/rustc_span/src/lib.rs | 10 +++++++++- compiler/rustc_span/src/source_map/tests.rs | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 36b1ced63fd4b..9692c81315b6f 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -503,11 +503,19 @@ impl RealFileName { FileNameDisplayPreference::Scope(scope) => self.path(scope).to_string_lossy(), FileNameDisplayPreference::Diagnostics(scope) => { let path = self.path(scope); + // Paths without `.` or `..` are returned unchanged. `normalize_lexically` + // rebuilds the path from components, which on Windows turns `/` into `\` + // and breaks remapped paths like `/rustc/\library\...`. + // The dot check is on the string since `components()` skips interior `.`. + let path_str = path.to_string_lossy(); + if !path_str.split(['/', '\\']).any(|seg| seg == "." || seg == "..") { + return path_str; + } match path.normalize_lexically() { Ok(normalized) => { Cow::Owned(normalized.into_os_string().to_string_lossy().into_owned()) } - Err(_) => path.to_string_lossy(), + Err(_) => path_str, } } } diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index b97c96787a96b..3113a7b93d94d 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -825,3 +825,13 @@ fn filename_for_diagnostics_verbose_keeps_parent_dir() { path_str("tests/sub/../helper.rs"), ); } + +#[test] +fn filename_for_diagnostics_keeps_separators_without_dot_segments() { + let sm = SourceMap::new(FilePathMapping::empty()); + // On Windows the remap prefix keeps `/` while the local part uses `\`. + // No dot segments, so the path must come back unchanged. + let path = "/rustc/FAKE_PREFIX\\library\\core\\src\\alloc\\layout.rs"; + let name = filename(&sm, path); + assert_eq!(sm.filename_for_diagnostics(&name).to_string(), path); +} From 8a8137612592a4c4474bed17546ffa58040f06a1 Mon Sep 17 00:00:00 2001 From: arferreira Date: Sun, 18 Oct 2026 11:11:02 -0400 Subject: [PATCH 4/6] Update no_delayed_bug stderr for path normalization --- tests/ui/abi/no_delayed_bug.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/abi/no_delayed_bug.stderr b/tests/ui/abi/no_delayed_bug.stderr index c21256b86a6c4..4fb45192b90e3 100644 --- a/tests/ui/abi/no_delayed_bug.stderr +++ b/tests/ui/abi/no_delayed_bug.stderr @@ -1,5 +1,5 @@ error: the SIMD type `Simd` has more elements than the limit 64 - --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:COL + --> $SRC_DIR/portable-simd/crates/core_simd/src/vector.rs:LL:COL note: the above error was encountered while instantiating `fn Simd::::splat` --> $DIR/no_delayed_bug.rs:13:17 From a8169380a63bf61857c6791fc0857c41ee2ab58a Mon Sep 17 00:00:00 2001 From: arferreira Date: Mon, 19 Oct 2026 09:53:59 -0400 Subject: [PATCH 5/6] Fix Windows path separator expectations in rustc_span tests --- compiler/rustc_span/src/source_map/tests.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 3113a7b93d94d..715464e13b19e 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -805,8 +805,9 @@ fn filename_for_diagnostics_resolves_parent_dir() { let with_parent = filename(&sm, "tests/sub/../helper.rs"); assert_eq!(sm.filename_for_diagnostics(&with_parent).to_string(), path_str("tests/helper.rs")); + // No dot segments, so the path comes back verbatim, separators included. let clean = filename(&sm, "tests/clean.rs"); - assert_eq!(sm.filename_for_diagnostics(&clean).to_string(), path_str("tests/clean.rs")); + assert_eq!(sm.filename_for_diagnostics(&clean).to_string(), "tests/clean.rs"); } #[test] @@ -820,10 +821,7 @@ fn filename_for_diagnostics_verbose_keeps_parent_dir() { }); let with_parent = filename(&sm, "tests/sub/../helper.rs"); - assert_eq!( - sm.filename_for_diagnostics(&with_parent).to_string(), - path_str("tests/sub/../helper.rs"), - ); + assert_eq!(sm.filename_for_diagnostics(&with_parent).to_string(), "tests/sub/../helper.rs",); } #[test] From 0214f233f569fbd2f0caa2259d62bf19fff91742 Mon Sep 17 00:00:00 2001 From: arferreira Date: Wed, 21 Oct 2026 09:32:50 -0400 Subject: [PATCH 6/6] Skip path normalization for remapped diagnostic paths --- compiler/rustc_span/src/lib.rs | 13 +++++++++---- compiler/rustc_span/src/source_map.rs | 6 +++--- compiler/rustc_span/src/source_map/tests.rs | 16 ++++++++++++++++ tests/ui/abi/no_delayed_bug.stderr | 2 +- .../generic_arg_infer/issue-91614.stderr | 4 ++-- 5 files changed, 31 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9692c81315b6f..d0bf7b9af9fcb 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -502,11 +502,16 @@ impl RealFileName { .map_or_else(|| "".into(), |f| f.to_string_lossy()), FileNameDisplayPreference::Scope(scope) => self.path(scope).to_string_lossy(), FileNameDisplayPreference::Diagnostics(scope) => { + // Remapped names are printed as given: rebuilding them from components + // re-separates synthetic prefixes on Windows (`/rustc/` becomes + // `\rustc\`), changing output `--remap-path-prefix` users depend on. + if self.scopes.contains(scope) { + return self.path(scope).to_string_lossy(); + } let path = self.path(scope); - // Paths without `.` or `..` are returned unchanged. `normalize_lexically` - // rebuilds the path from components, which on Windows turns `/` into `\` - // and breaks remapped paths like `/rustc/\library\...`. - // The dot check is on the string since `components()` skips interior `.`. + // Paths without `.` or `..` are returned unchanged, so their separators + // are not rewritten by a component rebuild. The dot check is on the + // string since `components()` skips interior `.`. let path_str = path.to_string_lossy(); if !path_str.split(['/', '\\']).any(|seg| seg == "." || seg == "..") { return path_str; diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 5869a4bd34ed8..5ddac209518f9 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -529,9 +529,9 @@ impl SourceMap { self.lookup_char_pos(sp.lo()).file.name.clone() } - /// Paths are normalized lexically, which can name the wrong file if a - /// component is a symlink. `--verbose` skips normalization and prints the - /// path as given. + /// Local paths are normalized lexically, which can name the wrong file if + /// a component is a symlink. Remapped paths and `--verbose` skip + /// normalization and print the path as given. pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> { if self.verbose { filename.display(RemapPathScopeComponents::DIAGNOSTICS) diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 715464e13b19e..682cb0b52886f 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -833,3 +833,19 @@ fn filename_for_diagnostics_keeps_separators_without_dot_segments() { let name = filename(&sm, path); assert_eq!(sm.filename_for_diagnostics(&name).to_string(), path); } + +#[test] +fn filename_for_diagnostics_keeps_remapped_dot_segments() { + let mapping = FilePathMapping::new( + vec![(path("abc/def"), path("fake"))], + RemapPathScopeComponents::all(), + ); + let sm = SourceMap::new(mapping); + + // The remapped name prints as given, `..` included. + let remapped = filename(&sm, "abc/def/sub/../helper.rs"); + assert_eq!( + sm.filename_for_diagnostics(&remapped).to_string(), + path_str("fake/sub/../helper.rs"), + ); +} diff --git a/tests/ui/abi/no_delayed_bug.stderr b/tests/ui/abi/no_delayed_bug.stderr index 4fb45192b90e3..c21256b86a6c4 100644 --- a/tests/ui/abi/no_delayed_bug.stderr +++ b/tests/ui/abi/no_delayed_bug.stderr @@ -1,5 +1,5 @@ error: the SIMD type `Simd` has more elements than the limit 64 - --> $SRC_DIR/portable-simd/crates/core_simd/src/vector.rs:LL:COL + --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:COL note: the above error was encountered while instantiating `fn Simd::::splat` --> $DIR/no_delayed_bug.rs:13:17 diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index 6a2952604587e..164bcc7111ca6 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -5,7 +5,7 @@ LL | let y = Mask::<_, _>::splat(false); | ^ ------------ type must be known at this point | note: required by a const generic parameter in `Mask` - --> $SRC_DIR/portable-simd/crates/core_simd/src/masks.rs:LL:COL + --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the value of const parameter `N` is specified | LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); @@ -18,7 +18,7 @@ LL | let y = Mask::<_, _>::splat(false); | ^ -------------------------- type must be known at this point | note: required by a const generic parameter in `Mask::::splat` - --> $SRC_DIR/portable-simd/crates/core_simd/src/masks.rs:LL:COL + --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the value of const parameter `N` is specified | LL | let y: Mask<_, N> = Mask::<_, _>::splat(false);