From bee31178e0e06699e0114b924b5c45e23a4c1ff4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Jul 2016 17:59:21 +0530 Subject: [PATCH 1/3] Make it possible to run tests on El Capitan --- Makefile | 2 +- tests/tools/run-bindgen.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) 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/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 From 7ab0e2cda43339dbafec8026561b5207f40a9f16 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 26 Jul 2016 15:03:28 +0530 Subject: [PATCH 2/3] Output diff from travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) 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: From 0fcf367becd11e1de017e832ff81262c1c5f6f6e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 20 Jul 2016 20:23:27 +0530 Subject: [PATCH 3/3] Add support for 'unsafe fields' --- src/gen.rs | 67 ++++++++++- src/parser.rs | 39 ++++++- src/types.rs | 17 ++- tests/expectations/accessors.rs | 194 ++++++++++++++++++++++++++++++++ tests/expectations/private.rs | 52 +++++++++ tests/headers/accessors.hpp | 46 ++++++++ tests/headers/private.hpp | 21 ++++ 7 files changed, 426 insertions(+), 10 deletions(-) create mode 100644 tests/expectations/accessors.rs create mode 100644 tests/expectations/private.rs create mode 100644 tests/headers/accessors.hpp create mode 100644 tests/headers/private.hpp 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; +};