diff options
Diffstat (limited to 'library/alloc')
| -rw-r--r-- | library/alloc/src/alloc.rs | 7 | ||||
| -rw-r--r-- | library/alloc/src/collections/btree/set.rs | 8 | ||||
| -rw-r--r-- | library/alloc/src/collections/linked_list/tests.rs | 147 | ||||
| -rw-r--r-- | library/alloc/src/collections/vec_deque/tests.rs | 38 | ||||
| -rw-r--r-- | library/alloc/src/ffi/c_str.rs | 111 | ||||
| -rw-r--r-- | library/alloc/src/rc.rs | 1 | ||||
| -rw-r--r-- | library/alloc/src/string.rs | 53 | ||||
| -rw-r--r-- | library/alloc/src/sync.rs | 1 | ||||
| -rw-r--r-- | library/alloc/src/vec/mod.rs | 32 | ||||
| -rw-r--r-- | library/alloc/src/vec/peek_mut.rs | 55 |
10 files changed, 300 insertions, 153 deletions
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index e1cc4ba25c4..b4176e9c1f4 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -31,8 +31,9 @@ unsafe extern "Rust" { #[rustc_std_internal_symbol] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; + #[rustc_nounwind] #[rustc_std_internal_symbol] - static __rust_no_alloc_shim_is_unstable: u8; + fn __rust_no_alloc_shim_is_unstable_v2(); } /// The global memory allocator. @@ -88,7 +89,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); + __rust_no_alloc_shim_is_unstable_v2(); __rust_alloc(layout.size(), layout.align()) } @@ -171,7 +172,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); + __rust_no_alloc_shim_is_unstable_v2(); __rust_alloc_zeroed(layout.size(), layout.align()) } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 51418036f42..aa9e5fce1d4 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1220,11 +1220,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { /// assert_eq!(high.into_iter().collect::<Vec<_>>(), [4, 5, 6, 7]); /// ``` #[unstable(feature = "btree_extract_if", issue = "70530")] - pub fn extract_if<'a, F, R>(&'a mut self, range: R, pred: F) -> ExtractIf<'a, T, R, F, A> + pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, T, R, F, A> where T: Ord, R: RangeBounds<T>, - F: 'a + FnMut(&T) -> bool, + F: FnMut(&T) -> bool, { let (inner, alloc) = self.map.extract_if_inner(range); ExtractIf { pred, inner, alloc } @@ -1585,11 +1585,11 @@ where } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl<'a, T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A> +impl<T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A> where T: PartialOrd, R: RangeBounds<T>, - F: 'a + FnMut(&T) -> bool, + F: FnMut(&T) -> bool, { type Item = T; diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs index 812fe229a0f..3d6c740e80b 100644 --- a/library/alloc/src/collections/linked_list/tests.rs +++ b/library/alloc/src/collections/linked_list/tests.rs @@ -1,6 +1,3 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] - use std::panic::{AssertUnwindSafe, catch_unwind}; use std::thread; @@ -8,6 +5,7 @@ use rand::RngCore; use super::*; use crate::testing::crash_test::{CrashTestDummy, Panic}; +use crate::testing::macros::struct_with_counted_drop; use crate::vec::Vec; #[test] @@ -58,48 +56,33 @@ fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> { v.iter().cloned().collect() } +/// Starting from the head of the LinkedList, +/// follow the next links, while checking the prev links, +/// and check that length equals the count of visited nodes. fn check_links<T>(list: &LinkedList<T>) { - unsafe { - let mut len = 0; - let mut last_ptr: Option<&Node<T>> = None; - let mut node_ptr: &Node<T>; - match list.head { - None => { - // tail node should also be None. - assert!(list.tail.is_none()); - assert_eq!(0, list.len); - return; - } - Some(node) => node_ptr = &*node.as_ptr(), - } - loop { - match (last_ptr, node_ptr.prev) { - (None, None) => {} - (None, _) => panic!("prev link for head"), - (Some(p), Some(pptr)) => { - assert_eq!(p as *const Node<T>, pptr.as_ptr() as *const Node<T>); - } - _ => panic!("prev link is none, not good"), - } - match node_ptr.next { - Some(next) => { - last_ptr = Some(node_ptr); - node_ptr = &*next.as_ptr(); - len += 1; - } - None => { - len += 1; - break; - } - } - } - - // verify that the tail node points to the last node. - let tail = list.tail.as_ref().expect("some tail node").as_ref(); - assert_eq!(tail as *const Node<T>, node_ptr as *const Node<T>); - // check that len matches interior links. - assert_eq!(len, list.len); + let mut node: &Node<T> = if let Some(node) = list.head { + // SAFETY: depends on correctness of LinkedList + unsafe { &*node.as_ptr() } + } else { + assert!(list.tail.is_none(), "empty list should have no tail node"); + assert_eq!(list.len, 0, "empty list should have length 0"); + return; + }; + + assert!(node.prev.is_none(), "head node should not have a prev link"); + let mut prev; + let mut len = 1; + while let Some(next) = node.next { + prev = node; + // SAFETY: depends on correctness of LinkedList + node = unsafe { &*next.as_ptr() }; + len += 1; + assert_eq!(node.prev.expect("missing prev link"), prev.into(), "bad prev link"); } + + let tail = list.tail.expect("list is non-empty, so there should be a tail node"); + assert_eq!(tail, node.into(), "tail node points to the last node"); + assert_eq!(len, list.len, "len matches interior links"); } #[test] @@ -1030,18 +1013,7 @@ fn extract_if_drop_panic_leak() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn extract_if_pred_panic_leak() { - static mut DROPS: i32 = 0; - - #[derive(Debug)] - struct D(u32); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(D(u32), DROPS); let mut q = LinkedList::new(); q.push_back(D(3)); @@ -1053,26 +1025,17 @@ fn extract_if_pred_panic_leak() { q.push_front(D(1)); q.push_front(D(0)); - catch_unwind(AssertUnwindSafe(|| { + _ = catch_unwind(AssertUnwindSafe(|| { q.extract_if(|item| if item.0 >= 2 { panic!() } else { true }).for_each(drop) - })) - .ok(); + })); - assert_eq!(unsafe { DROPS }, 2); // 0 and 1 + assert_eq!(DROPS.get(), 2); // 0 and 1 assert_eq!(q.len(), 6); } #[test] fn test_drop() { - static mut DROPS: i32 = 0; - struct Elem; - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(Elem, DROPS); let mut ring = LinkedList::new(); ring.push_back(Elem); @@ -1081,20 +1044,12 @@ fn test_drop() { ring.push_front(Elem); drop(ring); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); } #[test] fn test_drop_with_pop() { - static mut DROPS: i32 = 0; - struct Elem; - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(Elem, DROPS); let mut ring = LinkedList::new(); ring.push_back(Elem); @@ -1104,23 +1059,15 @@ fn test_drop_with_pop() { drop(ring.pop_back()); drop(ring.pop_front()); - assert_eq!(unsafe { DROPS }, 2); + assert_eq!(DROPS.get(), 2); drop(ring); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); } #[test] fn test_drop_clear() { - static mut DROPS: i32 = 0; - struct Elem; - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(Elem, DROPS); let mut ring = LinkedList::new(); ring.push_back(Elem); @@ -1128,30 +1075,16 @@ fn test_drop_clear() { ring.push_back(Elem); ring.push_front(Elem); ring.clear(); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); drop(ring); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); } #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drop_panic() { - static mut DROPS: i32 = 0; - - struct D(bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.0 { - panic!("panic in `drop`"); - } - } - } + struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } ); let mut q = LinkedList::new(); q.push_back(D(false)); @@ -1165,7 +1098,7 @@ fn test_drop_panic() { catch_unwind(move || drop(q)).ok(); - assert_eq!(unsafe { DROPS }, 8); + assert_eq!(DROPS.get(), 8); } #[test] diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs index c90679f1797..ad76cb14deb 100644 --- a/library/alloc/src/collections/vec_deque/tests.rs +++ b/library/alloc/src/collections/vec_deque/tests.rs @@ -1,9 +1,7 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] - use core::iter::TrustedLen; use super::*; +use crate::testing::macros::struct_with_counted_drop; #[bench] fn bench_push_back_100(b: &mut test::Bencher) { @@ -1086,36 +1084,24 @@ fn test_clone_from() { #[test] fn test_vec_deque_truncate_drop() { - static mut DROPS: u32 = 0; - #[derive(Clone)] - struct Elem(#[allow(dead_code)] i32); - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(Elem, DROPS); - let v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; - for push_front in 0..=v.len() { - let v = v.clone(); - let mut tester = VecDeque::with_capacity(5); - for (index, elem) in v.into_iter().enumerate() { + const LEN: usize = 5; + for push_front in 0..=LEN { + let mut tester = VecDeque::with_capacity(LEN); + for index in 0..LEN { if index < push_front { - tester.push_front(elem); + tester.push_front(Elem); } else { - tester.push_back(elem); + tester.push_back(Elem); } } - assert_eq!(unsafe { DROPS }, 0); + assert_eq!(DROPS.get(), 0); tester.truncate(3); - assert_eq!(unsafe { DROPS }, 2); + assert_eq!(DROPS.get(), 2); tester.truncate(0); - assert_eq!(unsafe { DROPS }, 5); - unsafe { - DROPS = 0; - } + assert_eq!(DROPS.get(), 5); + DROPS.set(0); } } diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 8b448a18402..93bdad75380 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -714,6 +714,8 @@ impl ops::Deref for CString { } } +/// Delegates to the [`CStr`] implementation of [`fmt::Debug`], +/// showing invalid UTF-8 as hex escapes. #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for CString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1097,6 +1099,46 @@ impl From<&CStr> for CString { } } +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<CStr> for CString { + #[inline] + fn eq(&self, other: &CStr) -> bool { + **self == *other + } + + #[inline] + fn ne(&self, other: &CStr) -> bool { + **self != *other + } +} + +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<&CStr> for CString { + #[inline] + fn eq(&self, other: &&CStr) -> bool { + **self == **other + } + + #[inline] + fn ne(&self, other: &&CStr) -> bool { + **self != **other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<Cow<'_, CStr>> for CString { + #[inline] + fn eq(&self, other: &Cow<'_, CStr>) -> bool { + **self == **other + } + + #[inline] + fn ne(&self, other: &Cow<'_, CStr>) -> bool { + **self != **other + } +} + #[stable(feature = "cstring_asref", since = "1.7.0")] impl ops::Index<ops::RangeFull> for CString { type Output = CStr; @@ -1179,6 +1221,75 @@ impl CStr { } } +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<CString> for CStr { + #[inline] + fn eq(&self, other: &CString) -> bool { + *self == **other + } + + #[inline] + fn ne(&self, other: &CString) -> bool { + *self != **other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<Cow<'_, Self>> for CStr { + #[inline] + fn eq(&self, other: &Cow<'_, Self>) -> bool { + *self == **other + } + + #[inline] + fn ne(&self, other: &Cow<'_, Self>) -> bool { + *self != **other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<CStr> for Cow<'_, CStr> { + #[inline] + fn eq(&self, other: &CStr) -> bool { + **self == *other + } + + #[inline] + fn ne(&self, other: &CStr) -> bool { + **self != *other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<&CStr> for Cow<'_, CStr> { + #[inline] + fn eq(&self, other: &&CStr) -> bool { + **self == **other + } + + #[inline] + fn ne(&self, other: &&CStr) -> bool { + **self != **other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<CString> for Cow<'_, CStr> { + #[inline] + fn eq(&self, other: &CString) -> bool { + **self == **other + } + + #[inline] + fn ne(&self, other: &CString) -> bool { + **self != **other + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl core::error::Error for NulError { #[allow(deprecated)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 4b8ea708e7e..010d17f7476 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -3004,7 +3004,6 @@ pub struct Weak< // `Weak::new` sets this to `usize::MAX` so that it doesn’t need // to allocate space on the heap. That's not a value a real pointer // will ever have because RcInner has alignment at least 2. - // This is only possible when `T: Sized`; unsized `T` never dangle. ptr: NonNull<RcInner<T>>, alloc: A, } diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 37614a7ca45..5f69f699867 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1105,6 +1105,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("append", "push")] #[rustc_diagnostic_item = "string_push_str"] @@ -1135,6 +1136,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_extend_from_within", since = "1.87.0")] + #[track_caller] pub fn extend_from_within<R>(&mut self, src: R) where R: RangeBounds<usize>, @@ -1206,6 +1208,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { self.vec.reserve(additional) @@ -1257,6 +1260,7 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn reserve_exact(&mut self, additional: usize) { self.vec.reserve_exact(additional) } @@ -1352,6 +1356,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { self.vec.shrink_to_fit() @@ -1379,6 +1384,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { self.vec.shrink_to(min_capacity) @@ -1400,6 +1406,7 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn push(&mut self, ch: char) { let len = self.len(); let ch_len = ch.len_utf8(); @@ -1456,6 +1463,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn truncate(&mut self, new_len: usize) { if new_len <= self.len() { assert!(self.is_char_boundary(new_len)); @@ -1489,10 +1497,11 @@ impl String { Some(ch) } - /// Removes a [`char`] from this `String` at a byte position and returns it. + /// Removes a [`char`] from this `String` at byte position `idx` and returns it. /// - /// This is an *O*(*n*) operation, as it requires copying every element in the - /// buffer. + /// Copies all bytes after the removed char to new positions. + /// + /// Note that calling this in a loop can result in quadratic behavior. /// /// # Panics /// @@ -1510,6 +1519,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] #[rustc_confusables("delete", "take")] pub fn remove(&mut self, idx: usize) -> char { let ch = match self[idx..].chars().next() { @@ -1678,10 +1688,13 @@ impl String { drop(guard); } - /// Inserts a character into this `String` at a byte position. + /// Inserts a character into this `String` at byte position `idx`. + /// + /// Reallocates if `self.capacity()` is insufficient, which may involve copying all + /// `self.capacity()` bytes. Makes space for the insertion by copying all bytes of + /// `&self[idx..]` to new positions. /// - /// This is an *O*(*n*) operation as it requires copying every element in the - /// buffer. + /// Note that calling this in a loop can result in quadratic behavior. /// /// # Panics /// @@ -1701,6 +1714,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("set")] pub fn insert(&mut self, idx: usize, ch: char) { @@ -1733,10 +1747,13 @@ impl String { } } - /// Inserts a string slice into this `String` at a byte position. + /// Inserts a string slice into this `String` at byte position `idx`. + /// + /// Reallocates if `self.capacity()` is insufficient, which may involve copying all + /// `self.capacity()` bytes. Makes space for the insertion by copying all bytes of + /// `&self[idx..]` to new positions. /// - /// This is an *O*(*n*) operation as it requires copying every element in the - /// buffer. + /// Note that calling this in a loop can result in quadratic behavior. /// /// # Panics /// @@ -1754,6 +1771,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "insert_str", since = "1.16.0")] #[rustc_diagnostic_item = "string_insert_str"] pub fn insert_str(&mut self, idx: usize, string: &str) { @@ -1882,6 +1900,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "string_split_off", since = "1.16.0")] #[must_use = "use `.truncate()` if you don't need the other half"] pub fn split_off(&mut self, at: usize) -> String { @@ -1946,6 +1965,7 @@ impl String { /// assert_eq!(s, ""); /// ``` #[stable(feature = "drain", since = "1.6.0")] + #[track_caller] pub fn drain<R>(&mut self, range: R) -> Drain<'_> where R: RangeBounds<usize>, @@ -2045,6 +2065,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "splice", since = "1.27.0")] + #[track_caller] pub fn replace_range<R>(&mut self, range: R, replace_with: &str) where R: RangeBounds<usize>, @@ -2094,6 +2115,7 @@ impl String { #[stable(feature = "box_str", since = "1.4.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline] + #[track_caller] pub fn into_boxed_str(self) -> Box<str> { let slice = self.vec.into_boxed_slice(); unsafe { from_boxed_utf8_unchecked(slice) } @@ -2281,6 +2303,7 @@ impl Error for FromUtf16Error { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for String { + #[track_caller] fn clone(&self) -> Self { String { vec: self.vec.clone() } } @@ -2289,6 +2312,7 @@ impl Clone for String { /// /// This method is preferred over simply assigning `source.clone()` to `self`, /// as it avoids reallocation if possible. + #[track_caller] fn clone_from(&mut self, source: &Self) { self.vec.clone_from(&source.vec); } @@ -2462,11 +2486,14 @@ impl<'a> Extend<Cow<'a, str>> for String { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "ascii_char", issue = "110998")] impl Extend<core::ascii::Char> for String { + #[inline] + #[track_caller] fn extend<I: IntoIterator<Item = core::ascii::Char>>(&mut self, iter: I) { self.vec.extend(iter.into_iter().map(|c| c.to_u8())); } #[inline] + #[track_caller] fn extend_one(&mut self, c: core::ascii::Char) { self.vec.push(c.to_u8()); } @@ -2475,11 +2502,14 @@ impl Extend<core::ascii::Char> for String { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "ascii_char", issue = "110998")] impl<'a> Extend<&'a core::ascii::Char> for String { + #[inline] + #[track_caller] fn extend<I: IntoIterator<Item = &'a core::ascii::Char>>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } #[inline] + #[track_caller] fn extend_one(&mut self, c: &'a core::ascii::Char) { self.vec.push(c.to_u8()); } @@ -2834,7 +2864,7 @@ macro_rules! impl_to_string { impl SpecToString for $signed { #[inline] fn spec_to_string(&self) -> String { - const SIZE: usize = $signed::MAX.ilog(10) as usize + 1; + const SIZE: usize = $signed::MAX.ilog10() as usize + 1; let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE]; // Only difference between signed and unsigned are these 8 lines. let mut out; @@ -2854,7 +2884,7 @@ macro_rules! impl_to_string { impl SpecToString for $unsigned { #[inline] fn spec_to_string(&self) -> String { - const SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1; + const SIZE: usize = $unsigned::MAX.ilog10() as usize + 1; let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); SIZE]; self._fmt(&mut buf).to_string() @@ -2870,6 +2900,7 @@ impl_to_string! { i32, u32, i64, u64, isize, usize, + i128, u128, } #[cfg(not(no_global_oom_handling))] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 17090925cfa..1e3c03977bd 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -342,7 +342,6 @@ pub struct Weak< // `Weak::new` sets this to `usize::MAX` so that it doesn’t need // to allocate space on the heap. That's not a value a real pointer // will ever have because RcInner has alignment at least 2. - // This is only possible when `T: Sized`; unsized `T` never dangle. ptr: NonNull<ArcInner<T>>, alloc: A, } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ce7321544b6..5bd82560da7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -109,6 +109,11 @@ mod in_place_collect; mod partial_eq; +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub use self::peek_mut::PeekMut; + +mod peek_mut; + #[cfg(not(no_global_oom_handling))] use self::spec_from_elem::SpecFromElem; @@ -729,6 +734,33 @@ impl<T> Vec<T> { pub unsafe fn from_parts(ptr: NonNull<T>, length: usize, capacity: usize) -> Self { unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } + + /// Returns a mutable reference to the last item in the vector, or + /// `None` if it is empty. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(vec_peek_mut)] + /// let mut vec = Vec::new(); + /// assert!(vec.peek_mut().is_none()); + /// + /// vec.push(1); + /// vec.push(5); + /// vec.push(2); + /// assert_eq!(vec.last(), Some(&2)); + /// if let Some(mut val) = vec.peek_mut() { + /// *val = 0; + /// } + /// assert_eq!(vec.last(), Some(&0)); + /// ``` + #[inline] + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> { + PeekMut::new(self) + } } impl<T, A: Allocator> Vec<T, A> { diff --git a/library/alloc/src/vec/peek_mut.rs b/library/alloc/src/vec/peek_mut.rs new file mode 100644 index 00000000000..c0dd941ed39 --- /dev/null +++ b/library/alloc/src/vec/peek_mut.rs @@ -0,0 +1,55 @@ +use core::ops::{Deref, DerefMut}; + +use super::Vec; +use crate::fmt; + +/// Structure wrapping a mutable reference to the last item in a +/// `Vec`. +/// +/// This `struct` is created by the [`peek_mut`] method on [`Vec`]. See +/// its documentation for more. +/// +/// [`peek_mut`]: Vec::peek_mut +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub struct PeekMut<'a, T> { + vec: &'a mut Vec<T>, +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<T: fmt::Debug> fmt::Debug for PeekMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("PeekMut").field(self.deref()).finish() + } +} + +impl<'a, T> PeekMut<'a, T> { + pub(crate) fn new(vec: &'a mut Vec<T>) -> Option<Self> { + if vec.is_empty() { None } else { Some(Self { vec }) } + } + + /// Removes the peeked value from the vector and returns it. + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn pop(self) -> T { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.pop().unwrap_unchecked() } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> Deref for PeekMut<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked(self.vec.len() - 1) } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> DerefMut for PeekMut<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + let idx = self.vec.len() - 1; + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked_mut(idx) } + } +} |
