From 52f9d5d607f34734f9c183c20c2418ed05ddb576 Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Tue, 30 Jul 2024 09:48:36 -0400 Subject: [PATCH] liballoc: introduce String, Vec const-slicing This change `const`-qualifies many methods on Vec and String, notably `as_slice`, `as_str`, `len`. These changes are made behind the unstable feature flag `const_vec_string_slice` with the following tracking issue: https://github.com/rust-lang/rust/issues/129041 --- library/alloc/src/lib.rs | 1 + library/alloc/src/raw_vec.rs | 10 +- library/alloc/src/string.rs | 28 +++--- library/alloc/src/vec/mod.rs | 23 +++-- ..._to_slice.PreCodegen.after.panic-abort.mir | 92 +++++++------------ ...to_slice.PreCodegen.after.panic-unwind.mir | 92 +++++++------------ tests/ui/consts/issue-94675.rs | 2 +- tests/ui/consts/issue-94675.stderr | 10 +- 8 files changed, 109 insertions(+), 149 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 5e4b08df6cb55..aa940b72e3006 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -117,6 +117,7 @@ #![feature(const_pin)] #![feature(const_refs_to_cell)] #![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 9c8fa7ceff4e5..c40d8cfe83543 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -293,7 +293,7 @@ impl RawVec { /// `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() } @@ -306,7 +306,7 @@ impl RawVec { /// /// 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::()) } @@ -501,8 +501,8 @@ impl RawVecInner { } #[inline] - fn ptr(&self) -> *mut T { - self.non_null::().as_ptr() + const fn ptr(&self) -> *mut T { + self.ptr.as_ptr() as _ } #[inline] @@ -511,7 +511,7 @@ impl RawVecInner { } #[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/string.rs b/library/alloc/src/string.rs index e628be1546f76..2f3dbac4ee32f 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1006,7 +1006,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 { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn into_bytes(self) -> Vec { self.vec } @@ -1022,8 +1023,9 @@ impl String { #[inline] #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] - pub fn as_str(&self) -> &str { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_str(&self) -> &str { + unsafe { str::from_utf8_unchecked(self.vec.as_slice()) } } /// Converts a `String` into a mutable string slice. @@ -1042,7 +1044,7 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] pub fn as_mut_str(&mut self) -> &mut str { - self + unsafe { str::from_utf8_unchecked_mut(&mut self.vec) } } /// Appends a given string slice onto the end of this `String`. @@ -1112,7 +1114,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() } @@ -1375,8 +1378,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. @@ -1748,8 +1752,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() } @@ -1767,7 +1772,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 } @@ -2484,7 +2490,7 @@ impl ops::Deref for String { #[inline] fn deref(&self) -> &str { - unsafe { str::from_utf8_unchecked(&self.vec) } + self.as_str() } } @@ -2495,7 +2501,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/vec/mod.rs b/library/alloc/src/vec/mod.rs index b4e0bc5fcbe41..03b612c7b6b72 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -946,7 +946,8 @@ impl Vec { /// ``` #[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() } @@ -1253,8 +1254,9 @@ impl Vec { /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] - pub fn as_slice(&self) -> &[T] { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_slice(&self) -> &[T] { + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } } /// Extracts a mutable slice of the entire vector. @@ -1271,7 +1273,7 @@ impl Vec { #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] pub fn as_mut_slice(&mut self) -> &mut [T] { - self + 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 @@ -1326,9 +1328,10 @@ impl Vec { /// [`as_mut_ptr`]: Vec::as_mut_ptr /// [`as_ptr`]: Vec::as_ptr #[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() @@ -2262,8 +2265,9 @@ impl Vec { /// ``` #[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 } @@ -2279,7 +2283,8 @@ impl Vec { /// assert!(!v.is_empty()); /// ``` #[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 } @@ -2828,7 +2833,7 @@ impl ops::Deref for Vec { #[inline] fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + self.as_slice() } } @@ -2836,7 +2841,7 @@ impl ops::Deref for Vec { impl ops::DerefMut for Vec { #[inline] fn deref_mut(&mut self) -> &mut [T] { - unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + self.as_mut_slice() } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index ce1e4a0abd61f..5898559bff9c1 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -5,67 +5,48 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _0: &[u8]; scope 1 (inlined as Deref>::deref) { debug self => _1; - let mut _7: usize; - scope 2 (inlined Vec::::as_ptr) { + scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec; - scope 3 (inlined alloc::raw_vec::RawVec::::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; - scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::) { - debug self => _3; - let mut _6: std::ptr::NonNull; - scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _6: usize; + scope 3 (inlined Vec::::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + debug self => _2; + let mut _3: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { debug self => _3; let mut _4: std::ptr::NonNull; - scope 6 (inlined Unique::::cast::) { + scope 6 (inlined Unique::::as_ptr) { debug ((self: Unique).0: std::ptr::NonNull) => _4; debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 7 (inlined NonNull::::cast::) { + scope 7 (inlined NonNull::::as_ptr) { debug self => _4; - scope 8 (inlined NonNull::::as_ptr) { - debug self => _4; - let mut _5: *const u8; - } - } - } - scope 9 (inlined #[track_caller] as Into>>::into) { - debug ((self: Unique).0: std::ptr::NonNull) => _6; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 10 (inlined as From>>::from) { - debug ((unique: Unique).0: std::ptr::NonNull) => _6; - debug ((unique: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 11 (inlined Unique::::as_non_null_ptr) { - debug ((self: Unique).0: std::ptr::NonNull) => _6; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - } + let mut _5: *const u8; } } } - scope 12 (inlined NonNull::::as_ptr) { - debug self => _6; - } } } - } - scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _5; - debug len => _7; - let _8: *const [u8]; - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } - scope 17 (inlined align_of::) { - } - scope 18 (inlined slice_from_raw_parts::) { + scope 8 (inlined std::slice::from_raw_parts::<'_, u8>) { debug data => _5; - debug len => _7; - scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _5; - debug metadata => _7; + debug len => _6; + let _7: *const [u8]; + scope 9 (inlined core::ub_checks::check_language_ub) { + scope 10 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 11 (inlined std::mem::size_of::) { + } + scope 12 (inlined align_of::) { + } + scope 13 (inlined slice_from_raw_parts::) { + debug data => _5; + debug len => _6; + scope 14 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + debug data_pointer => _5; + debug metadata => _6; + } } } } @@ -76,22 +57,19 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { _2 = &((*_1).0: alloc::raw_vec::RawVec); StorageLive(_3); _3 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); - StorageLive(_6); StorageLive(_4); _4 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _5 = copy (_4.0: *const u8); - _6 = NonNull:: { pointer: copy _5 }; StorageDead(_4); - StorageDead(_6); StorageDead(_3); StorageDead(_2); + StorageLive(_6); + _6 = copy ((*_1).1: usize); StorageLive(_7); - _7 = copy ((*_1).1: usize); - StorageLive(_8); - _8 = *const [u8] from (copy _5, copy _7); - _0 = &(*_8); - StorageDead(_8); + _7 = *const [u8] from (copy _5, copy _6); + _0 = &(*_7); StorageDead(_7); + StorageDead(_6); return; } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index ce1e4a0abd61f..5898559bff9c1 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -5,67 +5,48 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _0: &[u8]; scope 1 (inlined as Deref>::deref) { debug self => _1; - let mut _7: usize; - scope 2 (inlined Vec::::as_ptr) { + scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec; - scope 3 (inlined alloc::raw_vec::RawVec::::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; - scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::) { - debug self => _3; - let mut _6: std::ptr::NonNull; - scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _6: usize; + scope 3 (inlined Vec::::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + debug self => _2; + let mut _3: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { debug self => _3; let mut _4: std::ptr::NonNull; - scope 6 (inlined Unique::::cast::) { + scope 6 (inlined Unique::::as_ptr) { debug ((self: Unique).0: std::ptr::NonNull) => _4; debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 7 (inlined NonNull::::cast::) { + scope 7 (inlined NonNull::::as_ptr) { debug self => _4; - scope 8 (inlined NonNull::::as_ptr) { - debug self => _4; - let mut _5: *const u8; - } - } - } - scope 9 (inlined #[track_caller] as Into>>::into) { - debug ((self: Unique).0: std::ptr::NonNull) => _6; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 10 (inlined as From>>::from) { - debug ((unique: Unique).0: std::ptr::NonNull) => _6; - debug ((unique: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 11 (inlined Unique::::as_non_null_ptr) { - debug ((self: Unique).0: std::ptr::NonNull) => _6; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - } + let mut _5: *const u8; } } } - scope 12 (inlined NonNull::::as_ptr) { - debug self => _6; - } } } - } - scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _5; - debug len => _7; - let _8: *const [u8]; - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } - scope 17 (inlined align_of::) { - } - scope 18 (inlined slice_from_raw_parts::) { + scope 8 (inlined std::slice::from_raw_parts::<'_, u8>) { debug data => _5; - debug len => _7; - scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _5; - debug metadata => _7; + debug len => _6; + let _7: *const [u8]; + scope 9 (inlined core::ub_checks::check_language_ub) { + scope 10 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 11 (inlined std::mem::size_of::) { + } + scope 12 (inlined align_of::) { + } + scope 13 (inlined slice_from_raw_parts::) { + debug data => _5; + debug len => _6; + scope 14 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + debug data_pointer => _5; + debug metadata => _6; + } } } } @@ -76,22 +57,19 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { _2 = &((*_1).0: alloc::raw_vec::RawVec); StorageLive(_3); _3 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); - StorageLive(_6); StorageLive(_4); _4 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _5 = copy (_4.0: *const u8); - _6 = NonNull:: { pointer: copy _5 }; StorageDead(_4); - StorageDead(_6); StorageDead(_3); StorageDead(_2); + StorageLive(_6); + _6 = copy ((*_1).1: usize); StorageLive(_7); - _7 = copy ((*_1).1: usize); - StorageLive(_8); - _8 = *const [u8] from (copy _5, copy _7); - _0 = &(*_8); - StorageDead(_8); + _7 = *const [u8] from (copy _5, copy _6); + _0 = &(*_7); StorageDead(_7); + StorageDead(_6); return; } } diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index 00f5c3251e0a9..33290e890efa9 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -1,6 +1,6 @@ //@ known-bug: #103507 -#![feature(const_trait_impl, const_mut_refs)] +#![feature(const_trait_impl, const_mut_refs, const_vec_string_slice)] struct Foo<'a> { bar: &'a mut Vec, diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index ebfa09b2e5d5d..a85c5e10374f8 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -1,11 +1,3 @@ -error[E0015]: cannot call non-const fn `Vec::::len` in constant functions - --> $DIR/issue-94675.rs:11:27 - | -LL | self.bar[0] = baz.len(); - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - error[E0015]: cannot call non-const operator in constant functions --> $DIR/issue-94675.rs:11:17 | @@ -20,6 +12,6 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0015`.