From 85a9c741588aaf296ce94f480e342c2bf5c131ba Mon Sep 17 00:00:00 2001 From: AngelicosPhosphoros Date: Sun, 17 Jul 2022 23:33:29 +0300 Subject: [PATCH] Add tests that check `Vec::retain` predicate execution order. --- library/alloc/tests/vec.rs | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 5520f6ebf1904..b17f7a8eebc56 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -292,6 +292,22 @@ fn test_retain() { assert_eq!(vec, [2, 4]); } +#[test] +fn test_retain_predicate_order() { + for to_keep in [true, false] { + let mut number_of_executions = 0; + let mut vec = vec![1, 2, 3, 4]; + let mut next_expected = 1; + vec.retain(|&x| { + assert_eq!(next_expected, x); + next_expected += 1; + number_of_executions += 1; + to_keep + }); + assert_eq!(number_of_executions, 4); + } +} + #[test] fn test_retain_pred_panic_with_hole() { let v = (0..5).map(Rc::new).collect::>(); @@ -353,6 +369,35 @@ fn test_retain_drop_panic() { assert!(v.iter().all(|r| Rc::strong_count(r) == 1)); } +#[test] +fn test_retain_maybeuninits() { + // This test aimed to be run under miri. + use core::mem::MaybeUninit; + let mut vec: Vec<_> = [1i32, 2, 3, 4].map(|v| MaybeUninit::new(vec![v])).into(); + vec.retain(|x| { + // SAFETY: Retain must visit every element of Vec in original order and exactly once. + // Our values is initialized at creation of Vec. + let v = unsafe { x.assume_init_ref()[0] }; + if v & 1 == 0 { + return true; + } + // SAFETY: Value is initialized. + // Value wouldn't be dropped by `Vec::retain` + // because `MaybeUninit` doesn't drop content. + drop(unsafe { x.assume_init_read() }); + false + }); + let vec: Vec = vec + .into_iter() + .map(|x| unsafe { + // SAFETY: All values dropped in retain predicate must be removed by `Vec::retain`. + // Remaining values are initialized. + x.assume_init()[0] + }) + .collect(); + assert_eq!(vec, [2, 4]); +} + #[test] fn test_dedup() { fn case(a: Vec, b: Vec) {