Skip to content

Commit aed50ba

Browse files
authored
Rollup merge of #99386 - AngelicosPhosphoros:add_retain_test_maybeuninit, r=JohnTitor
Add tests that check `Vec::retain` predicate execution order. This behaviour is documented for `Vec::retain` which means that there is code that rely on that but there weren't tests about that.
2 parents 728f536 + 9bc0713 commit aed50ba

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

alloc/tests/vec.rs

+45
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,22 @@ fn test_retain() {
293293
assert_eq!(vec, [2, 4]);
294294
}
295295

296+
#[test]
297+
fn test_retain_predicate_order() {
298+
for to_keep in [true, false] {
299+
let mut number_of_executions = 0;
300+
let mut vec = vec![1, 2, 3, 4];
301+
let mut next_expected = 1;
302+
vec.retain(|&x| {
303+
assert_eq!(next_expected, x);
304+
next_expected += 1;
305+
number_of_executions += 1;
306+
to_keep
307+
});
308+
assert_eq!(number_of_executions, 4);
309+
}
310+
}
311+
296312
#[test]
297313
fn test_retain_pred_panic_with_hole() {
298314
let v = (0..5).map(Rc::new).collect::<Vec<_>>();
@@ -354,6 +370,35 @@ fn test_retain_drop_panic() {
354370
assert!(v.iter().all(|r| Rc::strong_count(r) == 1));
355371
}
356372

373+
#[test]
374+
fn test_retain_maybeuninits() {
375+
// This test aimed to be run under miri.
376+
use core::mem::MaybeUninit;
377+
let mut vec: Vec<_> = [1i32, 2, 3, 4].map(|v| MaybeUninit::new(vec![v])).into();
378+
vec.retain(|x| {
379+
// SAFETY: Retain must visit every element of Vec in original order and exactly once.
380+
// Our values is initialized at creation of Vec.
381+
let v = unsafe { x.assume_init_ref()[0] };
382+
if v & 1 == 0 {
383+
return true;
384+
}
385+
// SAFETY: Value is initialized.
386+
// Value wouldn't be dropped by `Vec::retain`
387+
// because `MaybeUninit` doesn't drop content.
388+
drop(unsafe { x.assume_init_read() });
389+
false
390+
});
391+
let vec: Vec<i32> = vec
392+
.into_iter()
393+
.map(|x| unsafe {
394+
// SAFETY: All values dropped in retain predicate must be removed by `Vec::retain`.
395+
// Remaining values are initialized.
396+
x.assume_init()[0]
397+
})
398+
.collect();
399+
assert_eq!(vec, [2, 4]);
400+
}
401+
357402
#[test]
358403
fn test_dedup() {
359404
fn case(a: Vec<i32>, b: Vec<i32>) {

0 commit comments

Comments
 (0)