summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rwxr-xr-xsrc/clang.rs9
-rwxr-xr-xsrc/codegen/mod.rs129
-rw-r--r--src/ir/comp.rs33
-rw-r--r--src/ir/context.rs2
-rw-r--r--src/ir/function.rs23
-rw-r--r--src/ir/item.rs59
-rw-r--r--src/ir/mod.rs1
-rw-r--r--src/ir/ty.rs67
-rw-r--r--src/ir/type_collector.rs23
-rwxr-xr-xsrc/lib.rs1
-rw-r--r--tests/tests.rs11
12 files changed, 212 insertions, 148 deletions
diff --git a/.travis.yml b/.travis.yml
index 031c61ff..5d3395e5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -41,6 +41,8 @@ before_script:
script:
- cargo build --verbose --features llvm_stable
- cargo test --features llvm_stable
+ - cargo build --release --verbose --features llvm_stable
+ - cargo test --release --features llvm_stable
- git add -A
- git diff @
- git diff-index --quiet HEAD
diff --git a/src/clang.rs b/src/clang.rs
index 0297ac0a..07680367 100755
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -670,9 +670,12 @@ impl Type {
/// Given that this type is an array, vector, or complex type, return the
/// type of its elements.
- pub fn elem_type(&self) -> Type {
- unsafe {
- Type { x: clang_getElementType(self.x) }
+ pub fn elem_type(&self) -> Option<Type> {
+ let current_type = Type { x: unsafe { clang_getElementType(self.x) } };
+ if current_type.kind() != CXType_Invalid {
+ Some(current_type)
+ } else {
+ None
}
}
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 65900739..a656c2c1 100755
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -14,11 +14,11 @@ use ir::item_kind::ItemKind;
use ir::comp::{CompKind, CompInfo, Field, Method};
use ir::layout::Layout;
use ir::annotations::FieldAccessorKind;
+use ir::type_collector::{ItemSet, TypeCollector};
use std::ops;
use std::borrow::Cow;
use std::mem;
-use std::collections::BTreeSet;
use std::collections::HashSet;
use std::collections::hash_map::{HashMap, Entry};
@@ -1584,133 +1584,6 @@ impl CodeGenerator for Function {
}
}
-type ItemSet = BTreeSet<ItemId>;
-
-trait TypeCollector {
- type Extra;
-
- fn collect_types(&self,
- context: &BindgenContext,
- types: &mut ItemSet,
- extra: &Self::Extra);
-}
-
-impl TypeCollector for ItemId {
- type Extra = ();
-
- fn collect_types(&self,
- context: &BindgenContext,
- types: &mut ItemSet,
- extra: &()) {
- context.resolve_item(*self).collect_types(context, types, extra);
- }
-}
-
-impl TypeCollector for Item {
- type Extra = ();
-
- fn collect_types(&self,
- context: &BindgenContext,
- types: &mut ItemSet,
- _extra: &()) {
- if self.is_hidden(context) || types.contains(&self.id()) {
- return;
- }
-
- match *self.kind() {
- ItemKind::Type(ref ty) => {
- types.insert(self.id());
- if !self.is_opaque(context) {
- ty.collect_types(context, types, self);
- }
- }
- _ => {}, // FIXME.
- }
- }
-}
-
-impl TypeCollector for Type {
- type Extra = Item;
-
- fn collect_types(&self,
- context: &BindgenContext,
- types: &mut ItemSet,
- item: &Item) {
- match *self.kind() {
- TypeKind::Pointer(inner) |
- TypeKind::Reference(inner) |
- TypeKind::Array(inner, _) |
- TypeKind::TemplateAlias(inner, _) |
- TypeKind::Alias(_, inner) |
- TypeKind::Named(_, Some(inner)) |
- TypeKind::ResolvedTypeRef(inner)
- => inner.collect_types(context, types, &()),
-
- TypeKind::TemplateRef(inner, ref template_args) => {
- inner.collect_types(context, types, &());
- for item in template_args {
- item.collect_types(context, types, &());
- }
- }
- TypeKind::Comp(ref ci) => ci.collect_types(context, types, item),
- TypeKind::Function(ref sig) => {
- sig.collect_types(context, types, item)
- }
- // FIXME: Pending types!
- ref other @ _ => {
- debug!("Ignoring: {:?}", other);
- },
- }
- }
-}
-
-impl TypeCollector for FunctionSig {
- type Extra = Item;
-
- fn collect_types(&self,
- context: &BindgenContext,
- types: &mut ItemSet,
- _item: &Item) {
- self.return_type().collect_types(context, types, &());
-
- for &(_, ty) in self.argument_types() {
- ty.collect_types(context, types, &());
- }
- }
-}
-
-impl TypeCollector for CompInfo {
- type Extra = Item;
-
- fn collect_types(&self,
- context: &BindgenContext,
- types: &mut ItemSet,
- item: &Item) {
- if let Some(template) = self.specialized_template() {
- template.collect_types(context, types, &());
- }
-
- let applicable_template_args = item.applicable_template_args(context);
- for arg in applicable_template_args {
- arg.collect_types(context, types, &());
- }
-
- for base in self.base_members() {
- base.collect_types(context, types, &());
- }
-
- for field in self.fields() {
- field.ty().collect_types(context, types, &());
- }
-
- for ty in self.inner_types() {
- ty.collect_types(context, types, &());
- }
-
- // FIXME(emilio): Methods, VTable?
- }
-}
-
pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
context.gen(|context| {
let mut result = CodegenResult::new();
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index 355adb5c..98003936 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -5,6 +5,7 @@ use super::context::BindgenContext;
use super::layout::Layout;
use super::item::{Item, ItemId};
use super::ty::{Type, RUST_DERIVE_IN_ARRAY_LIMIT};
+use super::type_collector::{ItemSet, TypeCollector};
use std::cell::Cell;
use std::cmp;
use parse::{ClangItemParser, ParseError};
@@ -802,3 +803,35 @@ impl CompInfo {
})
}
}
+
+impl TypeCollector for CompInfo {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ item: &Item) {
+ if let Some(template) = self.specialized_template() {
+ template.collect_types(context, types, &());
+ }
+
+ let applicable_template_args = item.applicable_template_args(context);
+ for arg in applicable_template_args {
+ arg.collect_types(context, types, &());
+ }
+
+ for base in self.base_members() {
+ base.collect_types(context, types, &());
+ }
+
+ for field in self.fields() {
+ field.ty().collect_types(context, types, &());
+ }
+
+ for ty in self.inner_types() {
+ ty.collect_types(context, types, &());
+ }
+
+ // FIXME(emilio): Methods, VTable?
+ }
+}
diff --git a/src/ir/context.rs b/src/ir/context.rs
index 65c62817..729a1c02 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -32,7 +32,7 @@ enum TypeKey {
// context.
struct GenContext<'ctx>(ExtCtxt<'ctx>);
-impl<'ctx> fmt::Debug for GenContext <'ctx> {
+impl<'ctx> fmt::Debug for GenContext<'ctx> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "GenContext {{ ... }}")
}
diff --git a/src/ir/function.rs b/src/ir/function.rs
index 0cf23f43..e9fd4a25 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -1,8 +1,9 @@
//! Intermediate representation for C/C++ functions and methods.
+use super::context::BindgenContext;
use super::item::{Item, ItemId};
use super::ty::TypeKind;
-use super::context::BindgenContext;
+use super::type_collector::{ItemSet, TypeCollector};
use syntax::abi;
use clang;
use clangll::Enum_CXCallingConv;
@@ -97,13 +98,16 @@ pub fn cursor_mangling(cursor: &clang::Cursor) -> Option<String> {
}
let mut mangling = cursor.mangling();
+ if mangling.is_empty() {
+ return None;
+ }
// Try to undo backend linkage munging (prepended _, generally)
if cfg!(target_os = "macos") {
mangling.remove(0);
}
- if mangling.is_empty() { None } else { Some(mangling) }
+ Some(mangling)
}
impl FunctionSig {
@@ -246,3 +250,18 @@ impl ClangSubItemParser for Function {
Ok(ParseResult::New(function, Some(cursor)))
}
}
+
+impl TypeCollector for FunctionSig {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ _item: &Item) {
+ self.return_type().collect_types(context, types, &());
+
+ for &(_, ty) in self.argument_types() {
+ ty.collect_types(context, types, &());
+ }
+ }
+}
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 0d409f04..a6d15cd7 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -4,6 +4,7 @@ use regex::Regex;
use super::context::BindgenContext;
use super::item_kind::ItemKind;
use super::ty::{Type, TypeKind};
+use super::type_collector::{ItemSet, TypeCollector};
use super::function::Function;
use super::module::Module;
use super::annotations::Annotations;
@@ -11,7 +12,6 @@ use std::cell::{Cell, RefCell};
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use clang;
-use clangll;
/// A trait to get the canonical name from an item.
///
@@ -76,6 +76,40 @@ impl ItemCanonicalPath for ItemId {
}
}
+impl TypeCollector for ItemId {
+ type Extra = ();
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ extra: &()) {
+ context.resolve_item(*self).collect_types(context, types, extra);
+ }
+}
+
+impl TypeCollector for Item {
+ type Extra = ();
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ _extra: &()) {
+ if self.is_hidden(context) || types.contains(&self.id()) {
+ return;
+ }
+
+ match *self.kind() {
+ ItemKind::Type(ref ty) => {
+ types.insert(self.id());
+ if !self.is_opaque(context) {
+ ty.collect_types(context, types, self);
+ }
+ }
+ _ => {}, // FIXME.
+ }
+ }
+}
+
/// An item is the base of the bindgen representation, it can be either a
/// module, a type, a function, or a variable (see `ItemKind` for more
/// information).
@@ -566,12 +600,12 @@ impl Item {
static ref RE_ENDS_WITH_BINDGEN_TY: Regex = Regex::new(r"_bindgen_ty(_\d+)+$").unwrap();
static ref RE_ENDS_WITH_BINDGEN_MOD: Regex = Regex::new(r"_bindgen_mod(_\d+)+$").unwrap();
}
-
+
let (re, kind) = match *self.kind() {
ItemKind::Module(..) => (&*RE_ENDS_WITH_BINDGEN_MOD, "mod"),
_ => (&*RE_ENDS_WITH_BINDGEN_TY, "ty"),
};
-
+
let parent_name = parent_name.and_then(|n| if n.is_empty() { None } else { Some(n) });
match (parent_name, base_name) {
(Some(parent), Some(base)) => format!("{}_{}", parent, base),
@@ -636,6 +670,7 @@ impl ClangItemParser for Item {
use ir::function::Function;
use ir::module::Module;
use ir::var::Var;
+ use clangll::*;
if !cursor.is_valid() {
return Err(ParseError::Continue);
@@ -697,11 +732,23 @@ impl ClangItemParser for Item {
}
// Guess how does clang treat extern "C" blocks?
- if cursor.kind() == clangll::CXCursor_UnexposedDecl {
+ if cursor.kind() == CXCursor_UnexposedDecl {
Err(ParseError::Recurse)
} else {
- error!("Unhandled cursor kind: {} ({})",
- ::clang::kind_to_str(cursor.kind()), cursor.kind());
+ // We whitelist cursors here known to be unhandled, to prevent being
+ // too noisy about this.
+ match cursor.kind() {
+ CXCursor_MacroDefinition |
+ CXCursor_InclusionDirective => {
+ debug!("Unhandled cursor kind {:?}: {:?}",
+ cursor.kind(), cursor);
+ },
+ _ =>{
+ error!("Unhandled cursor kind {:?}: {:?}",
+ cursor.kind(), cursor);
+ }
+ }
+
Err(ParseError::Continue)
}
}
diff --git a/src/ir/mod.rs b/src/ir/mod.rs
index 01f388b8..3c658a4a 100644
--- a/src/ir/mod.rs
+++ b/src/ir/mod.rs
@@ -14,4 +14,5 @@ pub mod item_kind;
pub mod layout;
pub mod module;
pub mod ty;
+pub mod type_collector;
pub mod var;
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index 442e0122..a914ce14 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -7,6 +7,7 @@ use super::item::{Item, ItemId};
use super::int::IntKind;
use super::layout::Layout;
use super::context::BindgenContext;
+use super::type_collector::{ItemSet, TypeCollector};
use parse::{ClangItemParser, ParseResult, ParseError};
use clang::{self, Cursor};
@@ -602,7 +603,18 @@ impl Type {
return Err(ParseError::Recurse);
}
- error!("invalid type {:?}", ty);
+ // If the type name is empty we're probably
+ // over-recursing to find a template parameter name
+ // or something like that, so just don't be too
+ // noisy with it since it causes confusion, see for
+ // example the discussion in:
+ //
+ // https://github.com/jamesmunns/teensy3-rs/issues/9
+ if !ty.spelling().is_empty() {
+ error!("invalid type {:?}", ty);
+ } else {
+ warn!("invalid type {:?}", ty);
+ }
return Err(ParseError::Continue);
}
}
@@ -613,7 +625,11 @@ impl Type {
return Err(ParseError::Recurse);
}
- error!("invalid type `{}`", ty.spelling());
+ if !ty.spelling().is_empty() {
+ error!("invalid type {:?}", ty);
+ } else {
+ warn!("invalid type {:?}", ty);
+ }
return Err(ParseError::Continue);
}
}
@@ -647,7 +663,9 @@ impl Type {
CXType_VariableArray |
CXType_DependentSizedArray |
CXType_IncompleteArray => {
- let inner = Item::from_ty(&ty.elem_type(), location, parent_id, ctx)
+ let inner = Item::from_ty(ty.elem_type().as_ref()
+ .expect("Not an appropriate type?"),
+ location, parent_id, ctx)
.expect("Not able to resolve array element?");
TypeKind::Pointer(inner)
}
@@ -679,14 +697,18 @@ impl Type {
// That being said, that should be fixed eventually.
CXType_Vector |
CXType_ConstantArray => {
- let inner = Item::from_ty(&ty.elem_type(), location, parent_id, ctx)
+ let inner = Item::from_ty(ty.elem_type().as_ref()
+ .expect("Not an appropriate type?"),
+ location, parent_id, ctx)
.expect("Not able to resolve array element?");
TypeKind::Array(inner, ty.num_elements().unwrap())
}
// A complex number is always a real and an imaginary part, so
// represent that as a two-item array.
CXType_Complex => {
- let inner = Item::from_ty(&ty.elem_type(), location, parent_id, ctx)
+ let inner = Item::from_ty(ty.elem_type().as_ref()
+ .expect("Not an appropriate type?"),
+ location, parent_id, ctx)
.expect("Not able to resolve array element?");
TypeKind::Array(inner, 2)
}
@@ -709,3 +731,38 @@ impl Type {
Ok(ParseResult::New(ty, Some(cursor.canonical())))
}
}
+
+impl TypeCollector for Type {
+ type Extra = Item;
+
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ item: &Item) {
+ match *self.kind() {
+ TypeKind::Pointer(inner) |
+ TypeKind::Reference(inner) |
+ TypeKind::Array(inner, _) |
+ TypeKind::TemplateAlias(inner, _) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::Named(_, Some(inner)) |
+ TypeKind::ResolvedTypeRef(inner)
+ => inner.collect_types(context, types, &()),
+
+ TypeKind::TemplateRef(inner, ref template_args) => {
+ inner.collect_types(context, types, &());
+ for item in template_args {
+ item.collect_types(context, types, &());
+ }
+ }
+ TypeKind::Comp(ref ci) => ci.collect_types(context, types, item),
+ TypeKind::Function(ref sig) => {
+ sig.collect_types(context, types, item)
+ }
+ // FIXME: Pending types!
+ ref other @ _ => {
+ debug!("Ignoring: {:?}", other);
+ },
+ }
+ }
+}
diff --git a/src/ir/type_collector.rs b/src/ir/type_collector.rs
new file mode 100644
index 00000000..a829b165
--- /dev/null
+++ b/src/ir/type_collector.rs
@@ -0,0 +1,23 @@
+//! Collecting type items.
+
+use std::collections::BTreeSet;
+use super::context::BindgenContext;
+use super::item::ItemId;
+
+/// A set of items.
+pub type ItemSet = BTreeSet<ItemId>;
+
+/// Collect all the type items referenced by this item.
+pub trait TypeCollector {
+ /// If a particular type needs extra information beyond what it has in
+ /// `self` and `context` to find its referenced type items, its
+ /// implementation can define this associated type, forcing callers to pass
+ /// the needed information through.
+ type Extra;
+
+ /// Add each type item referenced by `self` into the `types` set.
+ fn collect_types(&self,
+ context: &BindgenContext,
+ types: &mut ItemSet,
+ extra: &Self::Extra);
+}
diff --git a/src/lib.rs b/src/lib.rs
index 79385dc1..19ecb6c9 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,6 +12,7 @@
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![deny(missing_docs)]
+#![deny(warnings)]
// We internally use the deprecated BindgenOptions all over the place. Once we
// remove its `pub` declaration, we can un-deprecate it and remove this pragma.
diff --git a/tests/tests.rs b/tests/tests.rs
index 003c0f1a..addaa5ad 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -64,7 +64,11 @@ fn run_bindgen_tests() {
let mut bindgen = PathBuf::from(&crate_root);
bindgen.push("target");
- bindgen.push("debug");
+ if cfg!(debug_assertions) {
+ bindgen.push("debug");
+ } else {
+ bindgen.push("release");
+ }
bindgen.push("bindgen");
if !bindgen.is_file() {
panic!("{} is not a file! Build bindgen before running tests.",
@@ -92,8 +96,9 @@ fn run_bindgen_tests() {
.and_then(|x| x.parse::<usize>().ok())
.unwrap_or(TEST_BATCH_DEFAULT_SIZE);
- // Spawn batch_size child to run in parallel
- // and wait on all of them before processing the next batch
+ // Spawn `batch_size` children to run in parallel and wait on all of them
+ // before processing the next batch. This puts a limit on the resources
+ // consumed when testing, so that we don't overload the system.
let children = tests.chunks(batch_size).map(|x| {
x.iter().map(|entry| {