diff options
-rw-r--r-- | src/gen.rs | 16 | ||||
-rw-r--r-- | tests/support.rs | 171 | ||||
-rw-r--r-- | tests/test_builtins.rs | 8 | ||||
-rw-r--r-- | tests/test_func.rs | 5 | ||||
-rw-r--r-- | tests/test_struct.rs | 66 | ||||
-rw-r--r-- | tests/test_union.rs | 27 |
6 files changed, 116 insertions, 177 deletions
@@ -556,6 +556,8 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, members: Vec<CompMember>) -> Ve vis: ast::Inherited, span: ctx.span})); } + + items.push(mk_default_impl(ctx, name.as_slice())); items.extend(extra.into_iter()); items } @@ -609,7 +611,7 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec<Com }), empty_generics() ); - let union_id = rust_type_id(ctx, name); + let union_id = rust_type_id(ctx, name.clone()); let union_attrs = vec!(mk_repr_attr(ctx), mk_deriving_copy_attr(ctx)); let union_def = mk_item(ctx, union_id, def, ast::Public, union_attrs); @@ -625,6 +627,8 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec<Com union_def, mk_item(ctx, "".to_string(), union_impl, ast::Inherited, Vec::new()) ); + + items.push(mk_default_impl(ctx, name.as_slice())); items.extend(extra.into_iter()); items } @@ -729,6 +733,16 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: uint, methods } +// Implements std::default::Default using std::mem::zeroed. +fn mk_default_impl(ctx: &GenCtx, ty_name: &str) -> P<ast::Item> { + let name_ident = ctx.ext_cx.ident_of(ty_name); + quote_item!(&ctx.ext_cx, + impl ::std::default::Default for $name_ident { + fn default() -> $name_ident { unsafe { ::std::mem::zeroed() } } + } + ).unwrap() +} + fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned<ast::StructField_> { let ty_name = match layout.align { 1 => "u8", diff --git a/tests/support.rs b/tests/support.rs index a9b6dc4d..d837786a 100644 --- a/tests/support.rs +++ b/tests/support.rs @@ -1,15 +1,15 @@ use bindgen; use bindgen::{Logger, BindgenOptions}; + use std::default::Default; -use std::fmt; -use syntax::ast; -use syntax::print::pprust; -use syntax::ptr::P; +use syntax::ast; use syntax::codemap; use syntax::codemap::{Span, DUMMY_SP}; use syntax::parse; use syntax::parse::token; +use syntax::print::pprust; +use syntax::ptr::P; struct TestLogger; @@ -33,10 +33,13 @@ pub fn generate_bindings(filename: &str) -> Result<Vec<P<ast::Item>>, ()> { pub fn test_bind_eq(filename: &str, f:|ext_cx: DummyExtCtxt| -> Vec<Option<P<ast::Item>>>) { let ext_cx = mk_dummy_ext_ctxt(); - let items = normalize_attr_ids(generate_bindings(filename).unwrap()); - let quoted = normalize_attr_ids(f(ext_cx).into_iter().map(|x| x.unwrap()).collect()); - assert_eq!(PrettyItems { items: items }, - PrettyItems { items: quoted }); + let items = generate_bindings(filename).unwrap(); + let quoted =f(ext_cx).into_iter().map(|x| x.unwrap()).collect(); + + // The ast::Items themselves have insignificant (for our purposes) + // differences that make them difficult to compare directly. So, compare + // rendered versions, which is not beautiful, but should work. + assert_eq!(render_items("ed), render_items(&items)); } macro_rules! assert_bind_eq { @@ -48,6 +51,17 @@ macro_rules! assert_bind_eq { } } +fn render_items(items: &Vec<P<ast::Item>>) -> String { + pprust::to_string(|s| { + let module = ast::Mod { + inner: DUMMY_SP, + view_items: Vec::new(), + items: items.clone(), + }; + s.print_mod(&module, &[]) + }) +} + pub struct DummyExtCtxt { sess: parse::ParseSess, } @@ -77,144 +91,3 @@ impl DummyExtCtxt { fn mk_dummy_ext_ctxt<'a>() -> DummyExtCtxt { DummyExtCtxt { sess: parse::new_parse_sess() } } - -#[deriving(PartialEq)] -struct PrettyItems { - pub items: Vec<P<ast::Item>>, -} - -impl fmt::Show for PrettyItems { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let output = pprust::to_string(|s| { - let module = ast::Mod { - inner: DUMMY_SP, - view_items: Vec::new(), - items: self.items.clone(), - }; - s.print_mod(&module, &[]) - }); - write!(f, "\n{}\n", output) - } -} - -// libsyntax uses a thread-local variable to create unique AttrId values during -// parsing and quoting. normalize_attr_ids makes sure that all AttrId values -// for the passed `items` start at zero and proceed upward. This is necessary -// to correctly compare otherwise-identical ASTs. -fn normalize_attr_ids(items: Vec<P<ast::Item>>) -> Vec<P<ast::Item>> { - use std::mem; - use syntax::visit::*; - - struct Vis<'a> { - attr_id: uint, - items: Vec<P<ast::Item>>, - } - - impl<'a> Vis<'a> { - // TODO: visit_crate? ast::visit::Visitor does not deal with them directly, - // but concievably, it could eventually come up. - - fn rewrite_attrs(&mut self, attrs: Vec<ast::Attribute>) -> Vec<ast::Attribute> { - attrs.into_iter().map(|mut attr| { - attr.node.id = ast::AttrId(self.attr_id); - self.attr_id += 1; - attr - }).collect() - } - } - - unsafe fn force_mutable<T>(x: &T) -> &mut T { - mem::transmute(x) - } - - macro_rules! rewrite_attrs { - ($self_:ident, $item:expr) => { - unsafe { - let unsafe_item = force_mutable($item); - let new_attrs = mem::replace(&mut unsafe_item.attrs, vec!()); - let new_attrs = $self_.rewrite_attrs(new_attrs); - mem::replace(&mut unsafe_item.attrs, new_attrs); - } - } - } - - impl<'a, 'v> Visitor<'v> for Vis<'a> { - fn visit_item(&mut self, i: &ast::Item) { - rewrite_attrs!(self, i); - - match i.node { - ast::ItemImpl(_, _, _, _, ref impl_items) => { - for impl_item in impl_items.iter() { - match *impl_item { - ast::ImplItem::MethodImplItem(_) => { } - ast::ImplItem::TypeImplItem(ref typedef) => { - rewrite_attrs!(self, typedef.deref()); - } - } - } - } - _ => { } - } - - walk_item(self, i); - } - - fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { - rewrite_attrs!(self, i); - walk_foreign_item(self, i); - } - - fn visit_fn(&mut self, fk: FnKind, fd: &ast::FnDecl, b: &ast::Block, s: Span, _: ast::NodeId) { - match fk { - FkItemFn(_, _, _, _) | FkFnBlock => { } - FkMethod(_, _, method) => { - rewrite_attrs!(self, method); - } - } - walk_fn(self, fk, fd, b, s); - } - - fn visit_arm(&mut self, a: &ast::Arm) { - rewrite_attrs!(self, a); - walk_arm(self, a); - } - - fn visit_ty_method(&mut self, t: &ast::TypeMethod) { - rewrite_attrs!(self, t); - walk_ty_method(self, t); - } - - fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics) { - rewrite_attrs!(self, &v.node); - walk_variant(self, v, g); - } - - fn visit_view_item(&mut self, i: &ast::ViewItem) { - rewrite_attrs!(self, i); - walk_view_item(self, i); - } - - fn visit_struct_field(&mut self, s: &ast::StructField) { - rewrite_attrs!(self, &s.node); - walk_struct_field(self, s); - } - - fn visit_trait_item(&mut self, t: &ast::TraitItem) { - match *t { - ast::TraitItem::RequiredMethod(_) | - ast::TraitItem::ProvidedMethod(_) => { } - ast::TraitItem::TypeTraitItem(ref assoc_ty) => { - rewrite_attrs!(self, assoc_ty.deref()); - } - } - walk_trait_item(self, t); - } - } - - let mut visitor = Vis { attr_id: 0, items: vec!() }; - for item in items.into_iter() { - visitor.visit_item(item.deref()); - visitor.items.push(item); - } - visitor.items -} diff --git a/tests/test_builtins.rs b/tests/test_builtins.rs index 35cd573c..1df562c8 100644 --- a/tests/test_builtins.rs +++ b/tests/test_builtins.rs @@ -1,12 +1,6 @@ -#![feature(phase)] - -#[phase(plugin)] -extern crate bindgen; - -extern crate libc; - #[test] fn test_builtin_va_list() { + #[allow(dead_code, non_camel_case_types, raw_pointer_deriving)] mod ffi { bindgen!("headers/builtin_va_list.h", emit_builtins = true); } // Should test for more than compilation. } diff --git a/tests/test_func.rs b/tests/test_func.rs index 83bc2696..8a0f2584 100644 --- a/tests/test_func.rs +++ b/tests/test_func.rs @@ -22,6 +22,11 @@ fn func_ptr_in_struct() { extern "C" fn(x: ::libc::c_int, y: ::libc::c_int) -> Enum_baz>, } + ), + quote_item!(cx, + impl ::std::default::Default for Struct_Foo { + fn default() -> Struct_Foo { unsafe { ::std::mem::zeroed() } } + } ) ); } diff --git a/tests/test_struct.rs b/tests/test_struct.rs index 2d30174c..c6f6836f 100644 --- a/tests/test_struct.rs +++ b/tests/test_struct.rs @@ -1,7 +1,9 @@ +use std::default::Default; + #[test] fn with_anon_struct() { mod ffi { bindgen!("headers/struct_with_anon_struct.h"); } - let mut x = ffi::Struct_foo { bar: ffi::Struct_Unnamed1 { a: 0, b: 0 } }; + let mut x: ffi::Struct_foo = Default::default(); x.bar.a = 1; x.bar.b = 2; @@ -13,10 +15,7 @@ fn with_anon_struct() { #[test] fn with_anon_struct_array() { mod ffi { bindgen!("headers/struct_with_anon_struct_array.h"); } - let mut x = ffi::Struct_foo { bar: [ - ffi::Struct_Unnamed1 { a: 0, b: 0 }, - ffi::Struct_Unnamed1 { a: 1, b: 1 } ] - }; + let mut x: ffi::Struct_foo = Default::default(); x.bar[1].a = 1; x.bar[1].b = 2; @@ -27,11 +26,13 @@ fn with_anon_struct_array() { #[test] fn with_anon_struct_pointer() { + #[allow(raw_pointer_deriving)] mod ffi { bindgen!("headers/struct_with_anon_struct_pointer.h"); } - let mut unnamed = box ffi::Struct_Unnamed1 { a: 0, b: 0 }; + let mut x: ffi::Struct_foo = Default::default(); + let mut unnamed: ffi::Struct_Unnamed1 = Default::default(); unsafe { - let mut x = ffi::Struct_foo { bar: ::std::mem::transmute(unnamed) }; + x.bar = &mut unnamed; (*x.bar).a = 1; (*x.bar).b = 2; @@ -46,7 +47,7 @@ fn with_anon_struct_pointer() { #[test] fn with_anon_union() { mod ffi { bindgen!("headers/struct_with_anon_union.h"); } - let mut x = ffi::Struct_foo { bar: ffi::Union_Unnamed1 { _bindgen_data_: [0] } }; + let mut x: ffi::Struct_foo = Default::default(); unsafe { *x.bar.a() = 0x12345678; @@ -58,7 +59,7 @@ fn with_anon_union() { #[test] fn with_anon_unnamed_struct() { mod ffi { bindgen!("headers/struct_with_anon_unnamed_struct.h"); } - let mut x = ffi::Struct_foo { _bindgen_data_1_: [0, 0] }; + let mut x: ffi::Struct_foo = Default::default(); unsafe { *x.a() = 0x12345678; @@ -71,7 +72,7 @@ fn with_anon_unnamed_struct() { #[test] fn with_anon_unnamed_union() { mod ffi { bindgen!("headers/struct_with_anon_unnamed_union.h"); } - let mut x = ffi::Struct_foo { _bindgen_data_1_: [0] }; + let mut x: ffi::Struct_foo = Default::default(); unsafe { *x.a() = 0x12345678; @@ -83,7 +84,7 @@ fn with_anon_unnamed_union() { #[test] fn with_nesting() { mod ffi { bindgen!("headers/struct_with_nesting.h"); } - let mut x = ffi::Struct_foo { a: 0, _bindgen_data_1_: [0] }; + let mut x: ffi::Struct_foo = Default::default(); unsafe { x.a = 0x12345678; @@ -111,12 +112,23 @@ fn containing_fwd_decl_struct() { } ), quote_item!(cx, + impl ::std::default::Default for Struct_a { + fn default() -> Struct_a { unsafe { ::std::mem::zeroed() } } + } + ), + quote_item!(cx, #[repr(C)] #[deriving(Copy)] pub struct Struct_b { pub val_b: ::libc::c_int, } - )); + ), + quote_item!(cx, + impl ::std::default::Default for Struct_b { + fn default() -> Struct_b { unsafe { ::std::mem::zeroed() } } + } + ) + ); } #[test] @@ -133,7 +145,13 @@ fn with_unnamed_bitfields() { pub unnamed_field2: ::libc::c_ushort, pub d: ::libc::c_ushort, } - )); + ), + quote_item!(cx, + impl ::std::default::Default for Struct_bitfield { + fn default() -> Struct_bitfield { unsafe { ::std::mem::zeroed() } } + } + ) + ); } #[test] @@ -143,6 +161,24 @@ fn with_fwd_decl_struct() { let a = ffi::Struct_a { b: 1 }; let c = ffi::Struct_c { d: 1 }; - a.b; - c.d; + assert_eq!(a.b, 1); + assert_eq!(c.d, 1); +} + +#[test] +fn default_impl() { + mod ffi { bindgen!("headers/struct_with_nesting.h"); } + + let mut x: ffi::Struct_foo = Default::default(); + + unsafe { + assert_eq!(x.a, 0); + assert_eq!(*x.b(), 0); + assert_eq!(*x.c1(), 0); + assert_eq!(*x.c2(), 0); + assert_eq!(*x.d1(), 0); + assert_eq!(*x.d2(), 0); + assert_eq!(*x.d3(), 0); + assert_eq!(*x.d4(), 0); + } } diff --git a/tests/test_union.rs b/tests/test_union.rs index 33a3713d..15759e7f 100644 --- a/tests/test_union.rs +++ b/tests/test_union.rs @@ -1,9 +1,11 @@ +use std::default::Default; + #[test] fn with_anon_struct() { // XXX: Rustc thinks that the anonymous struct, bar, is unused. #[allow(dead_code)] mod ffi { bindgen!("headers/union_with_anon_struct.h"); } - let mut x = ffi::Union_foo { _bindgen_data_: [0, 0] }; + let mut x: ffi::Union_foo = Default::default(); unsafe { (*x.bar()).a = 0x12345678; @@ -17,7 +19,7 @@ fn with_anon_struct() { #[test] fn with_anon_union() { mod ffi { bindgen!("headers/union_with_anon_union.h"); } - let mut x = ffi::Union_foo { _bindgen_data_: [0] }; + let mut x: ffi::Union_foo = Default::default(); unsafe { *(*x.bar()).a() = 0x12345678; @@ -30,7 +32,7 @@ fn with_anon_union() { #[test] fn with_anon_unnamed_struct() { mod ffi { bindgen!("headers/union_with_anon_unnamed_struct.h"); } - let mut x = ffi::Union_pixel { _bindgen_data_: [0] }; + let mut x: ffi::Union_pixel = Default::default(); unsafe { *x.r() = 0xca; @@ -49,7 +51,7 @@ fn with_anon_unnamed_struct() { #[test] fn with_anon_unnamed_union() { mod ffi { bindgen!("headers/union_with_anon_unnamed_union.h"); } - let mut x = ffi::Union_foo { _bindgen_data_: [0] }; + let mut x: ffi::Union_foo = Default::default(); unsafe { *x.a() = 0x12345678; @@ -63,7 +65,7 @@ fn with_anon_unnamed_union() { #[test] fn with_nesting() { mod ffi { bindgen!("headers/union_with_nesting.h"); } - let mut x = ffi::Union_foo { _bindgen_data_: [0] }; + let mut x: ffi::Union_foo = Default::default(); unsafe { *x.a() = 0x12345678; @@ -75,3 +77,18 @@ fn with_nesting() { assert_eq!(*x.c2(), 0x1234); } } + +#[test] +fn default_impl() { + mod ffi { bindgen!("headers/Union_with_nesting.h"); } + + let mut x: ffi::Union_foo = Default::default(); + + unsafe { + assert_eq!(*x.a(), 0); + assert_eq!(*x.b1(), 0); + assert_eq!(*x.b2(), 0); + assert_eq!(*x.c1(), 0); + assert_eq!(*x.c2(), 0); + } +} |