diff --git a/library/std/src/path.rs b/library/std/src/path.rs index e540f86016038..4c86466392256 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2920,12 +2920,12 @@ impl cmp::PartialEq for Path { impl Hash for Path { fn hash(&self, h: &mut H) { let bytes = self.as_u8_slice(); - let prefix_len = match parse_prefix(&self.inner) { + let (prefix_len, verbatim) = match parse_prefix(&self.inner) { Some(prefix) => { prefix.hash(h); - prefix.len() + (prefix.len(), prefix.is_verbatim()) } - None => 0, + None => (0, false), }; let bytes = &bytes[prefix_len..]; @@ -2933,7 +2933,8 @@ impl Hash for Path { let mut bytes_hashed = 0; for i in 0..bytes.len() { - if is_sep_byte(bytes[i]) { + let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) }; + if is_sep { if i > component_start { let to_hash = &bytes[component_start..i]; h.write(to_hash); @@ -2941,11 +2942,18 @@ impl Hash for Path { } // skip over separator and optionally a following CurDir item - // since components() would normalize these away - component_start = i + match bytes[i..] { - [_, b'.', b'/', ..] | [_, b'.'] => 2, - _ => 1, - }; + // since components() would normalize these away. + component_start = i + 1; + + let tail = &bytes[component_start..]; + + if !verbatim { + component_start += match tail { + [b'.'] => 1, + [b'.', sep @ _, ..] if is_sep_byte(*sep) => 1, + _ => 0, + }; + } } } diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 2bf499e1ab823..0ab5956e1bc6b 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1498,6 +1498,20 @@ pub fn test_compare() { relative_from: Some("") ); + tc!("foo/.", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo/./bar", "foo/bar", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + tc!("foo/bar", "foo", eq: false, starts_with: true, @@ -1541,6 +1555,27 @@ pub fn test_compare() { ends_with: true, relative_from: Some("") ); + + tc!(r"C:\foo\.\bar.txt", r"C:\foo\bar.txt", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!(r"C:\foo\.", r"C:\foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!(r"\\?\C:\foo\.\bar.txt", r"\\?\C:\foo\bar.txt", + eq: false, + starts_with: false, + ends_with: false, + relative_from: None + ); } } diff --git a/src/test/ui/issues/issue-23036.rs b/src/test/ui/issues/issue-23036.rs index d67f184720e6c..ac24648e49e91 100644 --- a/src/test/ui/issues/issue-23036.rs +++ b/src/test/ui/issues/issue-23036.rs @@ -1,4 +1,5 @@ // run-pass +// ignore-wasm32-bare FIXME(#93923) llvm miscompilation use std::collections::HashMap; use std::path::Path;