diff --git a/.travis.yml b/.travis.yml
index cfdd470308..274aefc11e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -42,6 +42,7 @@ script:
- cargo build --verbose --features llvm_stable
- make test
- git add -A
+ - git diff @
- git diff-index --quiet HEAD
notifications:
diff --git a/Makefile b/Makefile
index 853eb195e0..cad0f51349 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ BINDGEN := ./target/debug/bindgen
.PHONY: $(BINDGEN)
$(BINDGEN):
- [ -f $@ ] || cargo build
+ [ -f $@ ] || cargo build --features llvm_stable
.PHONY: test
test: regen-tests
diff --git a/src/gen.rs b/src/gen.rs
index 83406eacf2..60ea76eb87 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -19,6 +19,7 @@ use syntax::print::pprust::tts_to_string;
use super::BindgenOptions;
use super::LinkType;
+use parser::Accessor;
use types::*;
use aster;
@@ -840,6 +841,52 @@ fn comp_attrs(ctx: &GenCtx, ci: &CompInfo, name: &str, extra: &mut Vec
) {
+ if accessor == Accessor::None {
+ return;
+ }
+ let ident = ctx.ext_cx.ident_of(&format!("{}", name));
+ let mutable_getter_name = ctx.ext_cx.ident_of(&format!("get_{}_mut", name));
+ let getter_name = ctx.ext_cx.ident_of(&format!("get_{}", name));
+ let imp = match accessor {
+ Accessor::Regular => quote_item!(&ctx.ext_cx,
+ impl X {
+ #[inline]
+ pub fn $getter_name(&self) -> & $ty {
+ & self.$ident
+ }
+ pub fn $mutable_getter_name(&mut self) -> &mut $ty {
+ &mut self.$ident
+ }
+ }
+ ),
+ Accessor::Unsafe => quote_item!(&ctx.ext_cx,
+ impl X {
+ #[inline]
+ pub unsafe fn $getter_name(&self) -> & $ty {
+ & self.$ident
+ }
+ pub unsafe fn $mutable_getter_name(&mut self) -> &mut $ty {
+ &mut self.$ident
+ }
+ }
+ ),
+ Accessor::Immutable => quote_item!(&ctx.ext_cx,
+ impl X {
+ #[inline]
+ pub fn $getter_name(&self) -> & $ty {
+ & self.$ident
+ }
+ }
+ ),
+ _ => return
+ };
+ match imp.unwrap().node {
+ ast::ItemKind::Impl(_, _, _, _, _, ref items) => methods.extend(items.clone()),
+ _ => unreachable!()
+ }
+}
fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec
> {
let layout = ci.layout;
@@ -878,14 +925,15 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec
};
if let Some(ref base) = base_vftable {
- vffields.push(ast::StructField {
+ let field = ast::StructField {
span: ctx.span,
vis: ast::Visibility::Public,
ident: Some(ctx.ext_cx.ident_of("_base")),
id: ast::DUMMY_NODE_ID,
ty: P(mk_ty(ctx, false, &[base.clone()])),
attrs: vec![],
- });
+ };
+ vffields.push(field);
}
for vm in ci.vmethods.iter() {
@@ -1052,15 +1100,22 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec
} else {
rust_ty
};
-
- fields.push(ast::StructField {
+ let vis = if f.private {
+ ast::Visibility::Inherited
+ } else {
+ ast::Visibility::Public
+ };
+ gen_accessors(ctx, &f_name, &rust_ty, f.accessor, &mut methods);
+ let field = ast::StructField {
span: ctx.span,
ident: Some(ctx.ext_cx.ident_of(&f_name)),
- vis: ast::Visibility::Public,
+ vis: vis,
id: ast::DUMMY_NODE_ID,
ty: rust_ty,
attrs: mk_doc_attr(ctx, &f.comment)
- });
+ };
+ fields.push(field);
+
if bypass {
continue;
}
diff --git a/src/parser.rs b/src/parser.rs
index de1242be5d..a09954c139 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -122,6 +122,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
CXCursor_ClassTemplate |
CXCursor_ClassDecl |
CXCursor_StructDecl => {
+ let anno = Annotations::new(&cursor);
let kind = if cursor.kind() == CXCursor_UnionDecl {
CompKind::Union
} else {
@@ -159,7 +160,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
}
};
- let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout);
+ let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout, anno);
ci.parser_cursor = Some(cursor);
// If it's an instantiation of another template,
@@ -538,12 +539,34 @@ fn opaque_ty(ctx: &mut ClangParserCtx, ty: &cx::Type) {
}
}
-struct Annotations {
+#[derive(Copy, PartialEq, Clone, Debug)]
+pub enum Accessor {
+ None,
+ Regular,
+ Unsafe,
+ Immutable,
+}
+
+#[derive(Clone, PartialEq, Debug)]
+pub struct Annotations {
opaque: bool,
hide: bool,
use_as: Option,
/// Disable deriving copy/clone on this struct.
no_copy: bool,
+ // In the None case we fall back to the value specified
+ // in the enclosing decl
+ private: Option,
+ accessor: Option,
+}
+
+fn parse_accessor(s: &str) -> Accessor {
+ match s {
+ "false" => Accessor::None,
+ "unsafe" => Accessor::Unsafe,
+ "immutable" => Accessor::Immutable,
+ _ => Accessor::Regular,
+ }
}
impl Annotations {
@@ -553,6 +576,8 @@ impl Annotations {
hide: false,
use_as: None,
no_copy: false,
+ private: None,
+ accessor: None
};
anno.parse(&cursor.comment());
@@ -571,6 +596,10 @@ impl Annotations {
"hide" => self.hide = true,
"replaces" => self.use_as = Some(comment.get_tag_attr_value(i)),
"nocopy" => self.no_copy = true,
+ "private" => self.private = Some(comment.get_tag_attr_value(i) != "false"),
+ "accessor" => {
+ self.accessor = Some(parse_accessor(&comment.get_tag_attr_value(i)))
+ },
_ => (),
}
}
@@ -792,12 +821,16 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
if should_replace {
*info = FieldInfo::new(name, ty, comment, bitfields, mutable);
+ info.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false));
+ info.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None));
return CXChildVisit_Continue;
}
}
}
- let field = FieldInfo::new(name, ty, comment, bitfields, mutable);
+ let mut field = FieldInfo::new(name, ty, comment, bitfields, mutable);
+ field.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false));
+ field.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None));
ci.members.push(CompMember::Field(field));
}
CXCursor_StructDecl |
diff --git a/src/types.rs b/src/types.rs
index 8036a75fe2..09ce4cb2b4 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -13,6 +13,8 @@ pub use self::IKind::*;
pub use self::FKind::*;
use clang::Cursor;
+use parser::{Annotations, Accessor};
+
static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT;
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
@@ -446,6 +448,9 @@ pub struct CompInfo {
/// Used to detect if we've run in a has_destructor cycle while cycling
/// around the template arguments.
detect_has_destructor_cycle: Cell,
+
+ /// Annotations on the decl
+ pub anno: Annotations,
}
static mut UNNAMED_COUNTER: u32 = 0;
@@ -466,7 +471,8 @@ impl CompInfo {
comment: String,
kind: CompKind,
members: Vec,
- layout: Layout) -> CompInfo {
+ layout: Layout,
+ anno: Annotations) -> CompInfo {
let was_unnamed = name.is_empty();
CompInfo {
kind: kind,
@@ -494,6 +500,7 @@ impl CompInfo {
was_unnamed: was_unnamed,
detect_derive_debug_cycle: Cell::new(false),
detect_has_destructor_cycle: Cell::new(false),
+ anno: anno,
}
}
@@ -640,6 +647,12 @@ pub struct FieldInfo {
pub bitfields: Option>,
/// If the C++ field is marked as `mutable`
pub mutable: bool,
+ /// True when field or enclosing struct
+ /// has a `` annotation
+ pub private: bool,
+ /// Set by the `
`
+ /// annotation on a field or enclosing struct
+ pub accessor: Accessor,
}
impl FieldInfo {
@@ -654,6 +667,8 @@ impl FieldInfo {
comment: comment,
bitfields: bitfields,
mutable: mutable,
+ private: false,
+ accessor: Accessor::None,
}
}
}
diff --git a/tests/expectations/accessors.rs b/tests/expectations/accessors.rs
new file mode 100644
index 0000000000..8d314878fc
--- /dev/null
+++ b/tests/expectations/accessors.rs
@@ -0,0 +1,194 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_SomeAccessors {
+ pub mNoAccessor: ::std::os::raw::c_int,
+ /**
*/
+ pub mBothAccessors: ::std::os::raw::c_int,
+ /**
*/
+ pub mUnsafeAccessors: ::std::os::raw::c_int,
+ /**
*/
+ pub mImmutableAccessor: ::std::os::raw::c_int,
+}
+impl Struct_SomeAccessors {
+ #[inline]
+ pub fn get_mBothAccessors(&self) -> &::std::os::raw::c_int {
+ &self.mBothAccessors
+ }
+ pub fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int {
+ &mut self.mBothAccessors
+ }
+ #[inline]
+ pub unsafe fn get_mUnsafeAccessors(&self) -> &::std::os::raw::c_int {
+ &self.mUnsafeAccessors
+ }
+ pub unsafe fn get_mUnsafeAccessors_mut(&mut self)
+ -> &mut ::std::os::raw::c_int {
+ &mut self.mUnsafeAccessors
+ }
+ #[inline]
+ pub fn get_mImmutableAccessor(&self) -> &::std::os::raw::c_int {
+ &self.mImmutableAccessor
+ }
+}
+impl ::std::clone::Clone for Struct_SomeAccessors {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_SomeAccessors() {
+ assert_eq!(::std::mem::size_of::
() , 16usize);
+ assert_eq!(::std::mem::align_of::() , 4usize);
+}
+/** */
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_AllAccessors {
+ pub mBothAccessors: ::std::os::raw::c_int,
+ pub mAlsoBothAccessors: ::std::os::raw::c_int,
+}
+impl Struct_AllAccessors {
+ #[inline]
+ pub fn get_mBothAccessors(&self) -> &::std::os::raw::c_int {
+ &self.mBothAccessors
+ }
+ pub fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int {
+ &mut self.mBothAccessors
+ }
+ #[inline]
+ pub fn get_mAlsoBothAccessors(&self) -> &::std::os::raw::c_int {
+ &self.mAlsoBothAccessors
+ }
+ pub fn get_mAlsoBothAccessors_mut(&mut self)
+ -> &mut ::std::os::raw::c_int {
+ &mut self.mAlsoBothAccessors
+ }
+}
+impl ::std::clone::Clone for Struct_AllAccessors {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_AllAccessors() {
+ assert_eq!(::std::mem::size_of::() , 8usize);
+ assert_eq!(::std::mem::align_of::() , 4usize);
+}
+/** */
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_AllUnsafeAccessors {
+ pub mBothAccessors: ::std::os::raw::c_int,
+ pub mAlsoBothAccessors: ::std::os::raw::c_int,
+}
+impl Struct_AllUnsafeAccessors {
+ #[inline]
+ pub unsafe fn get_mBothAccessors(&self) -> &::std::os::raw::c_int {
+ &self.mBothAccessors
+ }
+ pub unsafe fn get_mBothAccessors_mut(&mut self)
+ -> &mut ::std::os::raw::c_int {
+ &mut self.mBothAccessors
+ }
+ #[inline]
+ pub unsafe fn get_mAlsoBothAccessors(&self) -> &::std::os::raw::c_int {
+ &self.mAlsoBothAccessors
+ }
+ pub unsafe fn get_mAlsoBothAccessors_mut(&mut self)
+ -> &mut ::std::os::raw::c_int {
+ &mut self.mAlsoBothAccessors
+ }
+}
+impl ::std::clone::Clone for Struct_AllUnsafeAccessors {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_AllUnsafeAccessors() {
+ assert_eq!(::std::mem::size_of::() , 8usize);
+ assert_eq!(::std::mem::align_of::() , 4usize);
+}
+/** */
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_ContradictAccessors {
+ pub mBothAccessors: ::std::os::raw::c_int,
+ /** */
+ pub mNoAccessors: ::std::os::raw::c_int,
+ /** */
+ pub mUnsafeAccessors: ::std::os::raw::c_int,
+ /** */
+ pub mImmutableAccessor: ::std::os::raw::c_int,
+}
+impl Struct_ContradictAccessors {
+ #[inline]
+ pub fn get_mBothAccessors(&self) -> &::std::os::raw::c_int {
+ &self.mBothAccessors
+ }
+ pub fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int {
+ &mut self.mBothAccessors
+ }
+ #[inline]
+ pub unsafe fn get_mUnsafeAccessors(&self) -> &::std::os::raw::c_int {
+ &self.mUnsafeAccessors
+ }
+ pub unsafe fn get_mUnsafeAccessors_mut(&mut self)
+ -> &mut ::std::os::raw::c_int {
+ &mut self.mUnsafeAccessors
+ }
+ #[inline]
+ pub fn get_mImmutableAccessor(&self) -> &::std::os::raw::c_int {
+ &self.mImmutableAccessor
+ }
+}
+impl ::std::clone::Clone for Struct_ContradictAccessors {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_ContradictAccessors() {
+ assert_eq!(::std::mem::size_of::() , 16usize);
+ assert_eq!(::std::mem::align_of::() , 4usize);
+}
+/** */
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_Replaced {
+ pub mAccessor: ::std::os::raw::c_int,
+}
+impl Struct_Replaced {
+ #[inline]
+ pub fn get_mAccessor(&self) -> &::std::os::raw::c_int { &self.mAccessor }
+ pub fn get_mAccessor_mut(&mut self) -> &mut ::std::os::raw::c_int {
+ &mut self.mAccessor
+ }
+}
+impl ::std::clone::Clone for Struct_Replaced {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_Replaced() {
+ assert_eq!(::std::mem::size_of::() , 4usize);
+ assert_eq!(::std::mem::align_of::() , 4usize);
+}
+/** */
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_Wrapper {
+ pub mReplaced: Struct_Replaced,
+}
+impl Struct_Wrapper {
+ #[inline]
+ pub fn get_mReplaced(&self) -> &Struct_Replaced { &self.mReplaced }
+ pub fn get_mReplaced_mut(&mut self) -> &mut Struct_Replaced {
+ &mut self.mReplaced
+ }
+}
+impl ::std::clone::Clone for Struct_Wrapper {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_Wrapper() {
+ assert_eq!(::std::mem::size_of::() , 4usize);
+ assert_eq!(::std::mem::align_of::() , 4usize);
+}
diff --git a/tests/expectations/private.rs b/tests/expectations/private.rs
new file mode 100644
index 0000000000..7263e3ee0d
--- /dev/null
+++ b/tests/expectations/private.rs
@@ -0,0 +1,52 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_HasPrivate {
+ pub mNotPrivate: ::std::os::raw::c_int,
+ /** */
+ mIsPrivate: ::std::os::raw::c_int,
+}
+impl ::std::clone::Clone for Struct_HasPrivate {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_HasPrivate() {
+ assert_eq!(::std::mem::size_of::() , 8usize);
+ assert_eq!(::std::mem::align_of::() , 4usize);
+}
+/** */
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_VeryPrivate {
+ mIsPrivate: ::std::os::raw::c_int,
+ mIsAlsoPrivate: ::std::os::raw::c_int,
+}
+impl ::std::clone::Clone for Struct_VeryPrivate {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_VeryPrivate() {
+ assert_eq!(::std::mem::size_of::() , 8usize);
+ assert_eq!(::std::mem::align_of::() , 4usize);
+}
+/** */
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Struct_ContradictPrivate {
+ /** */
+ mNotPrivate: ::std::os::raw::c_int,
+ mIsPrivate: ::std::os::raw::c_int,
+}
+impl ::std::clone::Clone for Struct_ContradictPrivate {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_Struct_ContradictPrivate() {
+ assert_eq!(::std::mem::size_of::() , 8usize);
+ assert_eq!(::std::mem::align_of::() , 4usize);
+}
diff --git a/tests/headers/accessors.hpp b/tests/headers/accessors.hpp
new file mode 100644
index 0000000000..4c23e35d86
--- /dev/null
+++ b/tests/headers/accessors.hpp
@@ -0,0 +1,46 @@
+struct SomeAccessors {
+ int mNoAccessor;
+ /** */
+ int mBothAccessors;
+ /** */
+ int mUnsafeAccessors;
+ /** */
+ int mImmutableAccessor;
+};
+
+/** */
+struct AllAccessors {
+ int mBothAccessors;
+ int mAlsoBothAccessors;
+};
+
+/** */
+struct AllUnsafeAccessors {
+ int mBothAccessors;
+ int mAlsoBothAccessors;
+};
+
+/** */
+struct ContradictAccessors {
+ int mBothAccessors;
+ /** */
+ int mNoAccessors;
+ /** */
+ int mUnsafeAccessors;
+ /** */
+ int mImmutableAccessor;
+};
+
+/** */
+struct Replacing {
+ int mAccessor;
+};
+
+struct Replaced {
+ int noOp;
+};
+
+/** */
+struct Wrapper {
+ Replaced mReplaced;
+};
diff --git a/tests/headers/private.hpp b/tests/headers/private.hpp
new file mode 100644
index 0000000000..070bdddcdc
--- /dev/null
+++ b/tests/headers/private.hpp
@@ -0,0 +1,21 @@
+
+struct HasPrivate {
+ int mNotPrivate;
+ /** */
+ int mIsPrivate;
+};
+
+
+/** */
+struct VeryPrivate {
+ int mIsPrivate;
+ int mIsAlsoPrivate;
+};
+
+
+/** */
+struct ContradictPrivate {
+ /** */
+ int mNotPrivate;
+ int mIsPrivate;
+};
diff --git a/tests/tools/run-bindgen.py b/tests/tools/run-bindgen.py
index 50e96d95d9..2054924fcd 100755
--- a/tests/tools/run-bindgen.py
+++ b/tests/tools/run-bindgen.py
@@ -27,7 +27,13 @@
base_command.extend(flags);
base_command.append(sys.argv[2]);
-subprocess.check_call(base_command, cwd=os.getcwd())
+env = os.environ.copy()
+
+# El Capitan likes to unset dyld variables
+# https://forums.developer.apple.com/thread/9233
+if "DYLD_LIBRARY_PATH" not in env and "LIBCLANG_PATH" in env:
+ env["DYLD_LIBRARY_PATH"] = env["LIBCLANG_PATH"]
+subprocess.check_call(base_command, cwd=os.getcwd(), env=env)
name = None