about summary refs log tree commit diff
path: root/library/alloc/src
diff options
context:
space:
mode:
authorLaurențiu Nicola <lnicola@dend.ro>2024-10-08 14:25:39 +0300
committerLaurențiu Nicola <lnicola@dend.ro>2024-10-08 14:25:39 +0300
commit4316afffd9390bdac1d3bd5e5398c65d6e9bb150 (patch)
tree9d5b39941405bec4b7c4571606df8b88850325e9 /library/alloc/src
parent537fb8d1bb2405b118898c663bc076815a1762c7 (diff)
parentcf24c73141a77db730f4b7fda69dcd7e8b113b51 (diff)
Merge from rust-lang/rust
Diffstat (limited to 'library/alloc/src')
-rw-r--r--library/alloc/src/boxed.rs11
-rw-r--r--library/alloc/src/boxed/thin.rs2
-rw-r--r--library/alloc/src/collections/binary_heap/mod.rs5
-rw-r--r--library/alloc/src/collections/btree/node.rs10
-rw-r--r--library/alloc/src/ffi/c_str.rs1
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/raw_vec.rs12
-rw-r--r--library/alloc/src/rc.rs26
-rw-r--r--library/alloc/src/slice.rs67
-rw-r--r--library/alloc/src/str.rs129
-rw-r--r--library/alloc/src/string.rs38
-rw-r--r--library/alloc/src/sync.rs23
-rw-r--r--library/alloc/src/vec/into_iter.rs4
-rw-r--r--library/alloc/src/vec/mod.rs55
14 files changed, 242 insertions, 142 deletions
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index f61a484499f..5f207295683 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -199,7 +199,7 @@ use core::ops::{
     DerefPure, DispatchFromDyn, Receiver,
 };
 use core::pin::{Pin, PinCoerceUnsized};
-use core::ptr::{self, NonNull, Unique, addr_of_mut};
+use core::ptr::{self, NonNull, Unique};
 use core::task::{Context, Poll};
 use core::{borrow, fmt, slice};
 
@@ -228,6 +228,7 @@ mod thin;
 #[lang = "owned_box"]
 #[fundamental]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 // The declaration of the `Box` struct must be kept in sync with the
 // compiler or ICEs will happen.
 pub struct Box<
@@ -1277,7 +1278,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     #[inline]
     pub fn into_raw(b: Self) -> *mut T {
         // Make sure Miri realizes that we transition from a noalias pointer to a raw pointer here.
-        unsafe { addr_of_mut!(*&mut *Self::into_raw_with_allocator(b).0) }
+        unsafe { &raw mut *&mut *Self::into_raw_with_allocator(b).0 }
     }
 
     /// Consumes the `Box`, returning a wrapped `NonNull` pointer.
@@ -1396,7 +1397,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
         // want *no* aliasing requirements here!
         // In case `A` *is* `Global`, this does not quite have the right behavior; `into_raw`
         // works around that.
-        let ptr = addr_of_mut!(**b);
+        let ptr = &raw mut **b;
         let alloc = unsafe { ptr::read(&b.1) };
         (ptr, alloc)
     }
@@ -1506,7 +1507,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     pub fn as_mut_ptr(b: &mut Self) -> *mut T {
         // This is a primitive deref, not going through `DerefMut`, and therefore not materializing
         // any references.
-        ptr::addr_of_mut!(**b)
+        &raw mut **b
     }
 
     /// Returns a raw pointer to the `Box`'s contents.
@@ -1554,7 +1555,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     pub fn as_ptr(b: &Self) -> *const T {
         // This is a primitive deref, not going through `DerefMut`, and therefore not materializing
         // any references.
-        ptr::addr_of!(**b)
+        &raw const **b
     }
 
     /// Returns a reference to the underlying allocator.
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index 9baded3a521..78e5aec09b1 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -186,7 +186,7 @@ impl<T: ?Sized> ThinBox<T> {
 
     fn with_header(&self) -> &WithHeader<<T as Pointee>::Metadata> {
         // SAFETY: both types are transparent to `NonNull<u8>`
-        unsafe { &*(core::ptr::addr_of!(self.ptr) as *const WithHeader<_>) }
+        unsafe { &*((&raw const self.ptr) as *const WithHeader<_>) }
     }
 }
 
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 5e59abf54ee..59f10b09c73 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -374,7 +374,10 @@ impl<'a, T: Ord, A: Allocator> PeekMut<'a, T, A> {
             // the caller could've mutated the element. It is removed from the
             // heap on the next line and pop() is not sensitive to its value.
         }
