Skip to content

Commit 0915c6f

Browse files
committed
Auto merge of rust-lang#147037 - matthiaskrgr:rollup-xtgqzuu, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - rust-lang#116882 (rustdoc: hide `#[repr]` if it isn't part of the public ABI) - rust-lang#135771 ([rustdoc] Add support for associated items in "jump to def" feature) - rust-lang#141032 (avoid violating `slice::from_raw_parts` safety contract in `Vec::extract_if`) - rust-lang#142401 (Add proper name mangling for pattern types) - rust-lang#146293 (feat: non-panicking `Vec::try_remove`) - rust-lang#146859 (BTreeMap: Don't leak allocators when initializing nodes) - rust-lang#146924 (Add doc for `NonZero*` const creation) - rust-lang#146933 (Make `render_example_with_highlighting` return an `impl fmt::Display`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents c5cdb3d + 99ea110 commit 0915c6f

File tree

7 files changed

+110
-29
lines changed

7 files changed

+110
-29
lines changed

alloc/src/collections/btree/map.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ pub struct BTreeMap<
194194
root: Option<Root<K, V>>,
195195
length: usize,
196196
/// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes).
197+
// Although some of the accessory types store a copy of the allocator, the nodes do not.
198+
// Because allocations will remain live as long as any copy (like this one) of the allocator
199+
// is live, it's unnecessary to store the allocator in each node.
197200
pub(super) alloc: ManuallyDrop<A>,
198201
// For dropck; the `Box` avoids making the `Unpin` impl more strict than before
199202
_marker: PhantomData<crate::boxed::Box<(K, V), A>>,

alloc/src/collections/btree/node.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
225225
}
226226

227227
fn from_new_leaf<A: Allocator + Clone>(leaf: Box<LeafNode<K, V>, A>) -> Self {
228-
NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData }
228+
// The allocator must be dropped, not leaked. See also `BTreeMap::alloc`.
229+
let (leaf, _alloc) = Box::into_raw_with_allocator(leaf);
230+
// SAFETY: the node was just allocated.
231+
let node = unsafe { NonNull::new_unchecked(leaf) };
232+
NodeRef { height: 0, node, _marker: PhantomData }
229233
}
230234
}
231235

