summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/codegen/mod.rs41
-rw-r--r--src/ir/cant_derive_debug.rs1
-rw-r--r--src/ir/comp.rs6
-rw-r--r--src/ir/context.rs6
-rw-r--r--src/ir/function.rs56
-rw-r--r--src/ir/item.rs24
-rw-r--r--src/ir/named.rs1
-rw-r--r--src/ir/traversal.rs57
-rw-r--r--tests/expectations/tests/gen-constructors-neg.rs4
-rw-r--r--tests/expectations/tests/gen-destructors-neg.rs4
-rw-r--r--tests/expectations/tests/issue-826-generating-methods-when-asked-not-to.rs21
-rw-r--r--tests/headers/issue-826-generating-methods-when-asked-not-to.hpp5
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();
+};