@@ -6,7 +6,7 @@ use clang::{self, Cursor};
6
6
use parse:: ClangItemParser ;
7
7
use std:: borrow:: Cow ;
8
8
use std:: cell:: Cell ;
9
- use std:: collections:: { HashMap , hash_map} ;
9
+ use std:: collections:: { HashMap , VecDeque , hash_map} ;
10
10
use std:: collections:: btree_map:: { self , BTreeMap } ;
11
11
use std:: fmt;
12
12
use super :: int:: IntKind ;
@@ -399,18 +399,33 @@ impl<'ctx> BindgenContext<'ctx> {
399
399
continue ;
400
400
}
401
401
402
- if let Some ( mut module) = self . items . get_mut ( & old_parent) . unwrap ( ) . as_module_mut ( ) {
402
+ if let Some ( mut module) = self . items
403
+ . get_mut ( & old_parent)
404
+ . unwrap ( )
405
+ . as_module_mut ( ) {
403
406
// Deparent the replacement.
404
- let position = module. children ( ) . iter ( ) . position ( |id| * id == replacement) . unwrap ( ) ;
407
+ let position = module. children ( )
408
+ . iter ( )
409
+ . position ( |id| * id == replacement)
410
+ . unwrap ( ) ;
405
411
module. children_mut ( ) . remove ( position) ;
406
412
}
407
413
408
- if let Some ( mut module) = self . items . get_mut ( & new_parent) . unwrap ( ) . as_module_mut ( ) {
414
+ if let Some ( mut module) = self . items
415
+ . get_mut ( & new_parent)
416
+ . unwrap ( )
417
+ . as_module_mut ( ) {
409
418
module. children_mut ( ) . push ( replacement) ;
410
419
}
411
420
412
- self . items . get_mut ( & replacement) . unwrap ( ) . set_parent_for_replacement ( new_parent) ;
413
- self . items . get_mut ( & id) . unwrap ( ) . set_parent_for_replacement ( old_parent) ;
421
+ self . items
422
+ . get_mut ( & replacement)
423
+ . unwrap ( )
424
+ . set_parent_for_replacement ( new_parent) ;
425
+ self . items
426
+ . get_mut ( & id)
427
+ . unwrap ( )
428
+ . set_parent_for_replacement ( old_parent) ;
414
429
}
415
430
}
416
431
@@ -428,8 +443,7 @@ impl<'ctx> BindgenContext<'ctx> {
428
443
let cfg = ExpansionConfig :: default ( "xxx" . to_owned ( ) ) ;
429
444
let sess = parse:: ParseSess :: new ( ) ;
430
445
let mut loader = base:: DummyResolver ;
431
- let mut ctx =
432
- GenContext ( base:: ExtCtxt :: new ( & sess, cfg, & mut loader) ) ;
446
+ let mut ctx = GenContext ( base:: ExtCtxt :: new ( & sess, cfg, & mut loader) ) ;
433
447
434
448
ctx. 0 . bt_push ( ExpnInfo {
435
449
call_site : self . span ,
@@ -445,6 +459,8 @@ impl<'ctx> BindgenContext<'ctx> {
445
459
// because we remove it before the end of this function.
446
460
self . gen_ctx = Some ( unsafe { mem:: transmute ( & ctx) } ) ;
447
461
462
+ self . assert_no_dangling_references ( ) ;
463
+
448
464
if !self . collected_typerefs ( ) {
449
465
self . resolve_typerefs ( ) ;
450
466
self . process_replacements ( ) ;
@@ -455,6 +471,36 @@ impl<'ctx> BindgenContext<'ctx> {
455
471
ret
456
472
}
457
473
474
+ /// This function trying to find any dangling references inside of `items`
475
+ fn assert_no_dangling_references ( & self ) {
476
+ if cfg ! ( debug_assertions) {
477
+ for _ in self . assert_no_dangling_item_traversal ( ) {
478
+ // The iterator's next method does the asserting for us.
479
+ }
480
+ }
481
+ }
482
+
483
+ fn assert_no_dangling_item_traversal < ' me >
484
+ ( & ' me self )
485
+ -> AssertNoDanglingItemIter < ' me , ' ctx > {
486
+ assert ! ( self . in_codegen_phase( ) ) ;
487
+ assert ! ( self . current_module == self . root_module) ;
488
+
489
+ let mut roots = self . items ( ) . map ( |( & id, _) | id) ;
490
+
491
+ let mut seen = BTreeMap :: < ItemId , ItemId > :: new ( ) ;
492
+ let next_child = roots. next ( ) . map ( |id| id) . unwrap ( ) ;
493
+ seen. insert ( next_child, next_child) ;
494
+
495
+ let to_iterate = seen. iter ( ) . map ( |( & id, _) | id) . rev ( ) . collect ( ) ;
496
+
497
+ AssertNoDanglingItemIter {
498
+ ctx : self ,
499
+ seen : seen,
500
+ to_iterate : to_iterate,
501
+ }
502
+ }
503
+
458
504
// This deserves a comment. Builtin types don't get a valid declaration, so
459
505
// we can't add it to the cursor->type map.
460
506
//
@@ -1086,3 +1132,71 @@ impl<'ctx, 'gen> Iterator for WhitelistedItemsIter<'ctx, 'gen>
1086
1132
Some ( id)
1087
1133
}
1088
1134
}
1135
+
1136
+ /// An iterator to find any dangling items.
1137
+ ///
1138
+ /// See `BindgenContext::assert_no_dangling_item_traversal` for more information.
1139
+ pub struct AssertNoDanglingItemIter < ' ctx , ' gen >
1140
+ where ' gen : ' ctx ,
1141
+ {
1142
+ ctx : & ' ctx BindgenContext < ' gen > ,
1143
+ seen : BTreeMap < ItemId , ItemId > ,
1144
+ to_iterate : VecDeque < ItemId > ,
1145
+ }
1146
+
1147
+ impl < ' ctx , ' gen > Iterator for AssertNoDanglingItemIter < ' ctx , ' gen >
1148
+ where ' gen : ' ctx ,
1149
+ {
1150
+ type Item = ItemId ;
1151
+
1152
+ fn next ( & mut self ) -> Option < Self :: Item > {
1153
+ let id = match self . to_iterate . pop_front ( ) {
1154
+ None => {
1155
+ // We've traversed everything reachable from the previous root(s), see if
1156
+ // we have any more roots.
1157
+ match self . ctx
1158
+ . items ( )
1159
+ . filter ( |& ( id, _) | !self . seen . contains_key ( id) )
1160
+ . next ( )
1161
+ . map ( |( id, _) | * id) {
1162
+ None => return None ,
1163
+ Some ( id) => {
1164
+ // This is a new root.
1165
+ self . seen . insert ( id, id) ;
1166
+ id
1167
+ }
1168
+ }
1169
+ }
1170
+ Some ( id) => id,
1171
+ } ;
1172
+
1173
+ let mut sub_types = ItemSet :: new ( ) ;
1174
+ id. collect_types ( self . ctx , & mut sub_types, & ( ) ) ;
1175
+
1176
+ if self . ctx . resolve_item_fallible ( id) . is_none ( ) {
1177
+ let mut path = vec ! [ ] ;
1178
+ let mut current = id;
1179
+ loop {
1180
+ let predecessor = * self . seen . get ( & current)
1181
+ . expect ( "We know we found this item id, so it must have a predecessor" ) ;
1182
+ if predecessor == current {
1183
+ break ;
1184
+ }
1185
+ path. push ( predecessor) ;
1186
+ current = predecessor;
1187
+ }
1188
+ path. reverse ( ) ;
1189
+ panic ! ( "Found reference to dangling id = {:?}\n via path = {:?}" ,
1190
+ id,
1191
+ path) ;
1192
+ }
1193
+
1194
+ for sub_id in sub_types {
1195
+ if let Some ( value) = self . seen . insert ( id, sub_id) {
1196
+ self . to_iterate . push_back ( value) ;
1197
+ }
1198
+ }
1199
+
1200
+ Some ( id)
1201
+ }
1202
+ }
0 commit comments