Skip to content

Commit b0cb45e

Browse files
committed
Normalize .. and . in diagnostic file paths
1 parent 14196db commit b0cb45e

12 files changed

Lines changed: 88 additions & 23 deletions

File tree

compiler/rustc_span/src/lib.rs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#![feature(core_io_borrowed_buf)]
2222
#![feature(map_try_insert)]
2323
#![feature(negative_impls)]
24+
#![feature(normalize_lexically)]
2425
#![feature(read_buf)]
2526
#![feature(rustc_attrs)]
2627
// tidy-alphabetical-end
@@ -496,6 +497,15 @@ impl RealFileName {
496497
.file_name()
497498
.map_or_else(|| "".into(), |f| f.to_string_lossy()),
498499
FileNameDisplayPreference::Scope(scope) => self.path(scope).to_string_lossy(),
500+
FileNameDisplayPreference::Diagnostics(scope) => {
501+
let path = self.path(scope);
502+
match path.normalize_lexically() {
503+
Ok(normalized) => {
504+
Cow::Owned(normalized.into_os_string().to_string_lossy().into_owned())
505+
}
506+
Err(_) => path.to_string_lossy(),
507+
}
508+
}
499509
}
500510
}
501511
}
@@ -533,15 +543,23 @@ enum FileNameDisplayPreference {
533543
Local,
534544
Short,
535545
Scope(RemapPathScopeComponents),
546+
Diagnostics(RemapPathScopeComponents),
547+
}
548+
549+
impl<'a> FileNameDisplay<'a> {
550+
pub fn to_string_lossy(&self) -> Cow<'a, str> {
551+
match self.inner {
552+
FileName::Real(inner) => inner.to_string_lossy(self.display_pref),
553+
_ => Cow::from(self.to_string()),
554+
}
555+
}
536556
}
537557

538558
impl fmt::Display for FileNameDisplay<'_> {
539559
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
540560
use FileName::*;
541561
match *self.inner {
542-
Real(ref name) => {
543-
write!(fmt, "{}", name.to_string_lossy(self.display_pref))
544-
}
562+
Real(ref name) => write!(fmt, "{}", name.to_string_lossy(self.display_pref)),
545563
CfgSpec(_) => write!(fmt, "<cfgspec>"),
546564
MacroExpansion(_) => write!(fmt, "<macro expansion>"),
547565
Anon(_) => write!(fmt, "<anon>"),
@@ -554,15 +572,6 @@ impl fmt::Display for FileNameDisplay<'_> {
554572
}
555573
}
556574

