@@ -3,6 +3,7 @@ use std::collections::BTreeMap;
33use std:: convert:: TryFrom ;
44use std:: fmt:: Debug ;
55use std:: iter:: FromIterator ;
6+ use std:: mem;
67use std:: ops:: Bound :: { self , Excluded , Included , Unbounded } ;
78use std:: ops:: RangeBounds ;
89use std:: panic:: { catch_unwind, AssertUnwindSafe } ;
@@ -25,6 +26,20 @@ const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1;
2526// It's not the minimum size: removing an element from such a tree does not always reduce height.
2627const MIN_INSERTS_HEIGHT_2 : usize = NODE_CAPACITY + ( NODE_CAPACITY + 1 ) * NODE_CAPACITY + 1 ;
2728
29+ // Gather all references from a mutable iterator and make sure Miri notices if
30+ // using them is dangerous.
31+ fn test_all_refs < ' a , T : ' a > ( dummy : & mut T , iter : impl Iterator < Item = & ' a mut T > ) {
32+ // Gather all those references.
33+ let mut refs: Vec < & mut T > = iter. collect ( ) ;
34+ // Use them all. Twice, to be sure we got all interleavings.
35+ for r in refs. iter_mut ( ) {
36+ mem:: swap ( dummy, r) ;
37+ }
38+ for r in refs {
39+ mem:: swap ( dummy, r) ;
40+ }
41+ }
42+
2843#[ test]
2944fn test_basic_large ( ) {
3045 let mut map = BTreeMap :: new ( ) ;
@@ -268,7 +283,14 @@ fn test_iter_mut_mutation() {
268283}
269284
270285#[ test]
286+ #[ cfg_attr( miri, ignore) ] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
271287fn test_values_mut ( ) {
288+ let mut a: BTreeMap < _ , _ > = ( 0 ..MIN_INSERTS_HEIGHT_2 ) . map ( |i| ( i, i) ) . collect ( ) ;
289+ test_all_refs ( & mut 13 , a. values_mut ( ) ) ;
290+ }
291+
292+ #[ test]
293+ fn test_values_mut_mutation ( ) {
272294 let mut a = BTreeMap :: new ( ) ;
273295 a. insert ( 1 , String :: from ( "hello" ) ) ;
274296 a. insert ( 2 , String :: from ( "goodbye" ) ) ;
@@ -281,6 +303,36 @@ fn test_values_mut() {
281303 assert_eq ! ( values, [ String :: from( "hello!" ) , String :: from( "goodbye!" ) ] ) ;
282304}
283305
306+ #[ test]
307+ #[ cfg_attr( miri, ignore) ] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
308+ fn test_iter_entering_root_twice ( ) {
309+ let mut map: BTreeMap < _ , _ > = ( 0 ..2 ) . map ( |i| ( i, i) ) . collect ( ) ;
310+ let mut it = map. iter_mut ( ) ;
311+ let front = it. next ( ) . unwrap ( ) ;
312+ let back = it. next_back ( ) . unwrap ( ) ;
313+ assert_eq ! ( front, ( & 0 , & mut 0 ) ) ;
314+ assert_eq ! ( back, ( & 1 , & mut 1 ) ) ;
315+ * front. 1 = 24 ;
316+ * back. 1 = 42 ;
317+ assert_eq ! ( front, ( & 0 , & mut 24 ) ) ;
318+ assert_eq ! ( back, ( & 1 , & mut 42 ) ) ;
319+ }
320+
321+ #[ test]
322+ #[ cfg_attr( miri, ignore) ] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
323+ fn test_iter_descending_to_same_node_twice ( ) {
324+ let mut map: BTreeMap < _ , _ > = ( 0 ..MIN_INSERTS_HEIGHT_1 ) . map ( |i| ( i, i) ) . collect ( ) ;
325+ let mut it = map. iter_mut ( ) ;
326+ // Descend into first child.
327+ let front = it. next ( ) . unwrap ( ) ;
328+ // Descend into first child again, after running through second child.
329+ while it. next_back ( ) . is_some ( ) { }
330+ // Check immutable access.
331+ assert_eq ! ( front, ( & 0 , & mut 0 ) ) ;
332+ // Perform mutable access.
333+ * front. 1 = 42 ;
334+ }
335+
284336#[ test]
285337fn test_iter_mixed ( ) {
286338 // Miri is too slow
@@ -835,18 +887,16 @@ mod test_drain_filter {
835887 }
836888 }
837889
838- let mut map = BTreeMap :: new ( ) ;
839- map. insert ( 0 , D ) ;
840- map. insert ( 4 , D ) ;
841- map. insert ( 8 , D ) ;
890+ // Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
891+ let mut map = ( 0 ..3 ) . map ( |i| ( i * 4 , D ) ) . collect :: < BTreeMap < _ , _ > > ( ) ;
842892
843893 catch_unwind ( move || {
844894 drop ( map. drain_filter ( |i, _| {
845895 PREDS . fetch_add ( 1usize << i, Ordering :: SeqCst ) ;
846896 true
847897 } ) )
848898 } )
849- . ok ( ) ;
899+ . unwrap_err ( ) ;
850900
851901 assert_eq ! ( PREDS . load( Ordering :: SeqCst ) , 0x011 ) ;
852902 assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 3 ) ;
@@ -864,10 +914,8 @@ mod test_drain_filter {
864914 }
865915 }
866916
867- let mut map = BTreeMap :: new ( ) ;
868- map. insert ( 0 , D ) ;
869- map. insert ( 4 , D ) ;
870- map. insert ( 8 , D ) ;
917+ // Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
918+ let mut map = ( 0 ..3 ) . map ( |i| ( i * 4 , D ) ) . collect :: < BTreeMap < _ , _ > > ( ) ;
871919
872920 catch_unwind ( AssertUnwindSafe ( || {
873921 drop ( map. drain_filter ( |i, _| {
@@ -878,7 +926,45 @@ mod test_drain_filter {
878926 }
879927 } ) )
880928 } ) )
881- . ok ( ) ;
929+ . unwrap_err ( ) ;
930+
931+ assert_eq ! ( PREDS . load( Ordering :: SeqCst ) , 0x011 ) ;
932+ assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 1 ) ;
933+ assert_eq ! ( map. len( ) , 2 ) ;
934+ assert_eq ! ( map. first_entry( ) . unwrap( ) . key( ) , & 4 ) ;
935+ assert_eq ! ( map. last_entry( ) . unwrap( ) . key( ) , & 8 ) ;
936+ }
937+
938+ // Same as above, but attempt to use the iterator again after the panic in the predicate
939+ #[ test]
940+ fn pred_panic_reuse ( ) {
941+ static PREDS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
942+ static DROPS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
943+
944+ struct D ;
945+ impl Drop for D {
946+ fn drop ( & mut self ) {
947+ DROPS . fetch_add ( 1 , Ordering :: SeqCst ) ;
948+ }
949+ }
950+
951+ // Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
952+ let mut map = ( 0 ..3 ) . map ( |i| ( i * 4 , D ) ) . collect :: < BTreeMap < _ , _ > > ( ) ;
953+
954+ {
955+ let mut it = map. drain_filter ( |i, _| {
956+ PREDS . fetch_add ( 1usize << i, Ordering :: SeqCst ) ;
957+ match i {
958+ 0 => true ,
959+ _ => panic ! ( ) ,
960+ }
961+ } ) ;
962+ catch_unwind ( AssertUnwindSafe ( || while it. next ( ) . is_some ( ) { } ) ) . unwrap_err ( ) ;
963+ // Iterator behaviour after a panic is explicitly unspecified,
964+ // so this is just the current implementation:
965+ let result = catch_unwind ( AssertUnwindSafe ( || it. next ( ) ) ) ;
966+ assert ! ( matches!( result, Ok ( None ) ) ) ;
967+ }
882968
883969 assert_eq ! ( PREDS . load( Ordering :: SeqCst ) , 0x011 ) ;
884970 assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 1 ) ;
@@ -1283,6 +1369,34 @@ fn test_split_off_empty_left() {
12831369 assert ! ( right. into_iter( ) . eq( data) ) ;
12841370}
12851371
1372+ // In a tree with 3 levels, if all but a part of the first leaf node is split off,
1373+ // make sure fix_top eliminates both top levels.
1374+ #[ test]
1375+ fn test_split_off_tiny_left_height_2 ( ) {
1376+ let pairs = ( 0 ..MIN_INSERTS_HEIGHT_2 ) . map ( |i| ( i, i) ) ;
1377+ let mut left: BTreeMap < _ , _ > = pairs. clone ( ) . collect ( ) ;
1378+ let right = left. split_off ( & 1 ) ;
1379+ assert_eq ! ( left. len( ) , 1 ) ;
1380+ assert_eq ! ( right. len( ) , MIN_INSERTS_HEIGHT_2 - 1 ) ;
1381+ assert_eq ! ( * left. first_key_value( ) . unwrap( ) . 0 , 0 ) ;
1382+ assert_eq ! ( * right. first_key_value( ) . unwrap( ) . 0 , 1 ) ;
1383+ }
1384+
1385+ // In a tree with 3 levels, if only part of the last leaf node is split off,
1386+ // make sure fix_top eliminates both top levels.
1387+ #[ test]
1388+ fn test_split_off_tiny_right_height_2 ( ) {
1389+ let pairs = ( 0 ..MIN_INSERTS_HEIGHT_2 ) . map ( |i| ( i, i) ) ;
1390+ let last = MIN_INSERTS_HEIGHT_2 - 1 ;
1391+ let mut left: BTreeMap < _ , _ > = pairs. clone ( ) . collect ( ) ;
1392+ assert_eq ! ( * left. last_key_value( ) . unwrap( ) . 0 , last) ;
1393+ let right = left. split_off ( & last) ;
1394+ assert_eq ! ( left. len( ) , MIN_INSERTS_HEIGHT_2 - 1 ) ;
1395+ assert_eq ! ( right. len( ) , 1 ) ;
1396+ assert_eq ! ( * left. last_key_value( ) . unwrap( ) . 0 , last - 1 ) ;
1397+ assert_eq ! ( * right. last_key_value( ) . unwrap( ) . 0 , last) ;
1398+ }
1399+
12861400#[ test]
12871401fn test_split_off_large_random_sorted ( ) {
12881402 // Miri is too slow
@@ -1319,7 +1433,7 @@ fn test_into_iter_drop_leak_height_0() {
13191433 map. insert ( "d" , D ) ;
13201434 map. insert ( "e" , D ) ;
13211435
1322- catch_unwind ( move || drop ( map. into_iter ( ) ) ) . ok ( ) ;
1436+ catch_unwind ( move || drop ( map. into_iter ( ) ) ) . unwrap_err ( ) ;
13231437
13241438 assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 5 ) ;
13251439}
@@ -1343,7 +1457,7 @@ fn test_into_iter_drop_leak_height_1() {
13431457 DROPS . store ( 0 , Ordering :: SeqCst ) ;
13441458 PANIC_POINT . store ( panic_point, Ordering :: SeqCst ) ;
13451459 let map: BTreeMap < _ , _ > = ( 0 ..size) . map ( |i| ( i, D ) ) . collect ( ) ;
1346- catch_unwind ( move || drop ( map. into_iter ( ) ) ) . ok ( ) ;
1460+ catch_unwind ( move || drop ( map. into_iter ( ) ) ) . unwrap_err ( ) ;
13471461 assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , size) ;
13481462 }
13491463}
0 commit comments