Skip to content

Commit 696e2bb

Browse files
author
bors-servo
authored
Auto merge of #510 - fitzgen:cleanup-ir-graph-traversal, r=emilio
Cleanup IR graph traversal This is a bunch of pre-cursor work to properly determining which template type parameters are actually used or not. First three commits are mechanical / code motion / renaming. Fourth is the meat of this PR, making a bunch of things more generic and introducing the concept of an `EdgeKind` in the IR graph. Last commit is just `cargo fmt`. r? @emilio
2 parents c8f1855 + 6d2f907 commit 696e2bb

File tree

9 files changed

+461
-240
lines changed

9 files changed

+461
-240
lines changed

src/codegen/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
1212
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
1313
use ir::function::{Function, FunctionSig};
1414
use ir::int::IntKind;
15-
use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath};
15+
use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath,
16+
ItemSet};
1617
use ir::item_kind::ItemKind;
1718
use ir::layout::Layout;
1819
use ir::module::Module;
1920
use ir::objc::ObjCInterface;
2021
use ir::ty::{Type, TypeKind};
21-
use ir::type_collector::ItemSet;
2222
use ir::var::Var;
2323

2424
use std::borrow::Cow;
@@ -2190,7 +2190,7 @@ impl ToRustTy for Type {
21902190
.map(|arg| arg.to_rust_ty(ctx))
21912191
.collect::<Vec<_>>();
21922192

2193-
path.segments.last_mut().unwrap().parameters = if
2193+
path.segments.last_mut().unwrap().parameters = if
21942194
template_args.is_empty() {
21952195
None
21962196
} else {

src/ir/comp.rs

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use super::context::{BindgenContext, ItemId};
55
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
66
use super::item::Item;
77
use super::layout::Layout;
8+
use super::traversal::{EdgeKind, Trace, Tracer};
89
use super::ty::{TemplateDeclaration, Type};
9-
use super::type_collector::{ItemSet, TypeCollector};
1010
use clang;
1111
use parse::{ClangItemParser, ParseError};
1212
use std::cell::Cell;
@@ -1075,44 +1075,55 @@ impl<'a> CanDeriveCopy<'a> for CompInfo {
10751075
}
10761076
}
10771077

1078-
impl TypeCollector for CompInfo {
1078+
impl Trace for CompInfo {
10791079
type Extra = Item;
10801080

1081-
fn collect_types(&self,
1082-
context: &BindgenContext,
1083-
types: &mut ItemSet,
1084-
item: &Item) {
1081+
fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
1082+
where T: Tracer,
1083+
{
1084+
// TODO: We should properly distinguish template instantiations from
1085+
// template declarations at the type level. Why are some template
1086+
// instantiations represented here instead of as
1087+
// TypeKind::TemplateInstantiation?
10851088
if let Some(template) = self.specialized_template() {
1086-
types.insert(template);
1087-
}
1088-
1089-
let applicable_template_args = item.applicable_template_args(context);
1090-
for arg in applicable_template_args {
1091-
types.insert(arg);
1089+
// This is an instantiation of a template declaration with concrete
1090+
// template type arguments.
1091+
tracer.visit(template);
1092+
let args = item.applicable_template_args(context);
1093+
for a in args {
1094+
tracer.visit(a);
1095+
}
1096+
} else {
1097+
let params = item.applicable_template_args(context);
1098+
// This is a template declaration with abstract template type
1099+
// parameters.
1100+
for p in params {
1101+
tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition);
1102+
}
10921103
}
10931104

10941105
for base in self.base_members() {
1095-
types.insert(base.ty);
1106+
tracer.visit(base.ty);
10961107
}
10971108

10981109
for field in self.fields() {
1099-
types.insert(field.ty());
1110+
tracer.visit(field.ty());
11001111
}
11011112

11021113
for &ty in self.inner_types() {
1103-
types.insert(ty);
1114+
tracer.visit(ty);
11041115
}
11051116

11061117
for &var in self.inner_vars() {
1107-
types.insert(var);
1118+
tracer.visit(var);
11081119
}
11091120

11101121
for method in self.methods() {
1111-
types.insert(method.signature);
1122+
tracer.visit(method.signature);
11121123
}
11131124

11141125
for &ctor in self.constructors() {
1115-
types.insert(ctor);
1126+
tracer.visit(ctor);
11161127
}
11171128
}
11181129
}

src/ir/context.rs

Lines changed: 27 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
33
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
44
use super::int::IntKind;
5-
use super::item::{Item, ItemCanonicalPath};
5+
use super::item::{Item, ItemCanonicalPath, ItemSet};
66
use super::item_kind::ItemKind;
77
use super::module::{Module, ModuleKind};
8+
use super::traversal::{self, Edge, ItemTraversal};
89
use super::ty::{FloatKind, TemplateDeclaration, Type, TypeKind};
9-
use super::type_collector::{ItemSet, TypeCollector};
1010
use BindgenOptions;
1111
use cexpr;
1212
use chooser::TypeChooser;
@@ -15,7 +15,7 @@ use clang_sys;
1515
use parse::ClangItemParser;
1616
use std::borrow::Cow;
1717
use std::cell::Cell;
18-
use std::collections::{HashMap, VecDeque, hash_map};
18+
use std::collections::{HashMap, hash_map};
1919
use std::collections::btree_map::{self, BTreeMap};
2020
use std::fmt;
2121
use std::iter::IntoIterator;
@@ -151,6 +151,13 @@ pub struct BindgenContext<'ctx> {
151151
generated_bindegen_complex: Cell<bool>,
152152
}
153153

154+
/// A traversal of whitelisted items.
155+
pub type WhitelistedItems<'ctx, 'gen> = ItemTraversal<'ctx,
156+
'gen,
157+
ItemSet,
158+
Vec<ItemId>,
159+
fn(Edge) -> bool>;
160+
154161
impl<'ctx> BindgenContext<'ctx> {
155162
/// Construct the context for the given `options`.
156163
pub fn new(options: BindgenOptions) -> Self {
@@ -538,23 +545,14 @@ impl<'ctx> BindgenContext<'ctx> {
538545

539546
fn assert_no_dangling_item_traversal<'me>
540547
(&'me self)
541-
-> AssertNoDanglingItemIter<'me, 'ctx> {
548+
-> traversal::AssertNoDanglingItemsTraversal<'me, 'ctx> {
542549
assert!(self.in_codegen_phase());
543550
assert!(self.current_module == self.root_module);
544551

545-
let mut roots = self.items().map(|(&id, _)| id);
546-
547-
let mut seen = BTreeMap::<ItemId, ItemId>::new();
548-
let next_child = roots.next().map(|id| id).unwrap();
549-
seen.insert(next_child, next_child);
550-
551-
let to_iterate = seen.iter().map(|(&id, _)| id).rev().collect();
552-
553-
AssertNoDanglingItemIter {
554-
ctx: self,
555-
seen: seen,
556-
to_iterate: to_iterate,
557-
}
552+
let roots = self.items().map(|(&id, _)| id);
553+
traversal::AssertNoDanglingItemsTraversal::new(self,
554+
roots,
555+
traversal::all_edges)
558556
}
559557

560558
// This deserves a comment. Builtin types don't get a valid declaration, so
@@ -1202,8 +1200,7 @@ impl<'ctx> BindgenContext<'ctx> {
12021200
///
12031201
/// If no items are explicitly whitelisted, then all items are considered
12041202
/// whitelisted.
1205-
pub fn whitelisted_items<'me>(&'me self)
1206-
-> WhitelistedItemsIter<'me, 'ctx> {
1203+
pub fn whitelisted_items<'me>(&'me self) -> WhitelistedItems<'me, 'ctx> {
12071204
assert!(self.in_codegen_phase());
12081205
assert!(self.current_module == self.root_module);
12091206

@@ -1268,18 +1265,19 @@ impl<'ctx> BindgenContext<'ctx> {
12681265
})
12691266
.map(|(&id, _)| id);
12701267

1271-
let seen: ItemSet = roots.collect();
1272-
1273-
// The .rev() preserves the expected ordering traversal, resulting in
1274-
// more stable-ish bindgen-generated names for anonymous types (like
1268+
// The reversal preserves the expected ordering of traversal, resulting
1269+
// in more stable-ish bindgen-generated names for anonymous types (like
12751270
// unions).
1276-
let to_iterate = seen.iter().cloned().rev().collect();
1271+
let mut roots: Vec<_> = roots.collect();
1272+
roots.reverse();
12771273

1278-
WhitelistedItemsIter {
1279-
ctx: self,
1280-
seen: seen,
1281-
to_iterate: to_iterate,
1282-
}
1274+
let predicate = if self.options().whitelist_recursively {
1275+
traversal::all_edges
1276+
} else {
1277+
traversal::no_edges
1278+
};
1279+
1280+
WhitelistedItems::new(self, roots, predicate)
12831281
}
12841282

12851283
/// Convenient method for getting the prefix to use for most traits in
@@ -1364,124 +1362,3 @@ impl TemplateDeclaration for PartialType {
13641362
}
13651363
}
13661364
}
1367-
1368-
/// An iterator over whitelisted items.
1369-
///
1370-
/// See `BindgenContext::whitelisted_items` for more information.
1371-
pub struct WhitelistedItemsIter<'ctx, 'gen>
1372-
where 'gen: 'ctx,
1373-
{
1374-
ctx: &'ctx BindgenContext<'gen>,
1375-
1376-
/// The set of whitelisted items we have seen. If you think of traversing
1377-
/// whitelisted items like GC tracing, this is the mark bits, and contains
1378-
/// both black and gray items.
1379-
seen: ItemSet,
1380-
1381-
/// The set of whitelisted items that we have seen but have yet to iterate
1382-
/// over and collect transitive references from. To return to the GC analogy,
1383-
/// this is the mark stack, containing the set of gray items which we have
1384-
/// not finished tracing yet.
1385-
to_iterate: Vec<ItemId>,
1386-
}
1387-
1388-
impl<'ctx, 'gen> Iterator for WhitelistedItemsIter<'ctx, 'gen>
1389-
where 'gen: 'ctx,
1390-
{
1391-
type Item = ItemId;
1392-
1393-
fn next(&mut self) -> Option<Self::Item> {
1394-
let id = match self.to_iterate.pop() {
1395-
None => return None,
1396-
Some(id) => id,
1397-
};
1398-
1399-
debug_assert!(self.seen.contains(&id));
1400-
debug_assert!(self.ctx.items.contains_key(&id));
1401-
1402-
if self.ctx.options().whitelist_recursively {
1403-
let mut sub_types = ItemSet::new();
1404-
id.collect_types(self.ctx, &mut sub_types, &());
1405-
1406-
for id in sub_types {
1407-
if self.seen.insert(id) {
1408-
self.to_iterate.push(id);
1409-
}
1410-
}
1411-
}
1412-
1413-
Some(id)
1414-
}
1415-
}
1416-
1417-
/// An iterator to find any dangling items.
1418-
///
1419-
/// See `BindgenContext::assert_no_dangling_item_traversal` for more
1420-
/// information.
1421-
pub struct AssertNoDanglingItemIter<'ctx, 'gen>
1422-
where 'gen: 'ctx,
1423-
{
1424-
ctx: &'ctx BindgenContext<'gen>,
1425-
seen: BTreeMap<ItemId, ItemId>,
1426-
to_iterate: VecDeque<ItemId>,
1427-
}
1428-
1429-
impl<'ctx, 'gen> Iterator for AssertNoDanglingItemIter<'ctx, 'gen>
1430-
where 'gen: 'ctx,
1431-
{
1432-
type Item = ItemId;
1433-
1434-
fn next(&mut self) -> Option<Self::Item> {
1435-
let id = match self.to_iterate.pop_front() {
1436-
None => {
1437-
// We've traversed everything reachable from the previous
1438-
// root(s), see if we have any more roots.
1439-
match self.ctx
1440-
.items()
1441-
.filter(|&(id, _)| !self.seen.contains_key(id))
1442-
.next()
1443-
.map(|(id, _)| *id) {
1444-
None => return None,
1445-
Some(id) => {
1446-
// This is a new root.
1447-
self.seen.insert(id, id);
1448-
id
1449-
}
1450-
}
1451-
}
1452-
Some(id) => id,
1453-
};
1454-
1455-
let mut sub_types = ItemSet::new();
1456-
id.collect_types(self.ctx, &mut sub_types, &());
1457-
1458-
if self.ctx.resolve_item_fallible(id).is_none() {
1459-
let mut path = vec![];
1460-
let mut current = id;
1461-
loop {
1462-
let predecessor = *self.seen
1463-
.get(&current)
1464-
.expect("We know we found this item id, so it must have a \
1465-
predecessor");
1466-
if predecessor == current {
1467-
break;
1468-
}
1469-
path.push(predecessor);
1470-
current = predecessor;
1471-
}
1472-
path.reverse();
1473-
panic!("Found reference to dangling id = {:?}\nvia path = {:?}",
1474-
id,
1475-
path);
1476-
}
1477-
1478-
for sub_id in sub_types {
1479-
if self.seen.insert(sub_id, id).is_none() {
1480-
// We've never visited this sub item before.
1481-
self.to_iterate.push_back(sub_id);
1482-
}
1483-
}
1484-
1485-
Some(id)
1486-
}
1487-
}

src/ir/function.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
33
use super::context::{BindgenContext, ItemId};
44
use super::item::Item;
5+
use super::traversal::{Trace, Tracer};
56
use super::ty::TypeKind;
6-
use super::type_collector::{ItemSet, TypeCollector};
77
use clang;
88
use clang_sys::CXCallingConv;
99
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
@@ -316,17 +316,16 @@ impl ClangSubItemParser for Function {
316316
}
317317
}
318318

319-
impl TypeCollector for FunctionSig {
320-
type Extra = Item;
319+
impl Trace for FunctionSig {
320+
type Extra = ();
321321

322-
fn collect_types(&self,
323-
_context: &BindgenContext,
324-
types: &mut ItemSet,
325-
_item: &Item) {
326-
types.insert(self.return_type());
322+
fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
323+
where T: Tracer,
324+
{
325+
tracer.visit(self.return_type());
327326

328327
for &(_, ty) in self.argument_types() {
329-
types.insert(ty);
328+
tracer.visit(ty);
330329
}
331330
}
332331
}

0 commit comments

Comments
 (0)