Skip to content

Commit cda5e09

Browse files
committed
Only whitelist items which we intend to generate code for
This makes only generating certain kinds of items more robust, since we don't need to keep checking whether codegen is enabled for different kinds of items all over the place, and can do it the once. It should also reduce the number of items we have to consider in our various analyses for which we don't ultimately care about the answer. Fixes rust-lang#826
1 parent d98f3bc commit cda5e09

11 files changed

+186
-39
lines changed

src/codegen/mod.rs

+31-10
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ impl CodeGenerator for Item {
294294
result: &mut CodegenResult<'a>,
295295
whitelisted_items: &ItemSet,
296296
_extra: &()) {
297+
if !self.is_enabled_for_codegen(ctx) {
298+
return;
299+
}
300+
297301
if self.is_hidden(ctx) || result.seen(self.id()) {
298302
debug!("<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \
299303
self = {:?}",
@@ -316,19 +320,13 @@ impl CodeGenerator for Item {
316320
module.codegen(ctx, result, whitelisted_items, self);
317321
}
318322
ItemKind::Function(ref fun) => {
319-
if ctx.options().codegen_config.functions {
320-
fun.codegen(ctx, result, whitelisted_items, self);
321-
}
323+
fun.codegen(ctx, result, whitelisted_items, self);
322324
}
323325
ItemKind::Var(ref var) => {
324-
if ctx.options().codegen_config.vars {
325-
var.codegen(ctx, result, whitelisted_items, self);
326-
}
326+
var.codegen(ctx, result, whitelisted_items, self);
327327
}
328328
ItemKind::Type(ref ty) => {
329-
if ctx.options().codegen_config.types {
330-
ty.codegen(ctx, result, whitelisted_items, self);
331-
}
329+
ty.codegen(ctx, result, whitelisted_items, self);
332330
}
333331
}
334332
}
@@ -419,6 +417,7 @@ impl CodeGenerator for Var {
419417
item: &Item) {
420418
use ir::var::VarType;
421419
debug!("<Var as CodeGenerator>::codegen: item = {:?}", item);
420+
debug_assert!(item.is_enabled_for_codegen(ctx));
422421

423422
let canonical_name = item.canonical_name(ctx);
424423

@@ -522,6 +521,7 @@ impl CodeGenerator for Type {
522521
whitelisted_items: &ItemSet,
523522
item: &Item) {
524523
debug!("<Type as CodeGenerator>::codegen: item = {:?}", item);
524+
debug_assert!(item.is_enabled_for_codegen(ctx));
525525

526526
match *self.kind() {
527527
TypeKind::Void |
@@ -705,6 +705,8 @@ impl<'a> CodeGenerator for Vtable<'a> {
705705
_whitelisted_items: &ItemSet,
706706
item: &Item) {
707707
assert_eq!(item.id(), self.item_id);
708+
debug_assert!(item.is_enabled_for_codegen(ctx));
709+
708710
// For now, generate an empty struct, later we should generate function
709711
// pointers and whatnot.
710712
let attributes = vec![attributes::repr("C")];
@@ -745,6 +747,8 @@ impl CodeGenerator for TemplateInstantiation {
745747
result: &mut CodegenResult<'a>,
746748
_whitelisted_items: &ItemSet,
747749
item: &Item) {
750+
debug_assert!(item.is_enabled_for_codegen(ctx));
751+
748752
// Although uses of instantiations don't need code generation, and are
749753
// just converted to rust types in fields, vars, etc, we take this
750754
// opportunity to generate tests for their layout here. If the
@@ -1376,6 +1380,7 @@ impl CodeGenerator for CompInfo {
13761380
whitelisted_items: &ItemSet,
13771381
item: &Item) {
13781382
debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item);
1383+
debug_assert!(item.is_enabled_for_codegen(ctx));
13791384

13801385
// Don't output classes with template parameters that aren't types, and
13811386
// also don't output template specializations, neither total or partial.
@@ -1897,6 +1902,18 @@ impl MethodCodegen for Method {
18971902
result: &mut CodegenResult<'a>,
18981903
whitelisted_items: &ItemSet,
18991904
_parent: &CompInfo) {
1905+
assert!({
1906+
let cc = &ctx.options().codegen_config;
1907+
match self.kind() {
1908+
MethodKind::Constructor => cc.constructors,
1909+
MethodKind::Destructor => cc.destructors,
1910+
MethodKind::VirtualDestructor => cc.destructors,
1911+
MethodKind::Static |
1912+
MethodKind::Normal |
1913+
MethodKind::Virtual => cc.methods,
1914+
}
1915+
});
1916+
19001917
if self.is_virtual() {
19011918
return; // FIXME
19021919
}
@@ -2287,6 +2304,7 @@ impl CodeGenerator for Enum {
22872304
_whitelisted_items: &ItemSet,
22882305
item: &Item) {
22892306
debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item);
2307+
debug_assert!(item.is_enabled_for_codegen(ctx));
22902308

22912309
let name = item.canonical_name(ctx);
22922310
let enum_ty = item.expect_type();
@@ -3026,6 +3044,7 @@ impl CodeGenerator for Function {
30263044
_whitelisted_items: &ItemSet,
30273045
item: &Item) {
30283046
debug!("<Function as CodeGenerator>::codegen: item = {:?}", item);
3047+
debug_assert!(item.is_enabled_for_codegen(ctx));
30293048

30303049
// Similar to static member variables in a class template, we can't
30313050
// generate bindings to template functions, because the set of
@@ -3202,7 +3221,9 @@ impl CodeGenerator for ObjCInterface {
32023221
ctx: &BindgenContext,
32033222
result: &mut CodegenResult<'a>,
32043223
_whitelisted_items: &ItemSet,
3205-
_: &Item) {
3224+
item: &Item) {
3225+
debug_assert!(item.is_enabled_for_codegen(ctx));
3226+
32063227
let mut impl_items = vec![];
32073228
let mut trait_items = vec![];
32083229

src/ir/comp.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1587,7 +1587,11 @@ impl Trace for CompInfo {
15871587
}
15881588

15891589
for method in self.methods() {
1590-
tracer.visit_kind(method.signature, EdgeKind::Method);
1590+
if method.is_destructor() {
1591+
tracer.visit_kind(method.signature, EdgeKind::Destructor);
1592+
} else {
1593+
tracer.visit_kind(method.signature, EdgeKind::Method);
1594+
}
15911595
}
15921596

15931597
for &ctor in self.constructors() {

src/ir/context.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ pub struct WhitelistedItems<'ctx, 'gen>
180180
'gen,
181181
ItemSet,
182182
Vec<ItemId>,
183-
fn(Edge) -> bool>,
183+
for<'a> fn(&'a BindgenContext, Edge) -> bool>,
184184
}
185185

186186
impl<'ctx, 'gen> Iterator for WhitelistedItems<'ctx, 'gen>
@@ -209,7 +209,7 @@ impl<'ctx, 'gen> WhitelistedItems<'ctx, 'gen>
209209
where R: IntoIterator<Item = ItemId>,
210210
{
211211
let predicate = if ctx.options().whitelist_recursively {
212-
traversal::all_edges
212+
traversal::codegen_edges
213213
} else {
214214
traversal::no_edges
215215
};
@@ -1565,6 +1565,8 @@ impl<'ctx> BindgenContext<'ctx> {
15651565
assert!(self.current_module == self.root_module);
15661566

15671567
let roots = self.items()
1568+
// Only consider items that are enabled for codegen.
1569+
.filter(|&(_, item)| item.is_enabled_for_codegen(self))
15681570
.filter(|&(_, item)| {
15691571
// If nothing is explicitly whitelisted, then everything is fair
15701572
// game.

src/ir/function.rs

+47-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,47 @@
11
//! Intermediate representation for C/C++ functions and methods.
22
3+
use super::comp::MethodKind;
34
use super::context::{BindgenContext, ItemId};
45
use super::dot::DotAttributes;
56
use super::item::Item;
67
use super::traversal::{EdgeKind, Trace, Tracer};
78
use super::ty::TypeKind;
89
use clang;
9-
use clang_sys::CXCallingConv;
10+
use clang_sys::{self, CXCallingConv};
1011
use ir::derive::CanDeriveDebug;
1112
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
1213
use std::io;
1314
use syntax::abi;
1415

16+
/// What kind of a function are we looking at?
17+
#[derive(Debug, Copy, Clone, PartialEq)]
18+
pub enum FunctionKind {
19+
/// A plain, free function.
20+
Function,
21+
/// A method of some kind.
22+
Method(MethodKind),
23+
}
24+
25+
impl FunctionKind {
26+
fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> {
27+
Some(match cursor.kind() {
28+
clang_sys::CXCursor_FunctionDecl => FunctionKind::Function,
29+
clang_sys::CXCursor_Constructor => FunctionKind::Method(MethodKind::Constructor),
30+
clang_sys::CXCursor_Destructor => FunctionKind::Method(MethodKind::Destructor),
31+
clang_sys::CXCursor_CXXMethod => {
32+
if cursor.method_is_virtual() {
33+
FunctionKind::Method(MethodKind::Virtual)
34+
} else if cursor.method_is_static() {
35+
FunctionKind::Method(MethodKind::Static)
36+
} else {
37+
FunctionKind::Method(MethodKind::Normal)
38+
}
39+
}
40+
_ => return None,
41+
})
42+
}
43+
}
44+
1545
/// A function declaration, with a signature, arguments, and argument names.
1646
///
1747
/// The argument names vector must be the same length as the ones in the
@@ -29,20 +59,25 @@ pub struct Function {
2959

3060
/// The doc comment on the function, if any.
3161
comment: Option<String>,
62+
63+
/// The kind of function this is.
64+
kind: FunctionKind,
3265
}
3366

3467
impl Function {
3568
/// Construct a new function.
3669
pub fn new(name: String,
3770
mangled_name: Option<String>,
3871
sig: ItemId,
39-
comment: Option<String>)
72+
comment: Option<String>,
73+
kind: FunctionKind)
4074
-> Self {
4175
Function {
4276
name: name,
4377
mangled_name: mangled_name,
4478
signature: sig,
4579
comment: comment,
80+
kind: kind,
4681
}
4782
}
4883

@@ -60,6 +95,11 @@ impl Function {
6095
pub fn signature(&self) -> ItemId {
6196
self.signature
6297
}
98+
99+
/// Get this function's kind.
100+
pub fn kind(&self) -> FunctionKind {
101+
self.kind
102+
}
63103
}
64104

65105
impl DotAttributes for Function {
@@ -357,12 +397,10 @@ impl ClangSubItemParser for Function {
357397
context: &mut BindgenContext)
358398
-> Result<ParseResult<Self>, ParseError> {
359399
use clang_sys::*;
360-
match cursor.kind() {
361-
CXCursor_FunctionDecl |
362-
CXCursor_Constructor |
363-
CXCursor_Destructor |
364-
CXCursor_CXXMethod => {}
365-
_ => return Err(ParseError::Continue),
400+
401+
let kind = match FunctionKind::from_cursor(&cursor) {
402+
None => return Err(ParseError::Continue),
403+
Some(k) => k,
366404
};
367405

368406
debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
@@ -415,7 +453,7 @@ impl ClangSubItemParser for Function {
415453

416454
let comment = cursor.raw_comment();
417455

418-
let function = Self::new(name, mangled_name, sig, comment);
456+
let function = Self::new(name, mangled_name, sig, comment, kind);
419457
Ok(ParseResult::New(function, Some(cursor)))
420458
}
421459
}

src/ir/item.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
use super::super::codegen::CONSTIFIED_ENUM_MODULE_REPR_NAME;
44
use super::annotations::Annotations;
55
use super::comment;
6+
use super::comp::MethodKind;
67
use super::context::{BindgenContext, ItemId, PartialType};
78
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
89
use super::dot::DotAttributes;
9-
use super::function::Function;
10+
use super::function::{Function, FunctionKind};
1011
use super::item_kind::ItemKind;
1112
use super::layout::Opaque;
1213
use super::module::Module;
@@ -895,6 +896,27 @@ impl Item {
895896
_ => false,
896897
}
897898
}
899+
900+
/// Is this item of a kind that is enabled for code generation?
901+
pub fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool {
902+
let cc = &ctx.options().codegen_config;
903+
match *self.kind() {
904+
ItemKind::Module(..) => true,
905+
ItemKind::Var(_) => cc.vars,
906+
ItemKind::Type(_) => cc.types,
907+
ItemKind::Function(ref f) => {
908+
match f.kind() {
909+
FunctionKind::Function => cc.functions,
910+
FunctionKind::Method(MethodKind::Constructor) => cc.constructors,
911+
FunctionKind::Method(MethodKind::Destructor) |
912+
FunctionKind::Method(MethodKind::VirtualDestructor) => cc.destructors,
913+
FunctionKind::Method(MethodKind::Static) |
914+
FunctionKind::Method(MethodKind::Normal) |
915+
FunctionKind::Method(MethodKind::Virtual) => cc.methods,
916+
}
917+
}
918+
}
919+
}
898920
}
899921

900922
impl IsOpaque for ItemId {

src/ir/named.rs

+1
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> {
211211
EdgeKind::BaseMember |
212212
EdgeKind::Field |
213213
EdgeKind::Constructor |
214+
EdgeKind::Destructor |
214215
EdgeKind::VarType |
215216
EdgeKind::FunctionReturn |
216217
EdgeKind::FunctionParameter |

0 commit comments

Comments
 (0)