@@ -243,7 +247,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
243247
height: usize,
244248
) -> Self {
245249
debug_assert!(height > 0);
246-
let node = NonNull::from(Box::leak(internal)).cast();
250+
// The allocator must be dropped, not leaked. See also `BTreeMap::alloc`.
251+
let (internal, _alloc) = Box::into_raw_with_allocator(internal);
252+
// SAFETY: the node was just allocated.
253+
let internal = unsafe { NonNull::new_unchecked(internal) };
254+
let node = internal.cast();
247255
let mut this = NodeRef { height, node, _marker: PhantomData };
248256
this.borrow_mut().correct_all_childrens_parent_links();
249257
this

alloc/src/vec/extract_if.rs

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,37 @@ where
6464
type Item = T;
6565

6666
fn next(&mut self) -> Option<T> {
67-
unsafe {
68-
while self.idx < self.end {
69-
let i = self.idx;
70-
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
71-
let drained = (self.pred)(&mut v[i]);
72-
// Update the index *after* the predicate is called. If the index
73-
// is updated prior and the predicate panics, the element at this
74-
// index would be leaked.
75-
self.idx += 1;
76-
if drained {
77-
self.del += 1;
78-
return Some(ptr::read(&v[i]));
79-
} else if self.del > 0 {
80-
let del = self.del;
81-
let src: *const T = &v[i];
82-
let dst: *mut T = &mut v[i - del];
83-
ptr::copy_nonoverlapping(src, dst, 1);
67+
while self.idx < self.end {
68+
let i = self.idx;
69+
// SAFETY:
70+
// We know that `i < self.end` from the if guard and that `self.end <= self.old_len` from
71+
// the validity of `Self`. Therefore `i` points to an element within `vec`.
72+
//
73+
// Additionally, the i-th element is valid because each element is visited at most once
74+
// and it is the first time we access vec[i].
75+
//
76+
// Note: we can't use `vec.get_unchecked_mut(i)` here since the precondition for that
77+
// function is that i < vec.len(), but we've set vec's length to zero.
78+
let cur = unsafe { &mut *self.vec.as_mut_ptr().add(i) };
79+
let drained = (self.pred)(cur);
80+
// Update the index *after* the predicate is called. If the index
81+
// is updated prior and the predicate panics, the element at this
82+
// index would be leaked.
83+
self.idx += 1;
84+
if drained {
85+
self.del += 1;
86+
// SAFETY: We never touch this element again after returning it.
87+
return Some(unsafe { ptr::read(cur) });
88+
} else if self.del > 0 {
89+
// SAFETY: `self.del` > 0, so the hole slot must not overlap with current element.
90+
// We use copy for move, and never touch this element again.
91+
unsafe {
92+
let hole_slot = self.vec.as_mut_ptr().add(i - self.del);
93+
ptr::copy_nonoverlapping(cur, hole_slot, 1);
8494
}
8595
}
86-
None
8796
}
97+
None
8898
}
8999

90100
fn size_hint(&self) -> (usize, Option<usize>) {
@@ -95,14 +105,18 @@ where
95105
#[stable(feature = "extract_if", since = "1.87.0")]
96106
impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> {
97107
fn drop(&mut self) {
98-
unsafe {
99-
if self.idx < self.old_len && self.del > 0 {
100-
let ptr = self.vec.as_mut_ptr();
101-
let src = ptr.add(self.idx);
102-
let dst = src.sub(self.del);
103-
let tail_len = self.old_len - self.idx;
104-
src.copy_to(dst, tail_len);
108+
if self.del > 0 {
109+
// SAFETY: Trailing unchecked items must be valid since we never touch them.
110+
unsafe {
111+
ptr::copy(
112+
self.vec.as_ptr().add(self.idx),
113+
self.vec.as_mut_ptr().add(self.idx - self.del),
114+
self.old_len - self.idx,
115+
);
105116
}
117+
}
118+
// SAFETY: After filling holes, all items are in contiguous memory.
119+
unsafe {
106120
self.vec.set_len(self.old_len - self.del);
107121
}
108122
}

alloc/src/vec/mod.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,9 +2173,37 @@ impl<T, A: Allocator> Vec<T, A> {
21732173
panic!("removal index (is {index}) should be < len (is {len})");
21742174
}
21752175

2176+
match self.try_remove(index) {
2177+
Some(elem) => elem,
2178+
None => assert_failed(index, self.len()),
2179+
}
2180+
}
2181+
2182+
/// Remove and return the element at position `index` within the vector,
2183+
/// shifting all elements after it to the left, or [`None`] if it does not
2184+
/// exist.
2185+
///
2186+
/// Note: Because this shifts over the remaining elements, it has a
2187+
/// worst-case performance of *O*(*n*). If you'd like to remove
2188+
/// elements from the beginning of the `Vec`, consider using
2189+
/// [`VecDeque::pop_front`] instead.
2190+
///
2191+
/// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front
2192+
///
2193+
/// # Examples
2194+
///
2195+
/// ```
2196+
/// #![feature(vec_try_remove)]
2197+
/// let mut v = vec![1, 2, 3];
2198+
/// assert_eq!(v.try_remove(0), Some(1));
2199+
/// assert_eq!(v.try_remove(2), None);
2200+
/// ```
2201+
#[unstable(feature = "vec_try_remove", issue = "146954")]
2202+
#[rustc_confusables("delete", "take", "remove")]
2203+
pub fn try_remove(&mut self, index: usize) -> Option<T> {
21762204
let len = self.len();
21772205
if index >= len {
2178-
assert_failed(index, len);
2206+
return None;
21792207
}
21802208
unsafe {
21812209
// infallible
@@ -2191,7 +2219,7 @@ impl<T, A: Allocator> Vec<T, A> {
21912219
ptr::copy(ptr.add(1), ptr, len - index - 1);
21922220
}
21932221
self.set_len(len - 1);
2194-
ret
2222+
Some(ret)
21952223
}
21962224
}
21972225

alloctests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#![feature(unique_rc_arc)]
4242
#![feature(macro_metavar_expr_concat)]
4343
#![feature(vec_peek_mut)]
44+
#![feature(vec_try_remove)]
4445
#![allow(internal_features)]
4546
#![deny(fuzzy_provenance_casts)]
4647
#![deny(unsafe_op_in_unsafe_fn)]

alloctests/tests/vec.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,21 @@ fn test_swap_remove_empty() {
630630
vec.swap_remove(0);
631631
}
632632

633+
#[test]
634+
fn test_try_remove() {
635+
let mut vec = vec![1, 2, 3];
636+
// We are attempting to remove vec[0] which contains 1
637+
assert_eq!(vec.try_remove(0), Some(1));
638+
// Now `vec` looks like: [2, 3]
639+
// We will now try to remove vec[2] which does not exist
640+
// This should return `None`
641+
assert_eq!(vec.try_remove(2), None);
642+
643+
// We will try the same thing with an empty vector
644+
let mut v: Vec<u8> = vec![];
645+
assert!(v.try_remove(0).is_none());
646+
}
647+
633648
#[test]
634649
fn test_move_items() {
635650
let vec = vec![1, 2, 3];

core/src/num/nonzero.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,18 @@ macro_rules! nonzero_integer {
548548
#[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::<Option<", stringify!($Ty), ">>());")]
549549
/// ```
550550
///
551+
/// # Compile-time creation
552+
///
553+
/// Since both [`Option::unwrap()`] and [`Option::expect()`] are `const`, it is possible to
554+
/// define a new
555+
#[doc = concat!("`", stringify!($Ty), "`")]
556+
/// at compile time via:
557+
/// ```
558+
#[doc = concat!("use std::num::", stringify!($Ty), ";")]
559+
///
560+
#[doc = concat!("const TEN: ", stringify!($Ty), " = ", stringify!($Ty) , r#"::new(10).expect("ten is non-zero");"#)]
561+
/// ```
562+
///
551563
/// [null pointer optimization]: crate::option#representation
552564
#[$stability]
553565
pub type $Ty = NonZero<$Int>;

0 commit comments

Comments
 (0)