diff options
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | src/bin/bindgen.rs | 6 | ||||
-rw-r--r-- | src/clang.rs | 4 | ||||
-rw-r--r-- | src/gen.rs | 14 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/macro.rs | 1 | ||||
-rw-r--r-- | src/parser.rs | 55 | ||||
-rw-r--r-- | src/types.rs | 6 | ||||
-rw-r--r-- | tests/headers/struct_with_bitfields.h (renamed from tests/headers/unnamed_bitfields.h) | 3 | ||||
-rw-r--r-- | tests/test_struct.rs | 14 |
10 files changed, 62 insertions, 49 deletions
@@ -45,8 +45,6 @@ Options: matching any rule are bound to -builtins Output bindings for builtin definitions (for example __builtin_va_list) - -allow-bitfields Don't fail if we encounter a bitfield - (note that bindgen does not support bitfields) -allow-unknown-types Don't fail if we encounter types we do not support, instead treat them as void -emit-clang-ast Output the ast (for debugging purposes) @@ -79,7 +77,6 @@ Options: link_framework multiple strings match multiple strings emit_builtins bool true - allow_bitfields bool false allow_unknown_types bool false clang_args string ``` @@ -117,7 +114,7 @@ main.rs TODO ---- -* bit field +* bitfield accessors [clay's bindgen]: https://github.com/jckarter/clay/blob/master/tools/bindgen.clay [issue 89]: https://github.com/crabtw/rust-bindgen/issues/89 diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs index 01ed456c..6390ceb6 100644 --- a/src/bin/bindgen.rs +++ b/src/bin/bindgen.rs @@ -96,10 +96,6 @@ fn parse_args(args: &[String]) -> ParseResult { options.builtins = true; ix += 1u; } - "-allow-bitfields" => { - options.fail_on_bitfield = false; - ix += 1u; - } "-allow-unknown-types" => { options.fail_on_unknown_type = false; ix += 1u; @@ -139,8 +135,6 @@ Options: matching any rule are bound to. -builtins Output bindings for builtin definitions (for example __builtin_va_list) - -allow-bitfields Don't fail if we encounter a bitfield - (note that bindgen does not support bitfields) -allow-unknown-types Don't fail if we encounter types we do not support, instead treat them as void -emit-clang-ast Output the ast (for debugging purposes) diff --git a/src/clang.rs b/src/clang.rs index e5d7696c..8d1b58bf 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -65,13 +65,13 @@ impl Cursor { } // bitfield - pub fn bit_width(&self) -> Option<uint> { + pub fn bit_width(&self) -> Option<u32> { unsafe { let w = clang_getFieldDeclBitWidth(self.x); if w == -1 { None } else { - Some(w as uint) + Some(w as u32) } } } @@ -475,6 +475,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, members: Vec<CompMember>) -> Ve // after the current struct. let mut extra = vec!(); let mut unnamed: u32 = 0; + let mut bitfields: u32 = 0; for m in members.iter() { let (opt_rc_c, opt_f) = match m { @@ -484,13 +485,12 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, members: Vec<CompMember>) -> Ve }; if let Some(f) = opt_f { - // Needed so bitfields with unnamed members still parse - // They're still wrong though - let f_name = if f.name.is_empty() || "_" == f.name.as_slice() { - unnamed += 1; - format!("unnamed_field{}", unnamed) - } else { - rust_type_id(ctx, f.name.clone()) + let f_name = match f.bitfields { + Some(_) => { + bitfields += 1; + format!("_bindgen_bitfield_{}_", bitfields) + } + None => rust_type_id(ctx, f.name.clone()) }; let f_ty = P(cty_to_rs(ctx, &f.ty)); @@ -39,7 +39,6 @@ pub struct BindgenOptions { pub builtins: bool, pub links: Vec<(String, LinkType)>, pub emit_ast: bool, - pub fail_on_bitfield: bool, pub fail_on_unknown_type: bool, pub override_enum_ty: String, pub clang_args: Vec<String>, @@ -52,7 +51,6 @@ impl Default for BindgenOptions { builtins: false, links: Vec::new(), emit_ast: false, - fail_on_bitfield: false, fail_on_unknown_type: false, override_enum_ty: "".to_string(), clang_args: Vec::new() @@ -161,7 +159,6 @@ fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global builtins: options.builtins, match_pat: options.match_pat.clone(), emit_ast: options.emit_ast, - fail_on_bitfield: options.fail_on_bitfield, fail_on_unknown_type: options.fail_on_unknown_type, override_enum_ty: str_to_ikind(options.override_enum_ty.as_slice()), clang_args: options.clang_args.clone(), diff --git a/src/macro.rs b/src/macro.rs index a8fc6190..0a2425c2 100644 --- a/src/macro.rs +++ b/src/macro.rs @@ -96,7 +96,6 @@ impl MacroArgsVisitor for BindgenArgsVisitor { fn visit_bool(&mut self, name: Option<&str>, val: bool) -> bool { if name.is_some() { self.seen_named = true; } match name { - Some("allow_bitfields") => self.options.fail_on_bitfield = !val, Some("allow_unknown_types") => self.options.fail_on_unknown_type = !val, Some("emit_builtins") => self.options.builtins = val, _ => return false diff --git a/src/parser.rs b/src/parser.rs index 2622a944..428c91dc 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -4,6 +4,7 @@ use std::collections::{HashMap, HashSet}; use std::collections::hash_map; use std::cell::RefCell; +use std::iter::AdditiveIterator; use std::rc::Rc; use syntax::abi; @@ -21,7 +22,6 @@ pub struct ClangParserOptions { pub builtins: bool, pub match_pat: Vec<String>, pub emit_ast: bool, - pub fail_on_bitfield: bool, pub fail_on_unknown_type: bool, pub override_enum_ty: Option<il::IKind>, pub clang_args: Vec<String>, @@ -314,22 +314,47 @@ fn opaque_ty(ctx: &mut ClangParserCtx, ty: &cx::Type) { fn visit_composite(cursor: &Cursor, parent: &Cursor, ctx: &mut ClangParserCtx, members: &mut Vec<CompMember>) -> Enum_CXVisitorResult { + + fn is_bitfield_continuation(field: &il::FieldInfo, ty: &il::Type, width: u32) -> bool { + match (&field.bitfields, ty) { + (&Some(ref bitfields), &il::TInt(_, layout)) if *ty == field.ty => { + bitfields.iter().map(|&(_, w)| w).sum() + width <= (layout.size * 8) as u32 + }, + _ => false + } + } + match cursor.kind() { CXCursor_FieldDecl => { let ty = conv_ty(ctx, &cursor.cur_type(), cursor); - let name = cursor.spelling(); - let bit = cursor.bit_width(); - // If we encounter a bitfield, and fail_on_bitfield is set, throw an - // error and exit entirely. - if bit != None { - let fail = ctx.options.fail_on_bitfield; - log_err_warn(ctx, - format!("unsupported bitfield `{}` in `{}` ({})", - name, parent.spelling(), cursor.location() - ).as_slice(), - fail - ); - } + + let (name, bitfields) = match (cursor.bit_width(), members.last_mut()) { + // The field is a continuation of an exising bitfield + (Some(width), Some(&il::CompMember::Field(ref mut field))) + if is_bitfield_continuation(field, &ty, width) => { + + if let Some(ref mut bitfields) = field.bitfields { + bitfields.push((cursor.spelling(), width)); + } else { unreachable!() } + return CXChildVisit_Continue; + }, + // The field is the start of a new bitfield + (Some(width), _) => { + // Bitfields containing enums are not supported by the c standard + // https://stackoverflow.com/questions/11983231/is-it-safe-to-use-an-enum-in-a-bit-field + match &ty { + &il::TInt(_, _) => (), + _ => { + let msg = format!("Enums in bitfields are not supported ({}.{}).", + cursor.spelling(), parent.spelling()); + ctx.logger.warn(msg.as_slice()); + } + } + ("".to_string(), Some(vec!((cursor.spelling(), width)))) + }, + // The field is not a bitfield + (None, _) => (cursor.spelling(), None) + }; // The Clang C api does not fully expose composite fields, but it // does expose them in a way that can be detected. When the current @@ -372,7 +397,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, _ => false }; - let field = FieldInfo::new(name, ty.clone(), bit); + let field = FieldInfo::new(name, ty.clone(), bitfields); if is_composite { if let Some(CompMember::Comp(c)) = members.pop() { members.push(CompMember::CompField(c, field)); diff --git a/src/types.rs b/src/types.rs index fbd108b2..c80333d9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -203,15 +203,15 @@ impl fmt::Show for CompInfo { pub struct FieldInfo { pub name: String, pub ty: Type, - pub bit: Option<uint>, + pub bitfields: Option<Vec<(String, u32)>>, } impl FieldInfo { - pub fn new(name: String, ty: Type, bit: Option<uint>) -> FieldInfo { + pub fn new(name: String, ty: Type, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo { FieldInfo { name: name, ty: ty, - bit: bit, + bitfields: bitfields, } } } diff --git a/tests/headers/unnamed_bitfields.h b/tests/headers/struct_with_bitfields.h index 229bd728..ece512cd 100644 --- a/tests/headers/unnamed_bitfields.h +++ b/tests/headers/struct_with_bitfields.h @@ -6,4 +6,7 @@ struct bitfield { :1, :2, d :2; + int e; + unsigned int f : 2; + unsigned int g : 32; }; diff --git a/tests/test_struct.rs b/tests/test_struct.rs index c6f6836f..d9d8f930 100644 --- a/tests/test_struct.rs +++ b/tests/test_struct.rs @@ -132,18 +132,16 @@ fn containing_fwd_decl_struct() { } #[test] -fn with_unnamed_bitfields() { - assert_bind_eq!("headers/unnamed_bitfields.h", cx, +fn with_bitfields() { + assert_bind_eq!("headers/struct_with_bitfields.h", cx, quote_item!(cx, #[repr(C)] #[deriving(Copy)] pub struct Struct_bitfield { - pub a: ::libc::c_ushort, - pub b: ::libc::c_ushort, - pub c: ::libc::c_ushort, - pub unnamed_field1: ::libc::c_ushort, - pub unnamed_field2: ::libc::c_ushort, - pub d: ::libc::c_ushort, + pub _bindgen_bitfield_1_: ::libc::c_ushort, + pub e: ::libc::c_int, + pub _bindgen_bitfield_2_: ::libc::c_uint, + pub _bindgen_bitfield_3_: ::libc::c_uint, } ), quote_item!(cx, |