summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rw-r--r--ci/before_install.sh15
-rw-r--r--src/clang.rs19
-rw-r--r--src/codegen/mod.rs144
-rw-r--r--src/ir/function.rs2
-rw-r--r--src/ir/mod.rs1
-rw-r--r--src/ir/objc.rs99
-rw-r--r--src/ir/ty.rs43
-rw-r--r--src/lib.rs12
-rw-r--r--src/options.rs3
-rw-r--r--tests/expectations/Cargo.toml1
-rw-r--r--tests/expectations/tests/constant-non-specialized-tp.rs24
-rw-r--r--tests/expectations/tests/objc_interface.rs15
-rw-r--r--tests/expectations/tests/objc_interface_type.rs33
-rw-r--r--tests/expectations/tests/objc_method.rs17
-rw-r--r--tests/headers/constant-non-specialized-tp.hpp15
-rw-r--r--tests/headers/objc_interface.h8
-rw-r--r--tests/headers/objc_interface_type.h13
-rw-r--r--tests/headers/objc_method.h7
-rw-r--r--tests/tests.rs8
20 files changed, 461 insertions, 19 deletions
diff --git a/.travis.yml b/.travis.yml
index dd271f22..47af4eeb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,7 @@ addons:
os:
- linux
+ - osx
rust:
- stable
diff --git a/ci/before_install.sh b/ci/before_install.sh
index 06c75218..ebe4f4fb 100644
--- a/ci/before_install.sh
+++ b/ci/before_install.sh
@@ -1,6 +1,11 @@
set -e
pushd ~
+# Workaround for Travis CI macOS bug (https://github.com/travis-ci/travis-ci/issues/6307)
+if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
+ rvm get head || true
+fi
+
function llvm_version_triple() {
if [ "$1" == "3.8" ]; then
echo "3.8.0"
@@ -18,9 +23,17 @@ function llvm_download() {
tar -xf ${LLVM}.tar.xz -C llvm --strip-components=1
export LLVM_CONFIG_PATH=`pwd`/llvm/bin/llvm-config
+ if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
+ cp llvm/lib/libclang.dylib /usr/local/lib/libclang.dylib
+ fi
}
-llvm_download linux-gnu-ubuntu-14.04
+
+if [ "${TRAVIS_OS_NAME}" == "linux" ]; then
+ llvm_download linux-gnu-ubuntu-14.04
+else
+ llvm_download apple-darwin
+fi
popd
set +e
diff --git a/src/clang.rs b/src/clang.rs
index 9cf51436..a40abfca 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -201,14 +201,14 @@ impl Cursor {
}
/// Is the referent a template specialization?
- pub fn is_template(&self) -> bool {
+ pub fn is_template_specialization(&self) -> bool {
self.specialized().is_some()
}
/// Is the referent a fully specialized template specialization without any
/// remaining free template arguments?
pub fn is_fully_specialized_template(&self) -> bool {
- self.is_template() && self.num_template_args().unwrap_or(0) > 0
+ self.is_template_specialization() && self.num_template_args().unwrap_or(0) > 0
}
/// Is the referent a template specialization that still has remaining free
@@ -217,9 +217,17 @@ impl Cursor {
if self.is_toplevel() {
return false;
}
+
let parent = self.semantic_parent();
- (parent.is_template() && !parent.is_fully_specialized_template()) ||
- parent.is_in_non_fully_specialized_template()
+ if parent.is_fully_specialized_template() {
+ return false;
+ }
+
+ if !parent.is_template_like() {
+ return parent.is_in_non_fully_specialized_template();
+ }
+
+ return true;
}
/// Is this cursor pointing a valid referent?
@@ -688,7 +696,8 @@ impl Type {
CXType_Pointer |
CXType_RValueReference |
CXType_LValueReference |
- CXType_MemberPointer => {
+ CXType_MemberPointer |
+ CXType_ObjCObjectPointer => {
let ret = Type {
x: unsafe { clang_getPointeeType(self.x) },
};
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 436c2bd7..9dd3b6b9 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -13,6 +13,7 @@ use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath};
use ir::item_kind::ItemKind;
use ir::layout::Layout;
use ir::module::Module;
+use ir::objc::ObjCInterface;
use ir::ty::{Type, TypeKind};
use ir::type_collector::ItemSet;
use ir::var::Var;
@@ -87,6 +88,9 @@ struct CodegenResult<'a> {
/// Whether an incomplete array has been generated at least once.
saw_incomplete_array: bool,
+ /// Whether Objective C types have been seen at least once.
+ saw_objc: bool,
+
items_seen: HashSet<ItemId>,
/// The set of generated function/var names, needed because in C/C++ is
/// legal to do something like:
@@ -119,6 +123,7 @@ impl<'a> CodegenResult<'a> {
items: vec![],
saw_union: false,
saw_incomplete_array: false,
+ saw_objc: false,
codegen_id: codegen_id,
items_seen: Default::default(),
functions_seen: Default::default(),
@@ -140,6 +145,10 @@ impl<'a> CodegenResult<'a> {
self.saw_incomplete_array = true;
}
+ fn saw_objc(&mut self) {
+ self.saw_objc = true;
+ }
+
fn seen(&self, item: ItemId) -> bool {
self.items_seen.contains(&item)
}
@@ -184,6 +193,7 @@ impl<'a> CodegenResult<'a> {
self.saw_union |= new.saw_union;
self.saw_incomplete_array |= new.saw_incomplete_array;
+ self.saw_objc |= new.saw_objc;
new.items
}
@@ -359,6 +369,9 @@ impl CodeGenerator for Module {
if ctx.need_bindegen_complex_type() {
utils::prepend_complex_type(ctx, &mut *result);
}
+ if result.saw_objc {
+ utils::prepend_objc_header(ctx, &mut *result);
+ }
}
};
@@ -623,6 +636,9 @@ impl CodeGenerator for Type {
TypeKind::Enum(ref ei) => {
ei.codegen(ctx, result, whitelisted_items, item)
}
+ TypeKind::ObjCInterface(ref interface) => {
+ interface.codegen(ctx, result, whitelisted_items, item)
+ }
ref u @ TypeKind::UnresolvedTypeRef(..) => {
unreachable!("Should have been resolved after parsing {:?}!", u)
}
@@ -2111,6 +2127,9 @@ impl ToRustTy for Type {
let ident = ctx.rust_ident(&name);
quote_ty!(ctx.ext_cx(), $ident)
}
+ TypeKind::ObjCInterface(..) => {
+ quote_ty!(ctx.ext_cx(), id)
+ },
ref u @ TypeKind::UnresolvedTypeRef(..) => {
unreachable!("Should have been resolved after parsing {:?}!", u)
}
@@ -2144,10 +2163,22 @@ impl ToRustTy for FunctionSig {
// the array type derivation.
//
// [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
- let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.canonical_type(ctx).kind() {
- t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
- } else {
- arg_item.to_rust_ty(ctx)
+ let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
+ TypeKind::Array(t, _) => {
+ t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span())
+ },
+ TypeKind::Pointer(inner) => {
+ let inner = ctx.resolve_item(inner);
+ let inner_ty = inner.expect_type();
+ if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() {
+ quote_ty!(ctx.ext_cx(), id)
+ } else {
+ arg_item.to_rust_ty(ctx)
+ }
+ },
+ _ => {
+ arg_item.to_rust_ty(ctx)
+ }
};
let arg_name = match *name {
@@ -2263,6 +2294,85 @@ impl CodeGenerator for Function {
}
}
+impl CodeGenerator for ObjCInterface {
+ type Extra = Item;
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ _whitelisted_items: &ItemSet,
+ _: &Item) {
+ let mut impl_items = vec![];
+ let mut trait_items = vec![];
+
+ for method in self.methods() {
+ let method_name = ctx.rust_ident(method.name());
+
+ let body = quote_stmt!(ctx.ext_cx(), msg_send![self, $method_name])
+ .unwrap();
+ let block = ast::Block {
+ stmts: vec![body],
+ id: ast::DUMMY_NODE_ID,
+ rules: ast::BlockCheckMode::Default,
+ span: ctx.span(),
+ };
+
+ let sig = aster::AstBuilder::new()
+ .method_sig()
+ .unsafe_()
+ .fn_decl()
+ .self_()
+ .build(ast::SelfKind::Value(ast::Mutability::Immutable))
+ .build(ast::FunctionRetTy::Default(ctx.span()));
+ let attrs = vec![];
+
+ let impl_item = ast::ImplItem {
+ id: ast::DUMMY_NODE_ID,
+ ident: ctx.rust_ident(method.rust_name()),
+ vis: ast::Visibility::Inherited, // Public,
+ attrs: attrs.clone(),
+ node: ast::ImplItemKind::Method(sig.clone(), P(block)),
+ defaultness: ast::Defaultness::Final,
+ span: ctx.span(),
+ };
+
+ let trait_item = ast::TraitItem {
+ id: ast::DUMMY_NODE_ID,
+ ident: ctx.rust_ident(method.rust_name()),
+ attrs: attrs,
+ node: ast::TraitItemKind::Method(sig, None),
+ span: ctx.span(),
+ };
+
+ impl_items.push(impl_item);
+ trait_items.push(trait_item)
+ }
+
+
+ let trait_block = aster::AstBuilder::new()
+ .item()
+ .pub_()
+ .trait_(self.name())
+ .with_items(trait_items)
+ .build();
+
+ let ty_for_impl = quote_ty!(ctx.ext_cx(), id);
+ let impl_block = aster::AstBuilder::new()
+ .item()
+ .impl_()
+ .trait_()
+ .id(self.name())
+ .build()
+ .with_items(impl_items)
+ .build_ty(ty_for_impl);
+
+ result.push(trait_block);
+ result.push(impl_block);
+ result.saw_objc();
+ }
+}
+
+
+
pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
context.gen(|context| {
let counter = Cell::new(0);
@@ -2296,6 +2406,32 @@ mod utils {
use syntax::ast;
use syntax::ptr::P;
+
+ pub fn prepend_objc_header(ctx: &BindgenContext,
+ result: &mut Vec<P<ast::Item>>) {
+ let use_objc = if ctx.options().objc_extern_crate {
+ quote_item!(ctx.ext_cx(),
+ use objc;
+ ).unwrap()
+ } else {
+ quote_item!(ctx.ext_cx(),
+ #[macro_use]
+ extern crate objc;
+ ).unwrap()
+ };
+
+
+ let id_type = quote_item!(ctx.ext_cx(),
+ #[allow(non_camel_case_types)]
+ pub type id = *mut objc::runtime::Object;
+ )
+ .unwrap();
+
+ let items = vec![use_objc, id_type];
+ let old_items = mem::replace(result, items);
+ result.extend(old_items.into_iter());
+ }
+
pub fn prepend_union_types(ctx: &BindgenContext,
result: &mut Vec<P<ast::Item>>) {
let prefix = ctx.trait_prefix();
diff --git a/src/ir/function.rs b/src/ir/function.rs
index 6e205f1b..a50edfde 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -93,7 +93,7 @@ fn get_abi(cc: CXCallingConv) -> abi::Abi {
pub fn cursor_mangling(cursor: &clang::Cursor) -> Option<String> {
// We early return here because libclang may crash in some case
// if we pass in a variable inside a partial specialized template.
- // See servo/rust-bindgen#67.
+ // See servo/rust-bindgen#67, and servo/rust-bindgen#462.
if cursor.is_in_non_fully_specialized_template() {
return None;
}
diff --git a/src/ir/mod.rs b/src/ir/mod.rs
index 73793b16..d424fcdf 100644
--- a/src/ir/mod.rs
+++ b/src/ir/mod.rs
@@ -17,3 +17,4 @@ pub mod module;
pub mod ty;
pub mod type_collector;
pub mod var;
+pub mod objc;
diff --git a/src/ir/objc.rs b/src/ir/objc.rs
new file mode 100644
index 00000000..b9fe280b
--- /dev/null
+++ b/src/ir/objc.rs
@@ -0,0 +1,99 @@
+//! Objective C types
+
+use clang;
+use clang_sys::CXChildVisit_Continue;
+use clang_sys::CXCursor_ObjCInstanceMethodDecl;
+// use clang_sys::CXCursor_ObjCSuperClassRef;
+use super::context::BindgenContext;
+
+/// Objective C interface as used in TypeKind
+///
+/// Also protocols are parsed as this type
+#[derive(Debug)]
+pub struct ObjCInterface {
+ /// The name
+ /// like, NSObject
+ name: String,
+
+ /// List of the methods defined in this interfae
+ methods: Vec<ObjCInstanceMethod>,
+}
+
+/// The objective c methods
+#[derive(Debug)]
+pub struct ObjCInstanceMethod {
+ /// The original method selector name
+ /// like, dataWithBytes:length:
+ name: String,
+
+ /// Method name as converted to rust
+ /// like, dataWithBytes_length_
+ rust_name: String,
+}
+
+impl ObjCInterface {
+ fn new(name: &str) -> ObjCInterface {
+ ObjCInterface {
+ name: name.to_owned(),
+ methods: Vec::new(),
+ }
+ }
+
+ /// The name
+ /// like, NSObject
+ pub fn name(&self) -> &str {
+ self.name.as_ref()
+ }
+
+ /// List of the methods defined in this interfae
+ pub fn methods(&self) -> &Vec<ObjCInstanceMethod> {
+ &self.methods
+ }
+
+ /// Parses the Objective C interface from the cursor
+ pub fn from_ty(cursor: &clang::Cursor,
+ _ctx: &mut BindgenContext)
+ -> Option<Self> {
+ let name = cursor.spelling();
+ let mut interface = Self::new(&name);
+
+ cursor.visit(|cursor| {
+ match cursor.kind() {
+ CXCursor_ObjCInstanceMethodDecl => {
+ let name = cursor.spelling();
+ let method = ObjCInstanceMethod::new(&name);
+
+ interface.methods.push(method);
+ }
+ _ => {}
+ }
+ CXChildVisit_Continue
+ });
+ Some(interface)
+ }
+}
+
+impl ObjCInstanceMethod {
+ fn new(name: &str) -> ObjCInstanceMethod {
+ let split_name: Vec<&str> = name.split(':').collect();
+
+ let rust_name = split_name.join("_");
+
+ ObjCInstanceMethod {
+ name: name.to_owned(),
+ rust_name: rust_name.to_owned(),
+ }
+ }
+
+ /// The original method selector name
+ /// like, dataWithBytes:length:
+ pub fn name(&self) -> &str {
+ self.name.as_ref()
+ }
+
+ /// Method name as converted to rust
+ /// like, dataWithBytes_length_
+ pub fn rust_name(&self) -> &str {
+ self.rust_name.as_ref()
+ }
+}
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index 5474aa57..1246057b 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -10,6 +10,7 @@ use super::function::FunctionSig;
use super::int::IntKind;
use super::item::Item;
use super::layout::Layout;
+use super::objc::ObjCInterface;
use super::type_collector::{ItemSet, TypeCollector};
/// The base representation of a type in bindgen.
@@ -179,8 +180,12 @@ impl Type {
/// Is this a incomplete array type?
pub fn is_incomplete_array(&self, ctx: &BindgenContext) -> Option<ItemId> {
match self.kind {
- TypeKind::Array(item, len) => if len == 0 { Some(item) } else { None },
- TypeKind::ResolvedTypeRef(inner) => ctx.resolve_type(inner).is_incomplete_array(ctx),
+ TypeKind::Array(item, len) => {
+ if len == 0 { Some(item) } else { None }
+ }
+ TypeKind::ResolvedTypeRef(inner) => {
+ ctx.resolve_type(inner).is_incomplete_array(ctx)
+ }
_ => None,
}
}
@@ -287,7 +292,7 @@ impl Type {
let mut remaining = chars;
let valid = (first.is_alphabetic() || first == '_') &&
- remaining.all(|c| c.is_alphanumeric() || c == '_');
+ remaining.all(|c| c.is_alphanumeric() || c == '_');
!valid
}
@@ -324,7 +329,8 @@ impl Type {
TypeKind::Void |
TypeKind::NullPtr |
TypeKind::BlockPointer |
- TypeKind::Pointer(..) => Some(self),
+ TypeKind::Pointer(..) |
+ TypeKind::ObjCInterface(..) => Some(self),
TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(inner) |
@@ -492,6 +498,9 @@ pub enum TypeKind {
/// A named type, that is, a template parameter.
Named,
+
+ /// Objective C interface. Always referenced through a pointer
+ ObjCInterface(ObjCInterface),
}
impl Type {
@@ -525,6 +534,8 @@ impl Type {
TypeKind::BlockPointer |
TypeKind::Pointer(..) => false,
+ TypeKind::ObjCInterface(..) => true, // dunno?
+
TypeKind::UnresolvedTypeRef(..) => {
unreachable!("Should have been resolved after parsing!");
}
@@ -566,7 +577,16 @@ impl Type {
debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types);
let canonical_ty = ty.canonical_type();
- let kind = match ty.kind() {
+
+ // Parse objc protocols as if they were interfaces
+ let mut ty_kind = ty.kind();
+ if let Some(loc) = location {
+ if loc.kind() == CXCursor_ObjCProtocolDecl {
+ ty_kind = CXType_ObjCInterface;
+ }
+ }
+
+ let kind = match ty_kind {
CXType_Unexposed if *ty != canonical_ty &&
canonical_ty.kind() != CXType_Invalid &&
// Sometime clang desugars some types more than
@@ -720,8 +740,7 @@ impl Type {
}
};
- TypeKind::TemplateAlias(inner_type,
- args)
+ TypeKind::TemplateAlias(inner_type, args)
}
CXCursor_TemplateRef => {
let referenced = location.referenced().unwrap();
@@ -819,6 +838,7 @@ impl Type {
//
// We might need to, though, if the context is already in the
// process of resolving them.
+ CXType_ObjCObjectPointer |
CXType_MemberPointer |
CXType_Pointer => {
let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
@@ -900,6 +920,11 @@ impl Type {
parent_id,
ctx);
}
+ CXType_ObjCInterface => {
+ let interface = ObjCInterface::from_ty(&location.unwrap(), ctx)
+ .expect("Not a valid objc interface?");
+ TypeKind::ObjCInterface(interface)
+ }
_ => {
error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}",
ty.kind(),
@@ -954,6 +979,10 @@ impl TypeCollector for Type {
types.insert(id);
}
+ TypeKind::ObjCInterface(_) => {
+ // TODO:
+ }
+
// None of these variants have edges to other items and types.
TypeKind::UnresolvedTypeRef(_, _, None) |
TypeKind::Named |
diff --git a/src/lib.rs b/src/lib.rs
index dabab152..d6f3c66e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -198,6 +198,13 @@ impl Builder {
self
}
+ /// Generate '#[macro_use] extern crate objc;' instead of 'use objc;'
+ /// in the prologue of the files generated from objective-c files
+ pub fn objc_extern_crate(mut self, doit: bool) -> Self {
+ self.options.objc_extern_crate = doit;
+ self
+ }
+
/// Generate a C/C++ file that includes the header and has dummy uses of
/// every type defined in the header.
pub fn dummy_uses<T: Into<String>>(mut self, dummy_uses: T) -> Builder {
@@ -542,6 +549,10 @@ pub struct BindgenOptions {
/// Wether to whitelist types recursively. Defaults to true.
pub whitelist_recursively: bool,
+
+ /// Intead of emitting 'use objc;' to files generated from objective c files,
+ /// generate '#[macro_use] extern crate objc;'
+ pub objc_extern_crate: bool,
}
impl BindgenOptions {
@@ -588,6 +599,7 @@ impl Default for BindgenOptions {
conservative_inline_namespaces: false,
generate_comments: true,
whitelist_recursively: true,
+ objc_extern_crate: false,
}
}
}
diff --git a/src/options.rs b/src/options.rs
index 307ea6b0..535eac4b 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -49,6 +49,9 @@ pub fn builder_from_flags<I>(args: I)
Arg::with_name("no-recursive-whitelist")
.long("no-recursive-whitelist")
.help("Avoid whitelisting types recursively"),
+ Arg::with_name("objc-extern-crate")
+ .long("objc-extern-crate")
+ .help("Use extern crate instead of use for objc"),
Arg::with_name("builtins")
.long("builtins")
.help("Output bindings for builtin definitions, e.g. \
diff --git a/tests/expectations/Cargo.toml b/tests/expectations/Cargo.toml
index 034aa141..e0da6d5a 100644
--- a/tests/expectations/Cargo.toml
+++ b/tests/expectations/Cargo.toml
@@ -9,3 +9,4 @@ authors = [
]
[dependencies]
+objc = "0.2"
diff --git a/tests/expectations/tests/constant-non-specialized-tp.rs b/tests/expectations/tests/constant-non-specialized-tp.rs
new file mode 100644
index 00000000..bbadf8a2
--- /dev/null
+++ b/tests/expectations/tests/constant-non-specialized-tp.rs
@@ -0,0 +1,24 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Test<Args> {
+ pub _address: u8,
+ pub _phantom_0: ::std::marker::PhantomData<Args>,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Outer<T> {
+ pub _address: u8,
+ pub _phantom_0: ::std::marker::PhantomData<T>,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Outer_Inner<T> {
+ pub _address: u8,
+ pub _phantom_0: ::std::marker::PhantomData<T>,
+}
diff --git a/tests/expectations/tests/objc_interface.rs b/tests/expectations/tests/objc_interface.rs
new file mode 100644
index 00000000..027cf57e
--- /dev/null
+++ b/tests/expectations/tests/objc_interface.rs
@@ -0,0 +1,15 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+#![cfg(target_os="macos")]
+
+#[macro_use]
+extern crate objc;
+#[allow(non_camel_case_types)]
+pub type id = *mut objc::runtime::Object;
+pub trait Foo { }
+impl Foo for id { }
+pub trait bar { }
+impl bar for id { }
diff --git a/tests/expectations/tests/objc_interface_type.rs b/tests/expectations/tests/objc_interface_type.rs
new file mode 100644
index 00000000..2d68ee50
--- /dev/null
+++ b/tests/expectations/tests/objc_interface_type.rs
@@ -0,0 +1,33 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+#![cfg(target_os="macos")]
+
+#[macro_use]
+extern crate objc;
+#[allow(non_camel_case_types)]
+pub type id = *mut objc::runtime::Object;
+pub trait Foo { }
+impl Foo for id { }
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct FooStruct {
+ pub foo: *mut id,
+}
+#[test]
+fn bindgen_test_layout_FooStruct() {
+ assert_eq!(::std::mem::size_of::<FooStruct>() , 8usize);
+ assert_eq!(::std::mem::align_of::<FooStruct>() , 8usize);
+}
+impl Clone for FooStruct {
+ fn clone(&self) -> Self { *self }
+}
+extern "C" {
+ pub fn fooFunc(foo: id);
+}
+extern "C" {
+ #[link_name = "kFoo"]
+ pub static mut kFoo: *const id;
+}
diff --git a/tests/expectations/tests/objc_method.rs b/tests/expectations/tests/objc_method.rs
new file mode 100644
index 00000000..e2db24f6
--- /dev/null
+++ b/tests/expectations/tests/objc_method.rs
@@ -0,0 +1,17 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+#![cfg(target_os="macos")]
+
+#[macro_use]
+extern crate objc;
+#[allow(non_camel_case_types)]
+pub type id = *mut objc::runtime::Object;
+pub trait Foo {
+ unsafe fn method(self);
+}
+impl Foo for id {
+ unsafe fn method(self) { msg_send!(self , method) }
+}
diff --git a/tests/headers/constant-non-specialized-tp.hpp b/tests/headers/constant-non-specialized-tp.hpp
new file mode 100644
index 00000000..539c2887
--- /dev/null
+++ b/tests/headers/constant-non-specialized-tp.hpp
@@ -0,0 +1,15 @@
+// bindgen-flags: -- -std=c++11
+
+// This test ensure we protect ourselves from an LLVM crash.
+
+template <class... Args>
+struct Test {
+ static constexpr bool x[] = {Args::x...};
+};
+
+template<typename... T>
+struct Outer {
+ struct Inner {
+ static constexpr int value[] = { T::value... };
+ };
+};
diff --git a/tests/headers/objc_interface.h b/tests/headers/objc_interface.h
new file mode 100644
index 00000000..af84bf92
--- /dev/null
+++ b/tests/headers/objc_interface.h
@@ -0,0 +1,8 @@
+// bindgen-flags: --objc-extern-crate -- -x objective-c
+// bindgen-osx-only
+
+@interface Foo
+@end
+
+@protocol bar
+@end
diff --git a/tests/headers/objc_interface_type.h b/tests/headers/objc_interface_type.h
new file mode 100644
index 00000000..31d33664
--- /dev/null
+++ b/tests/headers/objc_interface_type.h
@@ -0,0 +1,13 @@
+// bindgen-flags: --objc-extern-crate -- -x objective-c
+// bindgen-osx-only
+
+@interface Foo
+@end
+
+struct FooStruct {
+ Foo *foo;
+};
+
+void fooFunc(Foo *foo);
+
+static const Foo *kFoo;
diff --git a/tests/headers/objc_method.h b/tests/headers/objc_method.h
new file mode 100644
index 00000000..91645f16
--- /dev/null
+++ b/tests/headers/objc_method.h
@@ -0,0 +1,7 @@
+// bindgen-flags: --objc-extern-crate -- -x objective-c
+// bindgen-osx-only
+
+@interface Foo
+- (void)method;
+// TODO: argument methods
+@end
diff --git a/tests/tests.rs b/tests/tests.rs
index 05c8ad2c..2886f8db 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -76,7 +76,7 @@ fn create_bindgen_builder(header: &PathBuf)
// Scoop up bindgen-flags from test header
let mut flags = Vec::with_capacity(2);
- for line in reader.lines().take(2) {
+ for line in reader.lines().take(3) {
let line = try!(line);
if line.contains("bindgen-flags: ") {
let extra_flags = line.split("bindgen-flags: ")
@@ -87,6 +87,12 @@ fn create_bindgen_builder(header: &PathBuf)
} else if line.contains("bindgen-unstable") &&
cfg!(feature = "llvm_stable") {
return Ok(None);
+ } else if line.contains("bindgen-osx-only") {
+ let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
+ flags = prepend_flags.into_iter()
+ .map(ToString::to_string)
+ .chain(flags)
+ .collect();
}
}