Skip to content

Fix for anonymous structs #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/bin/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ struct StdLogger;

impl Logger for StdLogger {
fn error(&self, msg: &str) {
error!("{}", msg);
println!("{}", msg);
}

fn warn(&self, msg: &str) {
warn!("{}", msg);
println!("{}", msg);
}
}

Expand Down Expand Up @@ -99,6 +99,10 @@ fn parse_args(args: &[String]) -> ParseResult {
options.builtins = true;
ix += 1;
}
"-ignore-functions" => {
options.ignore_functions = true;
ix += 1;
}
"-allow-unknown-types" => {
options.fail_on_unknown_type = false;
ix += 1;
Expand Down Expand Up @@ -138,6 +142,8 @@ Options:
matching any rule are bound to.
-builtins Output bindings for builtin definitions
(for example __builtin_va_list)
-ignore-functions Don't generate bindings for functions and methods.
This is useful when you only care about struct layouts.
-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)
Expand Down
108 changes: 39 additions & 69 deletions src/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use types::*;

struct GenCtx<'r> {
ext_cx: base::ExtCtxt<'r>,
unnamed_ty: usize,
span: Span
}

Expand Down Expand Up @@ -76,32 +75,11 @@ fn rust_type_id(ctx: &mut GenCtx, name: String) -> String {
s.push_str(&name);
s
} else {
match name.as_str() {
"int8_t" => "i8".to_string(),
"uint8_t" => "u8".to_string(),
"int16_t" => "i16".to_string(),
"uint16_t" => "u16".to_string(),
"int32_t" => "i32".to_string(),
"uint32_t" => "u32".to_string(),
"int64_t" => "i64".to_string(),
"uint64_t" => "u64".to_string(),
_ => {
let (n, _) = rust_id(ctx, name);
n
}
}
let (n, _) = rust_id(ctx, name);
n
}
}

fn unnamed_name(ctx: &mut GenCtx, name: String, filename: String) -> String {
return if name.is_empty() {
ctx.unnamed_ty += 1;
format!("{}_unnamed_{}", filename, ctx.unnamed_ty)
} else {
name
};
}

fn comp_name(kind: CompKind, name: &String) -> String {
match kind {
CompKind::Struct => struct_name(name),
Expand Down Expand Up @@ -262,7 +240,6 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec<Global>, span: Span) ->
let mut feature_gated_cfgs = vec![];
let mut ctx = GenCtx {
ext_cx: base::ExtCtxt::new(sess, Vec::new(), cfg, &mut feature_gated_cfgs),
unnamed_ty: 0,
span: span
};
ctx.ext_cx.bt_push(ExpnInfo {
Expand Down Expand Up @@ -312,35 +289,19 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec<Global>, span: Span) ->
defs.extend(ctypedef_to_rs(&mut ctx, t.name.clone(), t.comment.clone(), &t.ty).into_iter())
},
GCompDecl(ci) => {
{
let mut c = ci.borrow_mut();
c.name = unnamed_name(&mut ctx, c.name.clone(), c.filename.clone());
}
let c = ci.borrow().clone();
defs.push(opaque_to_rs(&mut ctx, comp_name(c.kind, &c.name)));
},
GComp(ci) => {
{
let mut c = ci.borrow_mut();
c.name = unnamed_name(&mut ctx, c.name.clone(), c.filename.clone());
}
let c = ci.borrow().clone();
defs.extend(comp_to_rs(&mut ctx, comp_name(c.kind, &c.name),
c).into_iter())
},
GEnumDecl(ei) => {
{
let mut e = ei.borrow_mut();
e.name = unnamed_name(&mut ctx, e.name.clone(), e.filename.clone());
}
let e = ei.borrow().clone();
defs.push(opaque_to_rs(&mut ctx, enum_name(&e.name)));
},
GEnum(ei) => {
{
let mut e = ei.borrow_mut();
e.name = unnamed_name(&mut ctx, e.name.clone(), e.filename.clone());
}
let e = ei.borrow().clone();
defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.comment, e.items, e.layout).into_iter())
},
Expand Down Expand Up @@ -671,24 +632,12 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, comment: String, ty: &Type) ->