-        this.heap.pop().unwrap()
+
+        // SAFETY: Have a `PeekMut` element proves that the associated binary heap being non-empty,
+        // so the `pop` operation will not fail.
+        unsafe { this.heap.pop().unwrap_unchecked() }
     }
 }
 
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 78ccb3af66d..5c513d34fc9 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -72,8 +72,8 @@ impl<K, V> LeafNode<K, V> {
         // be both slightly faster and easier to track in Valgrind.
         unsafe {
             // parent_idx, keys, and vals are all MaybeUninit
-            ptr::addr_of_mut!((*this).parent).write(None);
-            ptr::addr_of_mut!((*this).len).write(0);
+            (&raw mut (*this).parent).write(None);
+            (&raw mut (*this).len).write(0);
         }
     }
 
@@ -114,7 +114,7 @@ impl<K, V> InternalNode<K, V> {
         unsafe {
             let mut node = Box::<Self, _>::new_uninit_in(alloc);
             // We only need to initialize the data; the edges are MaybeUninit.
-            LeafNode::init(ptr::addr_of_mut!((*node.as_mut_ptr()).data));
+            LeafNode::init(&raw mut (*node.as_mut_ptr()).data);
             node.assume_init()
         }
     }
@@ -525,8 +525,8 @@ impl<'a, K, V, Type> NodeRef<marker::ValMut<'a>, K, V, Type> {
         // to avoid aliasing with outstanding references to other elements,
         // in particular, those returned to the caller in earlier iterations.
         let leaf = Self::as_leaf_ptr(&mut self);
-        let keys = unsafe { ptr::addr_of!((*leaf).keys) };
-        let vals = unsafe { ptr::addr_of_mut!((*leaf).vals) };
+        let keys = unsafe { &raw const (*leaf).keys };
+        let vals = unsafe { &raw mut (*leaf).vals };
         // We must coerce to unsized array pointers because of Rust issue #74679.
         let keys: *const [_] = keys;
         let vals: *mut [_] = vals;
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index 797d591a8b5..d496899e72b 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -696,6 +696,7 @@ impl CString {
 // memory-unsafe code from working by accident. Inline
 // to prevent LLVM from optimizing it away in debug builds.
 #[stable(feature = "cstring_drop", since = "1.13.0")]
+#[rustc_insignificant_dtor]
 impl Drop for CString {
     #[inline]
     fn drop(&mut self) {
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index ff5ddd16e07..c60c0743c7e 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -115,6 +115,7 @@
 #![feature(const_option)]
 #![feature(const_pin)]
 #![feature(const_size_of_val)]
+#![feature(const_vec_string_slice)]
 #![feature(core_intrinsics)]
 #![feature(deprecated_suggestion)]
 #![feature(deref_pure_trait)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 436e0596e3d..8fdca8c4200 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -280,7 +280,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
     /// be careful.
     #[inline]
-    pub fn ptr(&self) -> *mut T {
+    pub const fn ptr(&self) -> *mut T {
         self.inner.ptr()
     }
 
@@ -293,7 +293,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     ///
     /// This will always be `usize::MAX` if `T` is zero-sized.
     #[inline]
-    pub fn capacity(&self) -> usize {
+    pub const fn capacity(&self) -> usize {
         self.inner.capacity(size_of::<T>())
     }
 
@@ -488,17 +488,17 @@ impl<A: Allocator> RawVecInner<A> {
     }
 
     #[inline]
-    fn ptr<T>(&self) -> *mut T {
+    const fn ptr<T>(&self) -> *mut T {
         self.non_null::<T>().as_ptr()
     }
 
     #[inline]
-    fn non_null<T>(&self) -> NonNull<T> {
-        self.ptr.cast().into()
+    const fn non_null<T>(&self) -> NonNull<T> {
+        self.ptr.cast().as_non_null_ptr()
     }
 
     #[inline]
-    fn capacity(&self, elem_size: usize) -> usize {
+    const fn capacity(&self, elem_size: usize) -> usize {
         if elem_size == 0 { usize::MAX } else { self.cap.0 }
     }
 
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 54669bd310a..0e2c35845e8 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -787,7 +787,7 @@ impl<T, A: Allocator> Rc<T, A> {
 
         let strong = unsafe {
             let inner = init_ptr.as_ptr();
-            ptr::write(ptr::addr_of_mut!((*inner).value), data);
+            ptr::write(&raw mut (*inner).value, data);
 
             let prev_value = (*inner).strong.get();
             debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
@@ -1442,7 +1442,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
         // SAFETY: This cannot go through Deref::deref or Rc::inner because
         // this is required to retain raw/mut provenance such that e.g. `get_mut` can
         // write through the pointer after the Rc is recovered through `from_raw`.
-        unsafe { ptr::addr_of_mut!((*ptr).value) }
+        unsafe { &raw mut (*ptr).value }
     }
 
     /// Constructs an `Rc<T, A>` from a raw pointer in the provided allocator.
@@ -2042,8 +2042,8 @@ impl<T: ?Sized> Rc<T> {
         unsafe {
             debug_assert_eq!(Layout::for_value_raw(inner), layout);
 
-            ptr::addr_of_mut!((*inner).strong).write(Cell::new(1));
-            ptr::addr_of_mut!((*inner).weak).write(Cell::new(1));
+            (&raw mut (*inner).strong).write(Cell::new(1));
+            (&raw mut (*inner).weak).write(Cell::new(1));
         }
 
         Ok(inner)
@@ -2072,8 +2072,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
 
             // Copy value as bytes
             ptr::copy_nonoverlapping(
-                core::ptr::addr_of!(*src) as *const u8,
-                ptr::addr_of_mut!((*ptr).value) as *mut u8,
+                (&raw const *src) as *const u8,
+                (&raw mut (*ptr).value) as *mut u8,
                 value_size,
             );
 
@@ -2107,11 +2107,7 @@ impl<T> Rc<[T]> {
     unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {
         unsafe {
             let ptr = Self::allocate_for_slice(v.len());
-            ptr::copy_nonoverlapping(
-                v.as_ptr(),
-                ptr::addr_of_mut!((*ptr).value) as *mut T,
-                v.len(),
-            );
+            ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).value) as *mut T, v.len());
             Self::from_ptr(ptr)
         }
     }
@@ -2149,7 +2145,7 @@ impl<T> Rc<[T]> {
             let layout = Layout::for_value_raw(ptr);
 
             // Pointer to first element
-            let elems = ptr::addr_of_mut!((*ptr).value) as *mut T;
+            let elems = (&raw mut (*ptr).value) as *mut T;
 
             let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
 
@@ -2577,7 +2573,7 @@ impl<T: ?Sized + fmt::Debug, A: Allocator> fmt::Debug for Rc<T, A> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized, A: Allocator> fmt::Pointer for Rc<T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f)
+        fmt::Pointer::fmt(&(&raw const **self), f)
     }
 }
 
@@ -2718,7 +2714,7 @@ impl<T, A: Allocator> From<Vec<T, A>> for Rc<[T], A> {
             let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
 
             let rc_ptr = Self::allocate_for_slice_in(len, &alloc);
-            ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).value) as *mut T, len);
+            ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len);
 
             // Create a `Vec<T, &A>` with length 0, to deallocate the buffer
             // without dropping its contents or the allocator
@@ -3084,7 +3080,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
             // SAFETY: if is_dangling returns false, then the pointer is dereferenceable.
             // The payload may be dropped at this point, and we have to maintain provenance,
             // so use raw pointer manipulation.
-            unsafe { ptr::addr_of_mut!((*ptr).value) }
+            unsafe { &raw mut (*ptr).value }
         }
     }
 
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index f636f10d5c0..a92d22b1c30 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -180,10 +180,9 @@ impl<T> [T] {
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
     ///
-    /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting
-    /// order of elements in the slice is unspecified. All original elements will remain in the
-    /// slice and any possible modifications via interior mutability are observed in the input. Same
-    /// is true if the implementation of [`Ord`] for `T` panics.
+    /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
     ///
     /// When applicable, unstable sorting is preferred because it is generally faster than stable
     /// sorting and it doesn't allocate auxiliary memory. See
@@ -212,7 +211,15 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if
+    /// the [`Ord`] implementation itself panics.
+    ///
+    /// All safe functions on slices preserve the invariant that even if the function panics, all
+    /// original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. This ensures that recovery code (for instance inside
+    /// of a `Drop` or following a `catch_unwind`) will still have access to all the original
+    /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able
+    /// to dispose of all contained elements.
     ///
     /// # Examples
     ///
@@ -241,10 +248,9 @@ impl<T> [T] {
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
     ///
-    /// If the comparison function `compare` does not implement a [total order] the resulting order
-    /// of elements in the slice is unspecified. All original elements will remain in the slice and
-    /// any possible modifications via interior mutability are observed in the input. Same is true
-    /// if `compare` panics.
+    /// If the comparison function `compare` does not implement a [total order], the function may
+    /// panic; even if the function exits normally, the resulting order of elements in the slice is
+    /// unspecified. See also the note on panicking below.
     ///
     /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
     /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
@@ -263,7 +269,14 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if `compare` does not implement a [total order].
+    /// May panic if `compare` does not implement a [total order], or if `compare` itself panics.
+    ///
+    /// All safe functions on slices preserve the invariant that even if the function panics, all
+    /// original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. This ensures that recovery code (for instance inside
+    /// of a `Drop` or following a `catch_unwind`) will still have access to all the original
+    /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able
+    /// to dispose of all contained elements.
     ///
     /// # Examples
     ///
@@ -295,10 +308,9 @@ impl<T> [T] {
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*))
     /// worst-case, where the key function is *O*(*m*).
     ///
-    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
-    /// order of elements in the slice is unspecified. All original elements will remain in the
-    /// slice and any possible modifications via interior mutability are observed in the input. Same
-    /// is true if the implementation of [`Ord`] for `K` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
     ///
     /// # Current implementation
     ///
@@ -313,7 +325,15 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if
+    /// the [`Ord`] implementation or the key-function `f` panics.
+    ///
+    /// All safe functions on slices preserve the invariant that even if the function panics, all
+    /// original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. This ensures that recovery code (for instance inside
+    /// of a `Drop` or following a `catch_unwind`) will still have access to all the original
+    /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able
+    /// to dispose of all contained elements.
     ///
     /// # Examples
     ///
@@ -347,10 +367,9 @@ impl<T> [T] {
     /// storage to remember the results of key evaluation. The order of calls to the key function is
     /// unspecified and may change in future versions of the standard library.
     ///
-    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
-    /// order of elements in the slice is unspecified. All original elements will remain in the
-    /// slice and any possible modifications via interior mutability are observed in the input. Same
-    /// is true if the implementation of [`Ord`] for `K` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
     ///
     /// For simple key functions (e.g., functions that are property accesses or basic operations),
     /// [`sort_by_key`](slice::sort_by_key) is likely to be faster.
@@ -369,7 +388,15 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if
+    /// the [`Ord`] implementation panics.
+    ///
+    /// All safe functions on slices preserve the invariant that even if the function panics, all
+    /// original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. This ensures that recovery code (for instance inside
+    /// of a `Drop` or following a `catch_unwind`) will still have access to all the original
+    /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able
+    /// to dispose of all contained elements.
     ///
     /// # Examples
     ///
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 32212b61c6e..42501f9c315 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -9,6 +9,7 @@
 
 use core::borrow::{Borrow, BorrowMut};
 use core::iter::FusedIterator;
+use core::mem::MaybeUninit;
 #[stable(feature = "encode_utf16", since = "1.8.0")]
 pub use core::str::EncodeUtf16;
 #[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
@@ -365,14 +366,9 @@ impl str {
                   without modifying the original"]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
     pub fn to_lowercase(&self) -> String {
-        let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_lowercase);
+        let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_lowercase);
 
-        // Safety: we know this is a valid char boundary since
-        // out.len() is only progressed if ascii bytes are found
-        let rest = unsafe { self.get_unchecked(out.len()..) };
-
-        // Safety: We have written only valid ASCII to our vec
-        let mut s = unsafe { String::from_utf8_unchecked(out) };
+        let prefix_len = s.len();
 
         for (i, c) in rest.char_indices() {
             if c == 'Σ' {
@@ -381,8 +377,7 @@ impl str {
                 // in `SpecialCasing.txt`,
                 // so hard-code it rather than have a generic "condition" mechanism.
                 // See https://github.com/rust-lang/rust/issues/26035
-                let out_len = self.len() - rest.len();
-                let sigma_lowercase = map_uppercase_sigma(&self, i + out_len);
+                let sigma_lowercase = map_uppercase_sigma(self, prefix_len + i);
                 s.push(sigma_lowercase);
             } else {
                 match conversions::to_lower(c) {
@@ -458,14 +453,7 @@ impl str {
                   without modifying the original"]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
     pub fn to_uppercase(&self) -> String {
-        let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_uppercase);
-
-        // Safety: we know this is a valid char boundary since
-        // out.len() is only progressed if ascii bytes are found
-        let rest = unsafe { self.get_unchecked(out.len()..) };
-
-        // Safety: We have written only valid ASCII to our vec
-        let mut s = unsafe { String::from_utf8_unchecked(out) };
+        let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_uppercase);
 
         for c in rest.chars() {
             match conversions::to_upper(c) {
@@ -614,50 +602,87 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
     unsafe { Box::from_raw(Box::into_raw(v) as *mut str) }
 }
 
-/// Converts the bytes while the bytes are still ascii.
+/// Converts leading ascii bytes in `s` by calling the `convert` function.
+///
 /// For better average performance, this happens in chunks of `2*size_of::<usize>()`.
-/// Returns a vec with the converted bytes.
+///
+/// Returns a tuple of the converted prefix and the remainder starting from
+/// the first non-ascii character.
+///
+/// This function is only public so that it can be verified in a codegen test,
+/// see `issue-123712-str-to-lower-autovectorization.rs`.
+#[unstable(feature = "str_internals", issue = "none")]
+#[doc(hidden)]
 #[inline]
 #[cfg(not(test))]
 #[cfg(not(no_global_oom_handling))]
-fn convert_while_ascii(b: &[u8], convert: fn(&u8) -> u8) -> Vec<u8> {
-    let mut out = Vec::with_capacity(b.len());
+pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
+    // Process the input in chunks of 16 bytes to enable auto-vectorization.
+    // Previously the chunk size depended on the size of `usize`,
+    // but on 32-bit platforms with sse or neon is also the better choice.
+    // The only downside on other platforms would be a bit more loop-unrolling.
+    const N: usize = 16;
+
+    let mut slice = s.as_bytes();
+    let mut out = Vec::with_capacity(slice.len());
+    let mut out_slice = out.spare_capacity_mut();
+
+    let mut ascii_prefix_len = 0_usize;
+    let mut is_ascii = [false; N];
+
+    while slice.len() >= N {
+        // SAFETY: checked in loop condition
+        let chunk = unsafe { slice.get_unchecked(..N) };
+        // SAFETY: out_slice has at least same length as input slice and gets sliced with the same offsets
+        let out_chunk = unsafe { out_slice.get_unchecked_mut(..N) };
+
+        for j in 0..N {
+            is_ascii[j] = chunk[j] <= 127;
+        }
 
-    const USIZE_SIZE: usize = mem::size_of::<usize>();
-    const MAGIC_UNROLL: usize = 2;
-    const N: usize = USIZE_SIZE * MAGIC_UNROLL;
-    const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; USIZE_SIZE]);
+        // Auto-vectorization for this check is a bit fragile, sum and comparing against the chunk
+        // size gives the best result, specifically a pmovmsk instruction on x86.
+        // See https://github.com/llvm/llvm-project/issues/96395 for why llvm currently does not
+        // currently recognize other similar idioms.
+        if is_ascii.iter().map(|x| *x as u8).sum::<u8>() as usize != N {
+            break;
+        }
 
-    let mut i = 0;
-    unsafe {
-        while i + N <= b.len() {
-            // Safety: we have checks the sizes `b` and `out` to know that our
-            let in_chunk = b.get_unchecked(i..i + N);
-            let out_chunk = out.spare_capacity_mut().get_unchecked_mut(i..i + N);
-
-            let mut bits = 0;
-            for j in 0..MAGIC_UNROLL {
-                // read the bytes 1 usize at a time (unaligned since we haven't checked the alignment)
-                // safety: in_chunk is valid bytes in the range
-                bits |= in_chunk.as_ptr().cast::<usize>().add(j).read_unaligned();
-            }
-            // if our chunks aren't ascii, then return only the prior bytes as init
-            if bits & NONASCII_MASK != 0 {
-                break;
-            }
+        for j in 0..N {
+            out_chunk[j] = MaybeUninit::new(convert(&chunk[j]));
+        }
 
-            // perform the case conversions on N bytes (gets heavily autovec'd)
-            for j in 0..N {
-                // safety: in_chunk and out_chunk is valid bytes in the range
-                let out = out_chunk.get_unchecked_mut(j);
-                out.write(convert(in_chunk.get_unchecked(j)));
-            }
+        ascii_prefix_len += N;
+        slice = unsafe { slice.get_unchecked(N..) };
+        out_slice = unsafe { out_slice.get_unchecked_mut(N..) };
+    }
 
-            // mark these bytes as initialised
-            i += N;
+    // handle the remainder as individual bytes
+    while slice.len() > 0 {
+        let byte = slice[0];
+        if byte > 127 {
+            break;
+        }
+        // SAFETY: out_slice has at least same length as input slice
+        unsafe {
+            *out_slice.get_unchecked_mut(0) = MaybeUninit::new(convert(&byte));
         }
-        out.set_len(i);
+        ascii_prefix_len += 1;
+        slice = unsafe { slice.get_unchecked(1..) };
+        out_slice = unsafe { out_slice.get_unchecked_mut(1..) };
     }
 
-    out
+    unsafe {
+        // SAFETY: ascii_prefix_len bytes have been initialized above
+        out.set_len(ascii_prefix_len);
+
+        // SAFETY: We have written only valid ascii to the output vec
+        let ascii_string = String::from_utf8_unchecked(out);
+
+        // SAFETY: we know this is a valid char boundary
+        // since we only skipped over leading ascii bytes
+        let rest = core::str::from_utf8_unchecked(slice);
+
+        (ascii_string, rest)
+    }
 }
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index ee878e879e9..82dbf030608 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1059,7 +1059,8 @@ impl String {
     #[inline]
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_bytes(self) -> Vec<u8> {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn into_bytes(self) -> Vec<u8> {
         self.vec
     }
 
@@ -1076,8 +1077,11 @@ impl String {
     #[must_use]
     #[stable(feature = "string_as_str", since = "1.7.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")]
-    pub fn as_str(&self) -> &str {
-        self
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_str(&self) -> &str {
+        // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
+        // at construction.
+        unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
     }
 
     /// Converts a `String` into a mutable string slice.
@@ -1096,8 +1100,11 @@ impl String {
     #[must_use]
     #[stable(feature = "string_as_str", since = "1.7.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")]
-    pub fn as_mut_str(&mut self) -> &mut str {
-        self
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_mut_str(&mut self) -> &mut str {
+        // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
+        // at construction.
+        unsafe { str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) }
     }
 
     /// Appends a given string slice onto the end of this `String`.
@@ -1168,7 +1175,8 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn capacity(&self) -> usize {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn capacity(&self) -> usize {
         self.vec.capacity()
     }
 
@@ -1431,8 +1439,9 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn as_bytes(&self) -> &[u8] {
-        &self.vec
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_bytes(&self) -> &[u8] {
+        self.vec.as_slice()
     }
 
     /// Shortens this `String` to the specified length.
@@ -1784,7 +1793,8 @@ impl String {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
         &mut self.vec
     }
 
@@ -1805,8 +1815,9 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_confusables("length", "size")]
-    pub fn len(&self) -> usize {
+    pub const fn len(&self) -> usize {
         self.vec.len()
     }
 
@@ -1824,7 +1835,8 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn is_empty(&self) -> bool {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
@@ -2589,7 +2601,7 @@ impl ops::Deref for String {
 
     #[inline]
     fn deref(&self) -> &str {
-        unsafe { str::from_utf8_unchecked(&self.vec) }
+        self.as_str()
     }
 }
 
@@ -2600,7 +2612,7 @@ unsafe impl ops::DerefPure for String {}
 impl ops::DerefMut for String {
     #[inline]
     fn deref_mut(&mut self) -> &mut str {
-        unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
+        self.as_mut_str()
     }
 }
 
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 50886244d58..5d099a49854 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -237,6 +237,7 @@ macro_rules! acquire {
 /// [rc_examples]: crate::rc#examples
 #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct Arc<
     T: ?Sized,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
@@ -797,7 +798,7 @@ impl<T, A: Allocator> Arc<T, A> {
         // reference into a strong reference.
         let strong = unsafe {
             let inner = init_ptr.as_ptr();
-            ptr::write(ptr::addr_of_mut!((*inner).data), data);
+            ptr::write(&raw mut (*inner).data, data);
 
             // The above write to the data field must be visible to any threads which
             // observe a non-zero strong count. Therefore we need at least "Release" ordering
@@ -1583,7 +1584,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
         // SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner because
         // this is required to retain raw/mut provenance such that e.g. `get_mut` can
         // write through the pointer after the Rc is recovered through `from_raw`.
-        unsafe { ptr::addr_of_mut!((*ptr).data) }
+        unsafe { &raw mut (*ptr).data }
     }
 
     /// Constructs an `Arc<T, A>` from a raw pointer.
@@ -1955,8 +1956,8 @@ impl<T: ?Sized> Arc<T> {
         debug_assert_eq!(unsafe { Layout::for_value_raw(inner) }, layout);
 
         unsafe {
-            ptr::addr_of_mut!((*inner).strong).write(atomic::AtomicUsize::new(1));
-            ptr::addr_of_mut!((*inner).weak).write(atomic::AtomicUsize::new(1));
+            (&raw mut (*inner).strong).write(atomic::AtomicUsize::new(1));
+            (&raw mut (*inner).weak).write(atomic::AtomicUsize::new(1));
         }
 
         inner
@@ -1986,8 +1987,8 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
 
             // Copy value as bytes
             ptr::copy_nonoverlapping(
-                core::ptr::addr_of!(*src) as *const u8,
-                ptr::addr_of_mut!((*ptr).data) as *mut u8,
+                (&raw const *src) as *const u8,
+                (&raw mut (*ptr).data) as *mut u8,
                 value_size,
             );
 
@@ -2022,7 +2023,7 @@ impl<T> Arc<[T]> {
         unsafe {
             let ptr = Self::allocate_for_slice(v.len());
 
-            ptr::copy_nonoverlapping(v.as_ptr(), ptr::addr_of_mut!((*ptr).data) as *mut T, v.len());
+            ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).data) as *mut T, v.len());
 
             Self::from_ptr(ptr)
         }
@@ -2061,7 +2062,7 @@ impl<T> Arc<[T]> {
             let layout = Layout::for_value_raw(ptr);
 
             // Pointer to first element
-            let elems = ptr::addr_of_mut!((*ptr).data) as *mut T;
+            let elems = (&raw mut (*ptr).data) as *mut T;
 
             let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
 
@@ -2805,7 +2806,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
             // SAFETY: if is_dangling returns false, then the pointer is dereferenceable.
             // The payload may be dropped at this point, and we have to maintain provenance,
             // so use raw pointer manipulation.
-            unsafe { ptr::addr_of_mut!((*ptr).data) }
+            unsafe { &raw mut (*ptr).data }
         }
     }
 
@@ -3428,7 +3429,7 @@ impl<T: ?Sized + fmt::Debug, A: Allocator> fmt::Debug for Arc<T, A> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized, A: Allocator> fmt::Pointer for Arc<T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f)
+        fmt::Pointer::fmt(&(&raw const **self), f)
     }
 }
 
@@ -3678,7 +3679,7 @@ impl<T, A: Allocator + Clone> From<Vec<T, A>> for Arc<[T], A> {
             let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
 
             let rc_ptr = Self::allocate_for_slice_in(len, &alloc);
-            ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).data) as *mut T, len);
+            ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).data) as *mut T, len);
 
             // Create a `Vec<T, &A>` with length 0, to deallocate the buffer
             // without dropping its contents or the allocator
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index f7aad56695d..9a6745fdbc0 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -21,11 +21,11 @@ use crate::raw_vec::RawVec;
 macro non_null {
     (mut $place:expr, $t:ident) => {{
         #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
-        unsafe { &mut *(ptr::addr_of_mut!($place) as *mut NonNull<$t>) }
+        unsafe { &mut *((&raw mut $place) as *mut NonNull<$t>) }
     }},
     ($place:expr, $t:ident) => {{
         #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
-        unsafe { *(ptr::addr_of!($place) as *const NonNull<$t>) }
+        unsafe { *((&raw const $place) as *const NonNull<$t>) }
     }},
 }
 
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 1984cfeefc1..830512ceee8 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1240,7 +1240,8 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn capacity(&self) -> usize {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn capacity(&self) -> usize {
         self.buf.capacity()
     }
 
@@ -1548,8 +1549,22 @@ impl<T, A: Allocator> Vec<T, A> {
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")]
-    pub fn as_slice(&self) -> &[T] {
-        self
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_slice(&self) -> &[T] {
+        // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size
+        // `len` containing properly-initialized `T`s. Data must not be mutated for the returned
+        // lifetime. Further, `len * mem::size_of::<T>` <= `ISIZE::MAX`, and allocation does not
+        // "wrap" through overflowing memory addresses.
+        //
+        // * Vec API guarantees that self.buf:
+        //      * contains only properly-initialized items within 0..len
+        //      * is aligned, contiguous, and valid for `len` reads
+        //      * obeys size and address-wrapping constraints
+        //
+        // * We only construct `&mut` references to `self.buf` through `&mut self` methods; borrow-
+        //   check ensures that it is not possible to mutably alias `self.buf` within the
+        //   returned lifetime.
+        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
     }
 
     /// Extracts a mutable slice of the entire vector.
@@ -1566,8 +1581,22 @@ impl<T, A: Allocator> Vec<T, A> {
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")]
-    pub fn as_mut_slice(&mut self) -> &mut [T] {
-        self
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_mut_slice(&mut self) -> &mut [T] {
+        // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of
+        // size `len` containing properly-initialized `T`s. Data must not be accessed through any
+        // other pointer for the returned lifetime. Further, `len * mem::size_of::<T>` <=
+        // `ISIZE::MAX` and allocation does not "wrap" through overflowing memory addresses.
+        //
+        // * Vec API guarantees that self.buf:
+        //      * contains only properly-initialized items within 0..len
+        //      * is aligned, contiguous, and valid for `len` reads
+        //      * obeys size and address-wrapping constraints
+        //
+        // * We only construct references to `self.buf` through `&self` and `&mut self` methods;
+        //   borrow-check ensures that it is not possible to construct a reference to `self.buf`
+        //   within the returned lifetime.
+        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
     }
 
     /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
@@ -1624,9 +1653,10 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_ptr`]: Vec::as_ptr
     /// [`as_non_null`]: Vec::as_non_null
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_never_returns_null_ptr]
     #[inline]
-    pub fn as_ptr(&self) -> *const T {
+    pub const fn as_ptr(&self) -> *const T {
         // We shadow the slice method of the same name to avoid going through
         // `deref`, which creates an intermediate reference.
         self.buf.ptr()
@@ -1685,9 +1715,10 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_ptr`]: Vec::as_ptr
     /// [`as_non_null`]: Vec::as_non_null
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_never_returns_null_ptr]
     #[inline]
-    pub fn as_mut_ptr(&mut self) -> *mut T {
+    pub const fn as_mut_ptr(&mut self) -> *mut T {
         // We shadow the slice method of the same name to avoid going through
         // `deref_mut`, which creates an intermediate reference.
         self.buf.ptr()
@@ -2628,8 +2659,9 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_confusables("length", "size")]
-    pub fn len(&self) -> usize {
+    pub const fn len(&self) -> usize {
         self.len
     }
 
@@ -2646,7 +2678,8 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")]
-    pub fn is_empty(&self) -> bool {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
@@ -3197,7 +3230,7 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> {
 
     #[inline]
     fn deref(&self) -> &[T] {
-        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
+        self.as_slice()
     }
 }
 
@@ -3205,7 +3238,7 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> {
 impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
     #[inline]
     fn deref_mut(&mut self) -> &mut [T] {
-        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
+        self.as_mut_slice()
     }
 }