summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md5
-rw-r--r--src/bin/bindgen.rs6
-rw-r--r--src/clang.rs4
-rw-r--r--src/gen.rs14
-rw-r--r--src/lib.rs3
-rw-r--r--src/macro.rs1
-rw-r--r--src/parser.rs55
-rw-r--r--src/types.rs6
-rw-r--r--tests/headers/struct_with_bitfields.h (renamed from tests/headers/unnamed_bitfields.h)3
-rw-r--r--tests/test_struct.rs14
10 files changed, 62 insertions, 49 deletions
diff --git a/README.md b/README.md
index 7853fbf5..9358c9fd 100644
--- a/README.md
+++ b/README.md
@@ -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)
}
}
}
diff --git a/src/gen.rs b/src/gen.rs
index 9334096e..9aeeada1 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -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));
diff --git a/src/lib.rs b/src/lib.rs
index 73b6358f..4c8ed045 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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,