Skip to content

Commit 59a5256

Browse files
author
bors-servo
authored
Auto merge of #312 - impowski:debug_dangling_references, r=fitzgen
Add assert for dangling references without an associated ItemId So I think this is it? Fix issue #209 r? @fitzgen
2 parents 5976766 + 989a516 commit 59a5256

File tree

1 file changed

+122
-8
lines changed

1 file changed

+122
-8
lines changed

libbindgen/src/ir/context.rs

Lines changed: 122 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use clang::{self, Cursor};
66
use parse::ClangItemParser;
77
use std::borrow::Cow;
88
use std::cell::Cell;
9-
use std::collections::{HashMap, hash_map};
9+
use std::collections::{HashMap, VecDeque, hash_map};
1010
use std::collections::btree_map::{self, BTreeMap};
1111
use std::fmt;
1212
use super::int::IntKind;
@@ -399,18 +399,33 @@ impl<'ctx> BindgenContext<'ctx> {
399399
continue;
400400
}
401401

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() {
403406
// 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();
405411
module.children_mut().remove(position);
406412
}
407413

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() {
409418
module.children_mut().push(replacement);
410419
}
411420

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);
414429
}
415430
}
416431

@@ -428,8 +443,7 @@ impl<'ctx> BindgenContext<'ctx> {
428443
let cfg = ExpansionConfig::default("xxx".to_owned());
429444
let sess = parse::ParseSess::new();
430445
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));
433447

434448
ctx.0.bt_push(ExpnInfo {
435449
call_site: self.span,
@@ -445,6 +459,8 @@ impl<'ctx> BindgenContext<'ctx> {
445459
// because we remove it before the end of this function.
446460
self.gen_ctx = Some(unsafe { mem::transmute(&ctx) });
447461

462+
self.assert_no_dangling_references();
463+
448464
if !self.collected_typerefs() {
449465
self.resolve_typerefs();
450466
self.process_replacements();
@@ -455,6 +471,36 @@ impl<'ctx> BindgenContext<'ctx> {
455471
ret
456472
}
457473

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+
458504
// This deserves a comment. Builtin types don't get a valid declaration, so
459505
// we can't add it to the cursor->type map.
460506
//
@@ -1086,3 +1132,71 @@ impl<'ctx, 'gen> Iterator for WhitelistedItemsIter<'ctx, 'gen>
10861132
Some(id)
10871133
}
10881134
}
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 = {:?}\nvia 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

Comments
 (0)