about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJacob Pratt <jacob@jhpratt.dev>2024-04-26 19:25:57 -0400
committerGitHub <noreply@github.com>2024-04-26 19:25:57 -0400
commit7cbba53396610b7f0d98b6bacb6ee03838077e5d (patch)
treec175dea9a0ae688f57fcca0aa134002740de9589
parent7cb7337c1b59c5cbb9f09d3175736f5051f4b5bf (diff)
parentc47978a241ac1dd512b2ed7d146c1e1a71326dec (diff)
downloadrust-7cbba53396610b7f0d98b6bacb6ee03838077e5d.tar.gz
rust-7cbba53396610b7f0d98b6bacb6ee03838077e5d.zip
Rollup merge of #124410 - RalfJung:path-buf-transmute, r=Nilstrieb
PathBuf: replace transmuting by accessor functions

The existing `repr(transparent)` was anyway insufficient as `OsString` was not `repr(transparent)`. And furthermore, on Windows it was blatantly wrong as `OsString` wraps `Wtf8Buf` which is a `repr(Rust)` type with 2 fields:

https://github.com/rust-lang/rust/blob/51a7396ad3d78d9326ee1537b9ff29ab3919556f/library/std/src/sys_common/wtf8.rs#L131-L146

So let's just be honest about what happens and add accessor methods that make this abstraction-breaking act of PathBuf visible on the APIs that it pierces through.

Fixes https://github.com/rust-lang/rust/issues/124409
-rw-r--r--library/std/src/ffi/os_str.rs6
-rw-r--r--library/std/src/path.rs8
-rw-r--r--library/std/src/sys/os_str/bytes.rs6
-rw-r--r--library/std/src/sys/os_str/wtf8.rs6
-rw-r--r--library/std/src/sys_common/wtf8.rs6
5 files changed, 25 insertions, 7 deletions
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 20ebe1c4f8a..9dd3d7d3fa1 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -532,6 +532,12 @@ impl OsString {
         let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr;
         unsafe { Box::from_raw(rw) }
     }
+
+    /// Part of a hack to make PathBuf::push/pop more efficient.
+    #[inline]
+    pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {
+        self.inner.as_mut_vec_for_path_buf()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 1c58671a0cf..85355435100 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1158,12 +1158,6 @@ impl FusedIterator for Ancestors<'_> {}
 /// Which method works best depends on what kind of situation you're in.
 #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")]
 #[stable(feature = "rust1", since = "1.0.0")]
-// `PathBuf::as_mut_vec` current implementation relies
-// on `PathBuf` being layout-compatible with `Vec<u8>`.
-// However, `PathBuf` layout is considered an implementation detail and must not be relied upon. We
-// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
-// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
-#[cfg_attr(not(doc), repr(transparent))]
 pub struct PathBuf {
     inner: OsString,
 }
@@ -1171,7 +1165,7 @@ pub struct PathBuf {
 impl PathBuf {
     #[inline]
     fn as_mut_vec(&mut self) -> &mut Vec<u8> {
-        unsafe { &mut *(self as *mut PathBuf as *mut Vec<u8>) }
+        self.inner.as_mut_vec_for_path_buf()
     }
 
     /// Allocates an empty `PathBuf`.
diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs
index 9be02bc191e..18b969bca85 100644
--- a/library/std/src/sys/os_str/bytes.rs
+++ b/library/std/src/sys/os_str/bytes.rs
@@ -196,6 +196,12 @@ impl Buf {
     pub fn into_rc(&self) -> Rc<Slice> {
         self.as_slice().into_rc()
     }
+
+    /// Part of a hack to make PathBuf::push/pop more efficient.
+    #[inline]
+    pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {
+        &mut self.inner
+    }
 }
 
 impl Slice {
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index 352bd735903..b3ceb55802d 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -158,6 +158,12 @@ impl Buf {
     pub fn into_rc(&self) -> Rc<Slice> {
         self.as_slice().into_rc()
     }
+
+    /// Part of a hack to make PathBuf::push/pop more efficient.
+    #[inline]
+    pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {
+        self.inner.as_mut_vec_for_path_buf()
+    }
 }
 
 impl Slice {
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 2dbd19d7171..38e15f9f549 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -468,6 +468,12 @@ impl Wtf8Buf {
         let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) };
         Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false }
     }
+
+    /// Part of a hack to make PathBuf::push/pop more efficient.
+    #[inline]
+    pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {
+        &mut self.bytes
+    }
 }
 
 /// Creates a new WTF-8 string from an iterator of code points.