return match *ty {
TComp(ref ci) => {
let is_empty = ci.borrow().name.is_empty();
if is_empty {
ci.borrow_mut().name = name.clone();
let c = ci.borrow().clone();
comp_to_rs(ctx, name, c)
} else {
vec!(mk_item(ctx, name, comment, ty))
}
assert!(!ci.borrow().name.is_empty());
vec!(mk_item(ctx, name, comment, ty))
},
TEnum(ref ei) => {
let is_empty = ei.borrow().name.is_empty();
if is_empty {
ei.borrow_mut().name = name.clone();
let e = ei.borrow().clone();
cenum_to_rs(ctx, name, e.comment, e.items, e.layout)
} else {
vec!(mk_item(ctx, name, comment, ty))
}
assert!(!ei.borrow().name.is_empty());
vec!(mk_item(ctx, name, comment, ty))
},
_ => vec!(mk_item(ctx, name, comment, ty))
}
Expand Down Expand Up @@ -810,7 +759,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec<P<ast::Ite
ast::Public,
),
id: ast::DUMMY_NODE_ID,
ty: quote_ty!(&ctx.ext_cx, PhantomData<$inner_type>),
ty: quote_ty!(&ctx.ext_cx, ::std::marker::PhantomData<$inner_type>),
attrs: vec!(),
}));
}
Expand Down Expand Up @@ -1132,10 +1081,18 @@ fn cenum_to_rs(ctx: &mut GenCtx, name: String, comment: String, items: Vec<EnumI
}

