1
- // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
2
- #![ allow( static_mut_refs) ]
3
-
1
+ use std:: cell:: Cell ;
4
2
use std:: panic:: { AssertUnwindSafe , catch_unwind} ;
5
3
use std:: thread;
6
4
@@ -58,48 +56,33 @@ fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
58
56
v. iter ( ) . cloned ( ) . collect ( )
59
57
}
60
58
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.
61
62
fn 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" ) ;
102
81
}
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" ) ;
103
86
}
104
87
105
88
#[ test]
@@ -1027,21 +1010,26 @@ fn extract_if_drop_panic_leak() {
1027
1010
assert_eq ! ( d7. dropped( ) , 1 ) ;
1028
1011
}
1029
1012
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) ) ?;
1034
1018
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 ) ;
1037
1022
1038
- impl Drop for D {
1039
- fn drop ( & mut self ) {
1040
- unsafe {
1041
- DROPS += 1 ;
1023
+ $( $drop_stmt( self ) ) ?
1042
1024
}
1043
1025
}
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 ) ;
1045
1033
1046
1034
let mut q = LinkedList :: new ( ) ;
1047
1035
q. push_back ( D ( 3 ) ) ;
@@ -1053,26 +1041,17 @@ fn extract_if_pred_panic_leak() {
1053
1041
q. push_front ( D ( 1 ) ) ;
1054
1042
q. push_front ( D ( 0 ) ) ;
1055
1043
1056
- catch_unwind ( AssertUnwindSafe ( || {
1044
+ _ = catch_unwind ( AssertUnwindSafe ( || {
1057
1045
q. extract_if ( |item| if item. 0 >= 2 { panic ! ( ) } else { true } ) . for_each ( drop)
1058
- } ) )
1059
- . ok ( ) ;
1046
+ } ) ) ;
1060
1047
1061
- assert_eq ! ( unsafe { DROPS } , 2 ) ; // 0 and 1
1048
+ assert_eq ! ( DROPS . get ( ) , 2 ) ; // 0 and 1
1062
1049
assert_eq ! ( q. len( ) , 6 ) ;
1063
1050
}
1064
1051
1065
1052
#[ test]
1066
1053
fn 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 ) ;
1076
1055
1077
1056
let mut ring = LinkedList :: new ( ) ;
1078
1057
ring. push_back ( Elem ) ;
@@ -1081,20 +1060,12 @@ fn test_drop() {
1081
1060
ring. push_front ( Elem ) ;
1082
1061
drop ( ring) ;
1083
1062
1084
- assert_eq ! ( unsafe { DROPS } , 4 ) ;
1063
+ assert_eq ! ( DROPS . get ( ) , 4 ) ;
1085
1064
}
1086
1065
1087
1066
#[ test]
1088
1067
fn 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 ) ;
1098
1069
1099
1070
let mut ring = LinkedList :: new ( ) ;
1100
1071
ring. push_back ( Elem ) ;
@@ -1104,54 +1075,32 @@ fn test_drop_with_pop() {
1104
1075
1105
1076
drop ( ring. pop_back ( ) ) ;
1106
1077
drop ( ring. pop_front ( ) ) ;
1107
- assert_eq ! ( unsafe { DROPS } , 2 ) ;
1078
+ assert_eq ! ( DROPS . get ( ) , 2 ) ;
1108
1079
1109
1080
drop ( ring) ;
1110
- assert_eq ! ( unsafe { DROPS } , 4 ) ;
1081
+ assert_eq ! ( DROPS . get ( ) , 4 ) ;
1111
1082
}
1112
1083
1113
1084
#[ test]
1114
1085
fn 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 ) ;
1124
1087
1125
1088
let mut ring = LinkedList :: new ( ) ;
1126
1089
ring. push_back ( Elem ) ;
1127
1090
ring. push_front ( Elem ) ;
1128
1091
ring. push_back ( Elem ) ;
1129
1092
ring. push_front ( Elem ) ;
1130
1093
ring. clear ( ) ;
1131
- assert_eq ! ( unsafe { DROPS } , 4 ) ;
1094
+ assert_eq ! ( DROPS . get ( ) , 4 ) ;
1132
1095
1133
1096
drop ( ring) ;
1134
- assert_eq ! ( unsafe { DROPS } , 4 ) ;
1097
+ assert_eq ! ( DROPS . get ( ) , 4 ) ;
1135
1098
}
1136
1099
1137
1100
#[ test]
1138
1101
#[ cfg_attr( not( panic = "unwind" ) , ignore = "test requires unwinding support" ) ]
1139
1102
fn 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`" ) ; } ) ;
1155
1104
1156
1105
let mut q = LinkedList :: new ( ) ;
1157
1106
q. push_back ( D ( false ) ) ;
@@ -1165,7 +1114,7 @@ fn test_drop_panic() {
1165
1114
1166
1115
catch_unwind ( move || drop ( q) ) . ok ( ) ;
1167
1116
1168
- assert_eq ! ( unsafe { DROPS } , 8 ) ;
1117
+ assert_eq ! ( DROPS . get ( ) , 8 ) ;
1169
1118
}
1170
1119
1171
1120
#[ test]
0 commit comments