diff options
-rw-r--r-- | src/codegen/mod.rs | 41 | ||||
-rw-r--r-- | src/ir/cant_derive_debug.rs | 1 | ||||
-rw-r--r-- | src/ir/comp.rs | 6 | ||||
-rw-r--r-- | src/ir/context.rs | 6 | ||||
-rw-r--r-- | src/ir/function.rs | 56 | ||||
-rw-r--r-- | src/ir/item.rs | 24 | ||||
-rw-r--r-- | src/ir/named.rs | 1 | ||||
-rw-r--r-- | src/ir/traversal.rs | 57 | ||||
-rw-r--r-- | tests/expectations/tests/gen-constructors-neg.rs | 4 | ||||
-rw-r--r-- | tests/expectations/tests/gen-destructors-neg.rs | 4 | ||||
-rw-r--r-- | tests/expectations/tests/issue-826-generating-methods-when-asked-not-to.rs | 21 | ||||
-rw-r--r-- | tests/headers/issue-826-generating-methods-when-asked-not-to.hpp | 5 |
12 files changed, 187 insertions, 39 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 6f2bf96b..cf4fad50 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -294,6 +294,10 @@ impl CodeGenerator for Item { result: &mut CodegenResult<'a>, whitelisted_items: &ItemSet, _extra: &()) { + if !self.is_enabled_for_codegen(ctx) { + return; + } + if self.is_hidden(ctx) || result.seen(self.id()) { debug!("<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \ self = {:?}", @@ -316,19 +320,13 @@ impl CodeGenerator for Item { module.codegen(ctx, result, whitelisted_items, self); } ItemKind::Function(ref fun) => { - if ctx.options().codegen_config.functions { - fun.codegen(ctx, result, whitelisted_items, self); - } + fun.codegen(ctx, result, whitelisted_items, self); } ItemKind::Var(ref var) => { - if ctx.options().codegen_config.vars { - var.codegen(ctx, result, whitelisted_items, self); - } + var.codegen(ctx, result, whitelisted_items, self); } ItemKind::Type(ref ty) => { - if ctx.options().codegen_config.types { - ty.codegen(ctx, result, whitelisted_items, self); - } + ty.codegen(ctx, result, whitelisted_items, self); } } } @@ -419,6 +417,7 @@ impl CodeGenerator for Var { item: &Item) { use ir::var::VarType; debug!("<Var as CodeGenerator>::codegen: item = {:?}", item); + debug_assert!(item.is_enabled_for_codegen(ctx)); let canonical_name = item.canonical_name(ctx); @@ -522,6 +521,7 @@ impl CodeGenerator for Type { whitelisted_items: &ItemSet, item: &Item) { debug!("<Type as CodeGenerator>::codegen: item = {:?}", item); + debug_assert!(item.is_enabled_for_codegen(ctx)); match *self.kind() { TypeKind::Void | @@ -705,6 +705,8 @@ impl<'a> CodeGenerator for Vtable<'a> { _whitelisted_items: &ItemSet, item: &Item) { assert_eq!(item.id(), self.item_id); + debug_assert!(item.is_enabled_for_codegen(ctx)); + // For now, generate an empty struct, later we should generate function // pointers and whatnot. let attributes = vec![attributes::repr("C")]; @@ -745,6 +747,8 @@ impl CodeGenerator for TemplateInstantiation { result: &mut CodegenResult<'a>, _whitelisted_items: &ItemSet, item: &Item) { + debug_assert!(item.is_enabled_for_codegen(ctx)); + // Although uses of instantiations don't need code generation, and are // just converted to rust types in fields, vars, etc, we take this // opportunity to generate tests for their layout here. If the @@ -1376,6 +1380,7 @@ impl CodeGenerator for CompInfo { whitelisted_items: &ItemSet, item: &Item) { debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item); + debug_assert!(item.is_enabled_for_codegen(ctx)); // Don't output classes with template parameters that aren't types, and // also don't output template specializations, neither total or partial. @@ -1897,6 +1902,18 @@ impl MethodCodegen for Method { result: &mut CodegenResult<'a>, whitelisted_items: &ItemSet, _parent: &CompInfo) { + assert!({ + let cc = &ctx.options().codegen_config; + match self.kind() { + MethodKind::Constructor => cc.constructors, + MethodKind::Destructor => cc.destructors, + MethodKind::VirtualDestructor => cc.destructors, + MethodKind::Static | + MethodKind::Normal | + MethodKind::Virtual => cc.methods, + } + }); + if self.is_virtual() { return; // FIXME } @@ -2287,6 +2304,7 @@ impl CodeGenerator for Enum { _whitelisted_items: &ItemSet, item: &Item) { debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item); + debug_assert!(item.is_enabled_for_codegen(ctx)); let name = item.canonical_name(ctx); let enum_ty = item.expect_type(); @@ -3026,6 +3044,7 @@ impl CodeGenerator for Function { _whitelisted_items: &ItemSet, item: &Item) { debug!("<Function as CodeGenerator>::codegen: item = {:?}", item); + debug_assert!(item.is_enabled_for_codegen(ctx)); // Similar to static member variables in a class template, we can't // generate bindings to template functions, because the set of @@ -3202,7 +3221,9 @@ impl CodeGenerator for ObjCInterface { ctx: &BindgenContext, result: &mut CodegenResult<'a>, _whitelisted_items: &ItemSet, - _: &Item) { + item: &Item) { + debug_assert!(item.is_enabled_for_codegen(ctx)); + let mut impl_items = vec![]; let mut trait_items = vec![]; diff --git a/src/ir/cant_derive_debug.rs b/src/ir/cant_derive_debug.rs index 465f068c..f6a7fab7 100644 --- a/src/ir/cant_derive_debug.rs +++ b/src/ir/cant_derive_debug.rs @@ -67,6 +67,7 @@ impl<'ctx, 'gen> CantDeriveDebugAnalysis<'ctx, 'gen> { EdgeKind::TemplateParameterDefinition => true, EdgeKind::Constructor | + EdgeKind::Destructor | EdgeKind::FunctionReturn | EdgeKind::FunctionParameter | EdgeKind::InnerType | diff --git a/src/ir/comp.rs b/src/ir/comp.rs index c7c2d82a..0960ee11 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -1534,7 +1534,11 @@ impl Trace for CompInfo { } for method in self.methods() { - tracer.visit_kind(method.signature, EdgeKind::Method); + if method.is_destructor() { + tracer.visit_kind(method.signature, EdgeKind::Destructor); + } else { + tracer.visit_kind(method.signature, EdgeKind::Method); + } } for &ctor in self.constructors() { diff --git a/src/ir/context.rs b/src/ir/context.rs index b9b5af3e..a0c76186 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -186,7 +186,7 @@ pub struct WhitelistedItems<'ctx, 'gen> 'gen, ItemSet, Vec<ItemId>, - fn(Edge) -> bool>, + for<'a> fn(&'a BindgenContext, Edge) -> bool>, } impl<'ctx, 'gen> Iterator for WhitelistedItems<'ctx, 'gen> @@ -215,7 +215,7 @@ impl<'ctx, 'gen> WhitelistedItems<'ctx, 'gen> where R: IntoIterator<Item = ItemId>, { let predicate = if ctx.options().whitelist_recursively { - traversal::all_edges + traversal::codegen_edges } else { traversal::no_edges }; @@ -1573,6 +1573,8 @@ impl<'ctx> BindgenContext<'ctx> { assert!(self.current_module == self.root_module); let roots = self.items() + // Only consider items that are enabled for codegen. + .filter(|&(_, item)| item.is_enabled_for_codegen(self)) .filter(|&(_, item)| { // If nothing is explicitly whitelisted, then everything is fair // game. diff --git a/src/ir/function.rs b/src/ir/function.rs index 71bb0dd4..663bb8e3 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -1,17 +1,47 @@ //! Intermediate representation for C/C++ functions and methods. +use super::comp::MethodKind; use super::context::{BindgenContext, ItemId}; use super::dot::DotAttributes; use super::item::Item; use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::TypeKind; use clang; -use clang_sys::CXCallingConv; +use clang_sys::{self, CXCallingConv}; use ir::derive::CanTriviallyDeriveDebug; use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; use std::io; use syntax::abi; +/// What kind of a function are we looking at? +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum FunctionKind { + /// A plain, free function. + Function, + /// A method of some kind. + Method(MethodKind), +} + +impl FunctionKind { + fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> { + Some(match cursor.kind() { + clang_sys::CXCursor_FunctionDecl => FunctionKind::Function, + clang_sys::CXCursor_Constructor => FunctionKind::Method(MethodKind::Constructor), + clang_sys::CXCursor_Destructor => FunctionKind::Method(MethodKind::Destructor), + clang_sys::CXCursor_CXXMethod => { + if cursor.method_is_virtual() { + FunctionKind::Method(MethodKind::Virtual) + } else if cursor.method_is_static() { + FunctionKind::Method(MethodKind::Static) + } else { + FunctionKind::Method(MethodKind::Normal) + } + } + _ => return None, + }) + } +} + /// A function declaration, with a signature, arguments, and argument names. /// /// The argument names vector must be the same length as the ones in the @@ -29,6 +59,9 @@ pub struct Function { /// The doc comment on the function, if any. comment: Option<String>, + + /// The kind of function this is. + kind: FunctionKind, } impl Function { @@ -36,13 +69,15 @@ impl Function { pub fn new(name: String, mangled_name: Option<String>, sig: ItemId, - comment: Option<String>) + comment: Option<String>, + kind: FunctionKind) -> Self { Function { name: name, mangled_name: mangled_name, signature: sig, comment: comment, + kind: kind, } } @@ -60,6 +95,11 @@ impl Function { pub fn signature(&self) -> ItemId { self.signature } + + /// Get this function's kind. + pub fn kind(&self) -> FunctionKind { + self.kind + } } impl DotAttributes for Function { @@ -357,12 +397,10 @@ impl ClangSubItemParser for Function { context: &mut BindgenContext) -> Result<ParseResult<Self>, ParseError> { use clang_sys::*; - match cursor.kind() { - CXCursor_FunctionDecl | - CXCursor_Constructor | - CXCursor_Destructor | - CXCursor_CXXMethod => {} - _ => return Err(ParseError::Continue), + + let kind = match FunctionKind::from_cursor(&cursor) { + None => return Err(ParseError::Continue), + Some(k) => k, }; debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type()); @@ -415,7 +453,7 @@ impl ClangSubItemParser for Function { let comment = cursor.raw_comment(); - let function = Self::new(name, mangled_name, sig, comment); + let function = Self::new(name, mangled_name, sig, comment, kind); Ok(ParseResult::New(function, Some(cursor))) } } diff --git a/src/ir/item.rs b/src/ir/item.rs index 6712c8a7..2754c838 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -3,10 +3,11 @@ use super::super::codegen::CONSTIFIED_ENUM_MODULE_REPR_NAME; use super::annotations::Annotations; use super::comment; +use super::comp::MethodKind; use super::context::{BindgenContext, ItemId, PartialType}; use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; use super::dot::DotAttributes; -use super::function::Function; +use super::function::{Function, FunctionKind}; use super::item_kind::ItemKind; use super::layout::Opaque; use super::module::Module; @@ -874,6 +875,27 @@ impl Item { _ => false, } } + + /// Is this item of a kind that is enabled for code generation? + pub fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool { + let cc = &ctx.options().codegen_config; + match *self.kind() { + ItemKind::Module(..) => true, + ItemKind::Var(_) => cc.vars, + ItemKind::Type(_) => cc.types, + ItemKind::Function(ref f) => { + match f.kind() { + FunctionKind::Function => cc.functions, + FunctionKind::Method(MethodKind::Constructor) => cc.constructors, + FunctionKind::Method(MethodKind::Destructor) | + FunctionKind::Method(MethodKind::VirtualDestructor) => cc.destructors, + FunctionKind::Method(MethodKind::Static) | + FunctionKind::Method(MethodKind::Normal) | + FunctionKind::Method(MethodKind::Virtual) => cc.methods, + } + } + } + } } impl IsOpaque for ItemId { diff --git a/src/ir/named.rs b/src/ir/named.rs index a36ded64..5351f309 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -211,6 +211,7 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> { EdgeKind::BaseMember | EdgeKind::Field | EdgeKind::Constructor | + EdgeKind::Destructor | EdgeKind::VarType | EdgeKind::FunctionReturn | EdgeKind::FunctionParameter | diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs index cb27e8db..d4b081f5 100644 --- a/src/ir/traversal.rs +++ b/src/ir/traversal.rs @@ -139,6 +139,19 @@ pub enum EdgeKind { /// ``` Constructor, + /// An edge from a class or struct type to its destructor function. For + /// example, the edge from `Doggo` to `Doggo::~Doggo()`: + /// + /// ```C++ + /// struct Doggo { + /// char* wow; + /// + /// public: + /// ~Doggo(); + /// }; + /// ``` + Destructor, + /// An edge from a function declaration to its return type. For example, the /// edge from `foo` to `int`: /// @@ -172,26 +185,54 @@ pub enum EdgeKind { pub trait TraversalPredicate { /// Should the traversal follow this edge, and visit everything that is /// reachable through it? - fn should_follow(&self, edge: Edge) -> bool; + fn should_follow(&self, ctx: &BindgenContext, edge: Edge) -> bool; } -impl TraversalPredicate for fn(Edge) -> bool { - fn should_follow(&self, edge: Edge) -> bool { - (*self)(edge) +impl TraversalPredicate for for<'a> fn(&'a BindgenContext, Edge) -> bool { + fn should_follow(&self, ctx: &BindgenContext, edge: Edge) -> bool { + (*self)(ctx, edge) } } /// A `TraversalPredicate` implementation that follows all edges, and therefore /// traversals using this predicate will see the whole IR graph reachable from /// the traversal's roots. -pub fn all_edges(_: Edge) -> bool { +pub fn all_edges(_: &BindgenContext, _: Edge) -> bool { true } +/// A `TraversalPredicate` implementation that only follows edges to items that +/// are enabled for code generation. This lets us skip considering items for +/// which we won't generate any bindings to. +pub fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool { + let cc = &ctx.options().codegen_config; + match edge.kind { + EdgeKind::Generic => ctx.resolve_item(edge.to).is_enabled_for_codegen(ctx), + + // We statically know the kind of item that non-generic edges can point + // to, so we don't need to actually resolve the item and check + // `Item::is_enabled_for_codegen`. + EdgeKind::TemplateParameterDefinition | + EdgeKind::TemplateArgument | + EdgeKind::TemplateDeclaration | + EdgeKind::BaseMember | + EdgeKind::Field | + EdgeKind::InnerType | + EdgeKind::FunctionReturn | + EdgeKind::FunctionParameter | + EdgeKind::VarType | + EdgeKind::TypeReference => cc.types, + EdgeKind::InnerVar => cc.vars, + EdgeKind::Method => cc.methods, + EdgeKind::Constructor => cc.constructors, + EdgeKind::Destructor => cc.destructors, + } +} + /// A `TraversalPredicate` implementation that never follows any edges, and /// therefore traversals using this predicate will only visit the traversal's /// roots. -pub fn no_edges(_: Edge) -> bool { +pub fn no_edges(_: &BindgenContext, _: Edge) -> bool { false } @@ -401,7 +442,7 @@ impl<'ctx, 'gen, Storage, Queue, Predicate> Tracer { fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { let edge = Edge::new(item, kind); - if !self.predicate.should_follow(edge) { + if !self.predicate.should_follow(self.ctx, edge) { return; } @@ -451,7 +492,7 @@ pub type AssertNoDanglingItemsTraversal<'ctx, 'gen> = 'gen, Paths<'ctx, 'gen>, VecDeque<ItemId>, - fn(Edge) -> bool>; + for<'a> fn(&'a BindgenContext, Edge) -> bool>; #[cfg(test)] mod tests { diff --git a/tests/expectations/tests/gen-constructors-neg.rs b/tests/expectations/tests/gen-constructors-neg.rs index 834d5f2e..c894b95c 100644 --- a/tests/expectations/tests/gen-constructors-neg.rs +++ b/tests/expectations/tests/gen-constructors-neg.rs @@ -19,7 +19,3 @@ fn bindgen_test_layout_Foo() { impl Clone for Foo { fn clone(&self) -> Self { *self } } -extern "C" { - #[link_name = "_ZN3FooC1Ei"] - pub fn Foo_Foo(this: *mut Foo, a: ::std::os::raw::c_int); -} diff --git a/tests/expectations/tests/gen-destructors-neg.rs b/tests/expectations/tests/gen-destructors-neg.rs index c7c97104..64373d75 100644 --- a/tests/expectations/tests/gen-destructors-neg.rs +++ b/tests/expectations/tests/gen-destructors-neg.rs @@ -21,7 +21,3 @@ fn bindgen_test_layout_Foo() { "Alignment of field: " , stringify ! ( Foo ) , "::" , stringify ! ( bar ) )); } -extern "C" { - #[link_name = "_ZN3FooD1Ev"] - pub fn Foo_Foo_destructor(this: *mut Foo); -} diff --git a/tests/expectations/tests/issue-826-generating-methods-when-asked-not-to.rs b/tests/expectations/tests/issue-826-generating-methods-when-asked-not-to.rs new file mode 100644 index 00000000..c894b95c --- /dev/null +++ b/tests/expectations/tests/issue-826-generating-methods-when-asked-not-to.rs @@ -0,0 +1,21 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Foo { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Foo() { + assert_eq!(::std::mem::size_of::<Foo>() , 1usize , concat ! ( + "Size of: " , stringify ! ( Foo ) )); + assert_eq! (::std::mem::align_of::<Foo>() , 1usize , concat ! ( + "Alignment of " , stringify ! ( Foo ) )); +} +impl Clone for Foo { + fn clone(&self) -> Self { *self } +} diff --git a/tests/headers/issue-826-generating-methods-when-asked-not-to.hpp b/tests/headers/issue-826-generating-methods-when-asked-not-to.hpp new file mode 100644 index 00000000..f6b2ed30 --- /dev/null +++ b/tests/headers/issue-826-generating-methods-when-asked-not-to.hpp @@ -0,0 +1,5 @@ +// bindgen-flags: --ignore-methods -- --target=i686-pc-win32 + +struct Foo { + void test(); +}; |