1- // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
2- #![ allow( static_mut_refs) ]
3-
1+ use std:: cell:: Cell ;
42use std:: panic:: { AssertUnwindSafe , catch_unwind} ;
53use std:: thread;
64
@@ -58,48 +56,33 @@ fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
5856 v. iter ( ) . cloned ( ) . collect ( )
5957}
6058
59+ /// Starting from the head of the LinkedList,
60+ /// follow the next links, while checking the prev links,
61+ /// and check that length equals the count of visited nodes.
6162fn check_links < T > ( list : & LinkedList < T > ) {
62- unsafe {
63- let mut len = 0 ;
64- let mut last_ptr: Option < & Node < T > > = None ;
65- let mut node_ptr: & Node < T > ;
66- match list. head {
67- None => {
68- // tail node should also be None.
69- assert ! ( list. tail. is_none( ) ) ;
70- assert_eq ! ( 0 , list. len) ;
71- return ;
72- }
73- Some ( node) => node_ptr = & * node. as_ptr ( ) ,
74- }
75- loop {
76- match ( last_ptr, node_ptr. prev ) {
77- ( None , None ) => { }
78- ( None , _) => panic ! ( "prev link for head" ) ,
79- ( Some ( p) , Some ( pptr) ) => {
80- assert_eq ! ( p as * const Node <T >, pptr. as_ptr( ) as * const Node <T >) ;
81- }
82- _ => panic ! ( "prev link is none, not good" ) ,
83- }
84- match node_ptr. next {
85- Some ( next) => {
86- last_ptr = Some ( node_ptr) ;
87- node_ptr = & * next. as_ptr ( ) ;
88- len += 1 ;
89- }
90- None => {
91- len += 1 ;
92- break ;
93- }
94- }
95- }
96-
97- // verify that the tail node points to the last node.
98- let tail = list. tail . as_ref ( ) . expect ( "some tail node" ) . as_ref ( ) ;
99- assert_eq ! ( tail as * const Node <T >, node_ptr as * const Node <T >) ;
100- // check that len matches interior links.
101- assert_eq ! ( len, list. len) ;
63+ let mut node: & Node < T > = if let Some ( node) = list. head {
64+ // SAFETY: depends on correctness of LinkedList
65+ unsafe { & * node. as_ptr ( ) }
66+ } else {
67+ assert ! ( list. tail. is_none( ) , "empty list should have no tail node" ) ;
68+ assert_eq ! ( list. len, 0 , "empty list should have length 0" ) ;
69+ return ;
70+ } ;
71+
72+ assert ! ( node. prev. is_none( ) , "head node should not have a prev link" ) ;
73+ let mut prev;
74+ let mut len = 1 ;
75+ while let Some ( next) = node. next {
76+ prev = node;
77+ // SAFETY: depends on correctness of LinkedList
78+ node = unsafe { & * next. as_ptr ( ) } ;
79+ len += 1 ;
80+ assert_eq ! ( node. prev. expect( "missing prev link" ) , prev. into( ) , "bad prev link" ) ;
10281 }
82+
83+ let tail = list. tail . expect ( "list is non-empty, so there should be a tail node" ) ;
84+ assert_eq ! ( tail, node. into( ) , "tail node points to the last node" ) ;
85+ assert_eq ! ( len, list. len, "len matches interior links" ) ;
10386}
10487
10588#[ test]
@@ -1027,21 +1010,26 @@ fn extract_if_drop_panic_leak() {
10271010 assert_eq ! ( d7. dropped( ) , 1 ) ;
10281011}
10291012
1030- #[ test]
1031- #[ cfg_attr( not( panic = "unwind" ) , ignore = "test requires unwinding support" ) ]
1032- fn extract_if_pred_panic_leak ( ) {
1033- static mut DROPS : i32 = 0 ;
1013+ macro_rules! struct_with_counted_drop {
1014+ ( $struct_name: ident$( ( $elt_ty: ty) ) ?, $drop_counter: ident $( => $drop_stmt: expr) ?) => {
1015+ thread_local! { static $drop_counter: Cell <u32 > = Cell :: new( 0 ) ; }
1016+
1017+ struct $struct_name$( ( $elt_ty) ) ?;
10341018
1035- #[ derive( Debug ) ]
1036- struct D ( u32 ) ;
1019+ impl Drop for $struct_name {
1020+ fn drop( & mut self ) {
1021+ $drop_counter. set( $drop_counter. get( ) + 1 ) ;
10371022
1038- impl Drop for D {
1039- fn drop ( & mut self ) {
1040- unsafe {
1041- DROPS += 1 ;
1023+ $( $drop_stmt( self ) ) ?
10421024 }
10431025 }
1044- }
1026+ } ;
1027+ }
1028+
1029+ #[ test]
1030+ #[ cfg_attr( not( panic = "unwind" ) , ignore = "test requires unwinding support" ) ]
1031+ fn extract_if_pred_panic_leak ( ) {
1032+ struct_with_counted_drop ! ( D ( u32 ) , DROPS ) ;
10451033
10461034 let mut q = LinkedList :: new ( ) ;
10471035 q. push_back ( D ( 3 ) ) ;
@@ -1053,26 +1041,17 @@ fn extract_if_pred_panic_leak() {
10531041 q. push_front ( D ( 1 ) ) ;
10541042 q. push_front ( D ( 0 ) ) ;
10551043
1056- catch_unwind ( AssertUnwindSafe ( || {
1044+ _ = catch_unwind ( AssertUnwindSafe ( || {
10571045 q. extract_if ( |item| if item. 0 >= 2 { panic ! ( ) } else { true } ) . for_each ( drop)
1058- } ) )
1059- . ok ( ) ;
1046+ } ) ) ;
10601047
1061- assert_eq ! ( unsafe { DROPS } , 2 ) ; // 0 and 1
1048+ assert_eq ! ( DROPS . get ( ) , 2 ) ; // 0 and 1
10621049 assert_eq ! ( q. len( ) , 6 ) ;
10631050}
10641051
10651052#[ test]
10661053fn test_drop ( ) {
1067- static mut DROPS : i32 = 0 ;
1068- struct Elem ;
1069- impl Drop for Elem {
1070- fn drop ( & mut self ) {
1071- unsafe {
1072- DROPS += 1 ;
1073- }
1074- }
1075- }
1054+ struct_with_counted_drop ! ( Elem , DROPS ) ;
10761055
10771056 let mut ring = LinkedList :: new ( ) ;
10781057 ring. push_back ( Elem ) ;
@@ -1081,20 +1060,12 @@ fn test_drop() {
10811060 ring. push_front ( Elem ) ;
10821061 drop ( ring) ;
10831062
1084- assert_eq ! ( unsafe { DROPS } , 4 ) ;
1063+ assert_eq ! ( DROPS . get ( ) , 4 ) ;
10851064}
10861065
10871066#[ test]
10881067fn test_drop_with_pop ( ) {
1089- static mut DROPS : i32 = 0 ;
1090- struct Elem ;
1091- impl Drop for Elem {
1092- fn drop ( & mut self ) {
1093- unsafe {
1094- DROPS += 1 ;
1095- }
1096- }
1097- }
1068+ struct_with_counted_drop ! ( Elem , DROPS ) ;
10981069
10991070 let mut ring = LinkedList :: new ( ) ;
11001071 ring. push_back ( Elem ) ;
@@ -1104,54 +1075,32 @@ fn test_drop_with_pop() {
11041075
11051076 drop ( ring. pop_back ( ) ) ;
11061077 drop ( ring. pop_front ( ) ) ;
1107- assert_eq ! ( unsafe { DROPS } , 2 ) ;
1078+ assert_eq ! ( DROPS . get ( ) , 2 ) ;
11081079
11091080 drop ( ring) ;
1110- assert_eq ! ( unsafe { DROPS } , 4 ) ;
1081+ assert_eq ! ( DROPS . get ( ) , 4 ) ;
11111082}
11121083
11131084#[ test]
11141085fn test_drop_clear ( ) {
1115- static mut DROPS : i32 = 0 ;
1116- struct Elem ;
1117- impl Drop for Elem {
1118- fn drop ( & mut self ) {
1119- unsafe {
1120- DROPS += 1 ;
1121- }
1122- }
1123- }
1086+ struct_with_counted_drop ! ( Elem , DROPS ) ;
11241087
11251088 let mut ring = LinkedList :: new ( ) ;
11261089 ring. push_back ( Elem ) ;
11271090 ring. push_front ( Elem ) ;
11281091 ring. push_back ( Elem ) ;
11291092 ring. push_front ( Elem ) ;
11301093 ring. clear ( ) ;
1131- assert_eq ! ( unsafe { DROPS } , 4 ) ;
1094+ assert_eq ! ( DROPS . get ( ) , 4 ) ;
11321095
11331096 drop ( ring) ;
1134- assert_eq ! ( unsafe { DROPS } , 4 ) ;
1097+ assert_eq ! ( DROPS . get ( ) , 4 ) ;
11351098}
11361099
11371100#[ test]
11381101#[ cfg_attr( not( panic = "unwind" ) , ignore = "test requires unwinding support" ) ]
11391102fn test_drop_panic ( ) {
1140- static mut DROPS : i32 = 0 ;
1141-
1142- struct D ( bool ) ;
1143-
1144- impl Drop for D {
1145- fn drop ( & mut self ) {
1146- unsafe {
1147- DROPS += 1 ;
1148- }
1149-
1150- if self . 0 {
1151- panic ! ( "panic in `drop`" ) ;
1152- }
1153- }
1154- }
1103+ struct_with_counted_drop ! ( D ( bool ) , DROPS => |this: & D | if this. 0 { panic!( "panic in `drop`" ) ; } ) ;
11551104
11561105 let mut q = LinkedList :: new ( ) ;
11571106 q. push_back ( D ( false ) ) ;
@@ -1165,7 +1114,7 @@ fn test_drop_panic() {
11651114
11661115 catch_unwind ( move || drop ( q) ) . ok ( ) ;
11671116
1168- assert_eq ! ( unsafe { DROPS } , 8 ) ;
1117+ assert_eq ! ( DROPS . get ( ) , 8 ) ;
11691118}
11701119
11711120#[ test]
0 commit comments