557-
impl<'a> FileNameDisplay<'a> {
558-
pub fn to_string_lossy(&self) -> Cow<'a, str> {
559-
match self.inner {
560-
FileName::Real(inner) => inner.to_string_lossy(self.display_pref),
561-
_ => Cow::from(self.to_string()),
562-
}
563-
}
564-
}
565-
566575
impl FileName {
567576
pub fn is_real(&self) -> bool {
568577
use FileName::*;
@@ -609,6 +618,12 @@ impl FileName {
609618
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Scope(scope) }
610619
}
611620

621+
/// Like `display`, but with `.` and `..` resolved lexically. See #51349.
622+
#[inline]
623+
pub fn display_normalized(&self, scope: RemapPathScopeComponents) -> FileNameDisplay<'_> {
624+
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Diagnostics(scope) }
625+
}
626+
612627
pub fn macro_expansion_source_code(src: &str) -> FileName {
613628
let mut hasher = StableHasher::new();
614629
src.hash(&mut hasher);

compiler/rustc_span/src/source_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ impl SourceMap {
487487
}
488488

489489
pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> {
490-
filename.display(RemapPathScopeComponents::DIAGNOSTICS)
490+
filename.display_normalized(RemapPathScopeComponents::DIAGNOSTICS)
491491
}
492492

493493
pub fn is_multiline(&self, sp: Span) -> bool {

compiler/rustc_span/src/source_map/tests.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,3 +797,14 @@ fn read_binary_file_handles_lying_stat() {
797797
let bin = RealFileLoader.read_binary_file(kernel_max).unwrap();
798798
assert_eq!(&real[..], &bin[..]);
799799
}
800+
801+
#[test]
802+
fn filename_for_diagnostics_resolves_parent_dir() {
803+
let sm = SourceMap::new(FilePathMapping::empty());
804+
805+
let with_parent = filename(&sm, "tests/sub/../helper.rs");
806+
assert_eq!(sm.filename_for_diagnostics(&with_parent).to_string(), path_str("tests/helper.rs"));
807+
808+
let clean = filename(&sm, "tests/clean.rs");
809+
assert_eq!(sm.filename_for_diagnostics(&clean).to_string(), path_str("tests/clean.rs"));
810+
}

src/tools/compiletest/src/runtest.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2485,12 +2485,22 @@ impl<'test> TestCx<'test> {
24852485
let parent_dir = self.testpaths.file.parent().unwrap();
24862486
normalize_path(parent_dir, "$DIR");
24872487

2488+
// After #51349, rustc normalizes `tests/x/y/../aux/foo.rs` to
2489+
// `tests/x/aux/foo.rs`. Replace the grandparent with `$DIR/..` so
2490+
// stderrs keep the pre-normalization form.
2491+
if let Some(grandparent_dir) = parent_dir.parent() {
2492+
normalize_path(grandparent_dir, "$DIR/..");
2493+
}
2494+
24882495
if self.props.remap_src_base {
24892496
let mut remapped_parent_dir = Utf8PathBuf::from(FAKE_SRC_BASE);
24902497
if self.testpaths.relative_dir != Utf8Path::new("") {
24912498
remapped_parent_dir.push(&self.testpaths.relative_dir);
24922499
}
24932500
normalize_path(&remapped_parent_dir, "$DIR");
2501+
if let Some(remapped_grandparent) = remapped_parent_dir.parent() {
2502+
normalize_path(remapped_grandparent, "$DIR/..");
2503+
}
24942504
}
24952505

24962506
let base_dir = Utf8Path::new("/rustc/FAKE_PREFIX");

tests/ui/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,10 @@ Everything to do with `--diagnostic-width`.
440440

441441
Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic attribute namespace](https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md).
442442

443+
## `tests/ui/diagnostics/`
444+
445+
Tests for diagnostic output quality, such as path normalization in error messages.
446+
443447
## `tests/ui/did_you_mean/`
444448

445449
Tests for miscellaneous suggestions.

tests/ui/const-generics/generic_arg_infer/issue-91614.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | let y = Mask::<_, _>::splat(false);
55
| ^ ------------ type must be known at this point
66
|
77
note: required by a const generic parameter in `Mask`
8-
--> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL
8+
--> $SRC_DIR/portable-simd/crates/core_simd/src/masks.rs:LL:COL
99
help: consider giving `y` an explicit type, where the value of const parameter `N` is specified
1010
|
1111
LL | let y: Mask<_, N> = Mask::<_, _>::splat(false);
@@ -18,7 +18,7 @@ LL | let y = Mask::<_, _>::splat(false);
1818
| ^ -------------------------- type must be known at this point
1919
|
2020
note: required by a const generic parameter in `Mask::<T, N>::splat`
21-
--> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL
21+
--> $SRC_DIR/portable-simd/crates/core_simd/src/masks.rs:LL:COL
2222
help: consider giving `y` an explicit type, where the value of const parameter `N` is specified
2323
|
2424
LL | let y: Mask<_, N> = Mask::<_, _>::splat(false);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub fn foo() -> u32 {
2+
"not a u32"
3+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#[path = "../helper.rs"]
2+
mod helper;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Verify that diagnostic file paths are lexically normalized.
2+
// Without the fix for #51349, the error location would show
3+
// `auxiliary/sub/../helper.rs` instead of `auxiliary/helper.rs`.
4+
#[path = "auxiliary/sub/mod.rs"]
5+
mod sub;
6+
7+
fn main() {}
8+
9+
//~? ERROR mismatched types
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/auxiliary/helper.rs:2:5
3+
|
4+
LL | pub fn foo() -> u32 {
5+
| --- expected `u32` because of return type
6+
LL | "not a u32"
7+
| ^^^^^^^^^^^ expected `u32`, found `&str`
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)