@@ -1351,24 +1351,85 @@ fn test_try_reserve_exact() {
13511351}
13521352
13531353#[ test]
1354- fn test_stable_push_pop ( ) {
1354+ fn test_stable_pointers ( ) {
1355+ /// Pull an element from the iterator, then drop it.
1356+ /// Useful to cover both the `next` and `drop` paths of an iterator.
1357+ fn next_then_drop < I : Iterator > ( mut i : I ) {
1358+ i. next ( ) . unwrap ( ) ;
1359+ drop ( i) ;
1360+ }
1361+
13551362 // Test that, if we reserved enough space, adding and removing elements does not
13561363 // invalidate references into the vector (such as `v0`). This test also
13571364 // runs in Miri, which would detect such problems.
1358- let mut v = Vec :: with_capacity ( 10 ) ;
1365+ let mut v = Vec :: with_capacity ( 128 ) ;
13591366 v. push ( 13 ) ;
13601367
1361- // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
1362- let v0 = unsafe { & * ( & v[ 0 ] as * const _ ) } ;
1363-
1368+ // Laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
1369+ let v0 = & mut v[ 0 ] ;
1370+ let v0 = unsafe { & mut * ( v0 as * mut _ ) } ;
13641371 // Now do a bunch of things and occasionally use `v0` again to assert it is still valid.
1372+
1373+ // Pushing/inserting and popping/removing
13651374 v. push ( 1 ) ;
13661375 v. push ( 2 ) ;
13671376 v. insert ( 1 , 1 ) ;
13681377 assert_eq ! ( * v0, 13 ) ;
13691378 v. remove ( 1 ) ;
13701379 v. pop ( ) . unwrap ( ) ;
13711380 assert_eq ! ( * v0, 13 ) ;
1381+ v. push ( 1 ) ;
1382+ v. swap_remove ( 1 ) ;
1383+ assert_eq ! ( v. len( ) , 2 ) ;
1384+ v. swap_remove ( 1 ) ; // swap_remove the last element
1385+ assert_eq ! ( * v0, 13 ) ;
1386+
1387+ // Appending
1388+ v. append ( & mut vec ! [ 27 , 19 ] ) ;
1389+ assert_eq ! ( * v0, 13 ) ;
1390+
1391+ // Extending
1392+ v. extend_from_slice ( & [ 1 , 2 ] ) ;
1393+ v. extend ( & [ 1 , 2 ] ) ; // `slice::Iter` (with `T: Copy`) specialization
1394+ v. extend ( vec ! [ 2 , 3 ] ) ; // `vec::IntoIter` specialization
1395+ v. extend ( std:: iter:: once ( 3 ) ) ; // `TrustedLen` specialization
1396+ v. extend ( std:: iter:: empty :: < i32 > ( ) ) ; // `TrustedLen` specialization with empty iterator
1397+ v. extend ( std:: iter:: once ( 3 ) . filter ( |_| true ) ) ; // base case
1398+ v. extend ( std:: iter:: once ( & 3 ) ) ; // `cloned` specialization
1399+ assert_eq ! ( * v0, 13 ) ;
1400+
1401+ // Truncation
1402+ v. truncate ( 2 ) ;
1403+ assert_eq ! ( * v0, 13 ) ;
1404+
1405+ // Resizing
1406+ v. resize_with ( v. len ( ) + 10 , || 42 ) ;
1407+ assert_eq ! ( * v0, 13 ) ;
1408+ v. resize_with ( 2 , || panic ! ( ) ) ;
1409+ assert_eq ! ( * v0, 13 ) ;
1410+
1411+ // No-op reservation
1412+ v. reserve ( 32 ) ;
1413+ v. reserve_exact ( 32 ) ;
1414+ assert_eq ! ( * v0, 13 ) ;
1415+
1416+ // Partial draining
1417+ v. resize_with ( 10 , || 42 ) ;
1418+ next_then_drop ( v. drain ( 5 ..) ) ;
1419+ assert_eq ! ( * v0, 13 ) ;
1420+
1421+ // Splicing
1422+ v. resize_with ( 10 , || 42 ) ;
1423+ next_then_drop ( v. splice ( 5 .., vec ! [ 1 , 2 , 3 , 4 , 5 ] ) ) ; // empty tail after range
1424+ assert_eq ! ( * v0, 13 ) ;
1425+ next_then_drop ( v. splice ( 5 ..8 , vec ! [ 1 ] ) ) ; // replacement is smaller than original range
1426+ assert_eq ! ( * v0, 13 ) ;
1427+ next_then_drop ( v. splice ( 5 ..6 , vec ! [ 1 ; 10 ] . into_iter ( ) . filter ( |_| true ) ) ) ; // lower bound not exact
1428+ assert_eq ! ( * v0, 13 ) ;
1429+
1430+ // Smoke test that would fire even outside Miri if an actual relocation happened.
1431+ * v0 -= 13 ;
1432+ assert_eq ! ( v[ 0 ] , 0 ) ;
13721433}
13731434
13741435// https://github.com/rust-lang/rust/pull/49496 introduced specialization based on:
0 commit comments