let variants = items.iter().map(|it| {
let value_sign = ast::UnsuffixedIntLit(if it.val < 0 { ast::Minus } else { ast::Plus });
let value_node =
ast::ExprLit(P(respan(ctx.span, ast::LitInt(it.val.abs() as u64,
value_sign))));
// FIXME(bholley): The overall handling of enum signs is kinda sloppy - we
// store them as an i64 even if the enum type is unsigned, which means that
// we end up generating literals the high bit of the bitfield is set. This
// works out to the same bitfield with two's complement, but we can't negate
// i64::min_value(), so we need to handle it separately.
let value_node = if it.val == i64::min_value() {
let value_sign = ast::UnsuffixedIntLit(ast::Plus);
ast::ExprLit(P(respan(ctx.span, ast::LitInt(it.val as u64, value_sign ))))
} else {
let value_sign = ast::UnsuffixedIntLit(if it.val < 0 { ast::Minus } else { ast::Plus });
ast::ExprLit(P(respan(ctx.span, ast::LitInt(it.val.abs() as u64, value_sign))))
};

let variant = respan(ctx.span, ast::Variant_ {
name: ctx.ext_cx.ident_of(&it.name),
Expand Down Expand Up @@ -1289,17 +1246,25 @@ fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
}

fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
field_type: &Type, bitfields: &Vec<(String, u32)>) -> ast::ImplItem {
field_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem {
let field_type = cty_to_rs(ctx, field_type, false);
let mut args = vec!();
let mut unnamed: usize = 0;
for &(ref name, width) in bitfields.iter() {
let ident = if name.is_empty() {
unnamed += 1;
let dummy = format!("unnamed_bitfield{}", unnamed);
ctx.ext_cx.ident_of(&dummy)
} else {
ctx.ext_cx.ident_of(name)
};
args.push(ast::Arg {
ty: P(type_for_bitfield_width(ctx, width)),
pat: P(ast::Pat {
id: ast::DUMMY_NODE_ID,
node: ast::PatIdent(
ast::BindingMode::ByValue(ast::MutImmutable),
respan(ctx.span, ctx.ext_cx.ident_of(name)),
respan(ctx.span, ident),
None
),
span: ctx.span
Expand All @@ -1318,8 +1283,15 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,

let mut offset = 0;
let mut exprs = quote_expr!(&ctx.ext_cx, 0);
let mut unnamed: usize = 0;
for &(ref name, width) in bitfields.iter() {
let name_ident = ctx.ext_cx.ident_of(&name);
let name_ident = if name.is_empty() {
unnamed += 1;
let dummy = format!("unnamed_bitfield{}", unnamed);
ctx.ext_cx.ident_of(&dummy)
} else {
ctx.ext_cx.ident_of(name)
};
exprs = quote_expr!(&ctx.ext_cx,
$exprs | (($name_ident as $field_type) << $offset)
);
Expand Down Expand Up @@ -1618,16 +1590,14 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty {
mk_ty(ctx, false, vec!(id))
},
&TComp(ref ci) => {
let mut c = ci.borrow_mut();
c.name = unnamed_name(ctx, c.name.clone(), c.filename.clone());
let mut c = ci.borrow();
let args = c.args.iter().map(|gt| {
P(cty_to_rs(ctx, gt, allow_bool))
}).collect();
mk_ty_args(ctx, false, vec!(comp_name(c.kind, &c.name)), args)
},
&TEnum(ref ei) => {
let mut e = ei.borrow_mut();
e.name = unnamed_name(ctx, e.name.clone(), e.filename.clone());
let mut e = ei.borrow();
mk_ty(ctx, false, vec!(enum_name(&e.name)))
}
};
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub struct BindgenOptions {
pub builtins: bool,
pub links: Vec<(String, LinkType)>,
pub emit_ast: bool,
pub ignore_functions: bool,
pub fail_on_unknown_type: bool,
pub override_enum_ty: String,
pub clang_args: Vec<String>,
Expand All @@ -116,6 +117,7 @@ impl Default for BindgenOptions {
builtins: false,
links: Vec::new(),
emit_ast: false,
ignore_functions: false,
fail_on_unknown_type: true,
override_enum_ty: "".to_string(),
clang_args: Vec::new()
Expand Down Expand Up @@ -224,6 +226,7 @@ fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global
builtins: options.builtins,
match_pat: options.match_pat.clone(),
emit_ast: options.emit_ast,
ignore_functions: options.ignore_functions,
fail_on_unknown_type: options.fail_on_unknown_type,
override_enum_ty: str_to_ikind(&options.override_enum_ty),
clang_args: options.clang_args.clone(),
Expand Down
5 changes: 5 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct ClangParserOptions {
pub match_pat: Vec<String>,
pub emit_ast: bool,
pub fail_on_unknown_type: bool,
pub ignore_functions: bool,
pub override_enum_ty: Option<il::IKind>,
pub clang_args: Vec<String>,
}
Expand Down Expand Up @@ -590,6 +591,10 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
ci.base_members += 1;
}
CXCursor_CXXMethod => {
if ctx.options.ignore_functions {
return CXChildVisit_Continue;
}

let linkage = cursor.linkage();
if linkage != CXLinkage_External {
return CXChildVisit_Continue;
Expand Down
15 changes: 13 additions & 2 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,22 @@ pub struct CompInfo {
pub layout: Layout,
}

static mut UNNAMED_COUNTER: u32 = 0;

fn unnamed_name(name: String, filename: &String) -> String {
return if name.is_empty() {
let n = unsafe { UNNAMED_COUNTER += 1; UNNAMED_COUNTER };
format!("{}_unnamed_{}", filename, n)
} else {
name
};
}

impl CompInfo {
pub fn new(name: String, filename: String, comment: String, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo {
CompInfo {
kind: kind,
name: name,
name: unnamed_name(name, &filename),
filename: filename,
comment: comment,
members: members,
Expand Down Expand Up @@ -253,7 +264,7 @@ pub struct EnumInfo {
impl EnumInfo {
pub fn new(name: String, filename: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
EnumInfo {
name: name,
name: unnamed_name(name, &filename),
comment: String::new(),
filename: filename,
items: items,
Expand Down
4 changes: 2 additions & 2 deletions tests/support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub fn assert_bind_eq(filename: &str, reference_items_str: &str)

let mut parser = parse::new_parser_from_source_str(ext_cx.parse_sess(), ext_cx.cfg(), "".to_string(), reference_items_str.to_string());
let mut reference_items = Vec::new();
while let Some(item) = parser.parse_item() {
while let Ok(Some(item)) = parser.parse_item() {
reference_items.push(item);
}

Expand All @@ -47,7 +47,7 @@ pub fn assert_bind_eq(filename: &str, reference_items_str: &str)
// rendered versions, which is not beautiful, but should work.
let reference_rendered = render_items(&reference_items);
let generated_rendered = render_items(&generated_items);

if reference_rendered != generated_rendered {
println!("Generated bindings for {} do not match the reference bindings.", filename);
println!("");
Expand Down