diff --git a/libc-test/build.rs b/libc-test/build.rs index bcdb412c..dda79a4b 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -109,13 +109,11 @@ fn build_cfg(cfg: &mut ast::CrateConfig, target: &str) { impl<'a> TestGenerator<'a> { fn test_type(&mut self, ty: &str) { let cty = if ty.starts_with("c_") { - let rest = ty[2..].replace("long", " long"); - if rest.starts_with("u") { - format!("unsigned {}", &rest[1..]) - } else if rest.starts_with("s") && rest != "short" { - format!("signed {}", &rest[1..]) - } else { - rest + match &ty[2..].replace("long", " long")[..] { + s if s.starts_with("u") => format!("unsigned {}", &s[1..]), + "short" => format!("short"), + s if s.starts_with("s") => format!("signed {}", &s[1..]), + s => s.to_string(), } } else { (match ty { @@ -126,15 +124,61 @@ impl<'a> TestGenerator<'a> { self.test_size_align(ty, &cty); } - fn test_struct(&mut self, ty: &str, _s: &ast::StructDef) { - let cty = if ty.starts_with("pthread") || ty == "glob_t" { - ty.to_string() - } else if ty == "ip6_mreq" { - "struct ipv6_mreq".to_string() - } else { - format!("struct {}", ty) + fn test_struct(&mut self, ty: &str, s: &ast::StructDef) { + let cty = match ty { + t if ty.starts_with("pthread") => t.to_string(), + "glob_t" => "glob_t".to_string(), + "ip6_mreq" => "struct ipv6_mreq".to_string(), + s => format!("struct {}", s), }; self.test_size_align(ty, &cty); + + writeln!(self.rust, r#" + #[test] + fn field_offset_size_{ty}() {{ + "#, ty = ty); + for field in s.fields.iter() { + let name = match field.node.kind { + ast::NamedField(name, ast::Public) => name, + ast::NamedField(_, ast::Inherited) => continue, + ast::UnnamedField(..) => panic!("no tuple structs in FFI"), + }; + + let cname = match &name.to_string()[..] { + s if s.ends_with("_nsec") && ty == "stat" => { + s.replace("_nsec", "spec.tv_nsec") + } + s => s.to_string(), + }; + + writeln!(self.c, r#" + uint64_t __test_offset_{ty}_{rust_field}() {{ + return offsetof({cty}, {c_field}); + }} + uint64_t __test_size_{ty}_{rust_field}() {{ + {cty}* foo = NULL; + return sizeof(foo->{c_field}); + }} + "#, ty = ty, cty = cty, rust_field = name, c_field = cname); + writeln!(self.rust, r#" + extern {{ + fn __test_offset_{ty}_{field}() -> u64; + fn __test_size_{ty}_{field}() -> u64; + }} + unsafe {{ + let foo = 0 as *const {ty}; + same(offset_of!({ty}, {field}), + __test_offset_{ty}_{field}(), + "field offset {field} of {ty}"); + same(mem::size_of_val(&(*foo).{field}) as u64, + __test_size_{ty}_{field}(), + "field size {field} of {ty}"); + }} + "#, ty = ty, field = name); + } + writeln!(self.rust, r#" + }} + "#); } fn test_size_align(&mut self, rust: &str, c: &str) { @@ -150,12 +194,10 @@ impl<'a> TestGenerator<'a> { fn __test_align_{ty}() -> u64; }} unsafe {{ - let a = mem::size_of::<{ty}>() as u64; - let b = __test_size_{ty}(); - assert!(a == b, "bad size: rust {{}} != c {{}}", a, b); - let a = mem::align_of::<{ty}>() as u64; - let b = __test_align_{ty}(); - assert!(a == b, "bad align: rust {{}} != c {{}}", a, b); + same(mem::size_of::<{ty}>() as u64, + __test_size_{ty}(), "size"); + same(mem::align_of::<{ty}>() as u64, + __test_align_{ty}(), "align"); }} }} "#, ty = rust); diff --git a/libc-test/tests/all.rs b/libc-test/tests/all.rs index 447e3557..b717c8a5 100644 --- a/libc-test/tests/all.rs +++ b/libc-test/tests/all.rs @@ -6,5 +6,17 @@ use std::mem; use libc::*; use libc::types::os::common::bsd43::*; +fn same(rust: u64, c: u64, attr: &str) { + if rust != c { + panic!("bad {}: rust: {} != c {}", attr, rust, c); + } +} + +macro_rules! offset_of { + ($ty:ident, $field:ident) => ( + (&((*(0 as *const $ty)).$field)) as *const _ as u64 + ) +} + #[cfg(test)] include!(concat!(env!("OUT_DIR"), "/all.rs")); diff --git a/src/lib.rs b/src/lib.rs index 46a53d05..bd57a155 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -230,11 +230,11 @@ pub mod types { pub gl_pathv: *mut *mut c_char, pub gl_offs: size_t, - pub __unused1: *mut c_void, - pub __unused2: *mut c_void, - pub __unused3: *mut c_void, - pub __unused4: *mut c_void, - pub __unused5: *mut c_void, + __unused1: *mut c_void, + __unused2: *mut c_void, + __unused3: *mut c_void, + __unused4: *mut c_void, + __unused5: *mut c_void, } #[repr(C)] @@ -491,8 +491,8 @@ pub mod types { pub st_mtime_nsec: c_long, pub st_ctime: time_t, pub st_ctime_nsec: c_long, - pub __unused4: c_long, - pub __unused5: c_long, + __unused4: c_long, + __unused5: c_long, } #[repr(C)] @@ -693,7 +693,7 @@ pub mod types { pub st_mtime_nsec: c_long, pub st_ctime: time_t, pub st_ctime_nsec: c_long, - pub __unused: [c_long; 3], + __unused: [c_long; 3], } #[repr(C)] @@ -738,7 +738,7 @@ pub mod types { pub st_mtime_nsec: c_long, pub st_ctime: time_t, pub st_ctime_nsec: c_long, - pub __unused: [c_int; 2], + __unused: [c_int; 2], } #[repr(C)] @@ -787,18 +787,18 @@ pub mod types { #[repr(C)] #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: size_t, - pub __unused1: size_t, + __unused1: size_t, pub gl_offs: size_t, - pub __unused2: c_int, + __unused2: c_int, pub gl_pathv: *mut *mut c_char, - pub __unused3: *mut c_void, + __unused3: *mut c_void, - pub __unused4: *mut c_void, - pub __unused5: *mut c_void, - pub __unused6: *mut c_void, - pub __unused7: *mut c_void, - pub __unused8: *mut c_void, + __unused4: *mut c_void, + __unused5: *mut c_void, + __unused6: *mut c_void, + __unused7: *mut c_void, + __unused8: *mut c_void, } #[repr(C)] @@ -1021,7 +1021,7 @@ pub mod types { pub st_lspare: int32_t, pub st_birthtime: time_t, pub st_birthtime_nsec: c_long, - pub __unused: [u8; 8], + __unused: [u8; 8], } #[repr(C)] @@ -1149,18 +1149,18 @@ pub mod types { #[repr(C)] #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: size_t, - pub __unused1: size_t, + __unused1: size_t, pub gl_offs: size_t, - pub __unused2: c_int, + __unused2: c_int, pub gl_pathv: *mut *mut c_char, - pub __unused3: *mut c_void, + __unused3: *mut c_void, - pub __unused4: *mut c_void, - pub __unused5: *mut c_void, - pub __unused6: *mut c_void, - pub __unused7: *mut c_void, - pub __unused8: *mut c_void, + __unused4: *mut c_void, + __unused5: *mut c_void, + __unused6: *mut c_void, + __unused7: *mut c_void, + __unused8: *mut c_void, } #[repr(C)] @@ -1422,32 +1422,32 @@ pub mod types { pub gl_offs: c_int, pub gl_flags: c_int, pub gl_pathv: *mut *mut c_char, - pub __unused1: *mut c_void, - pub __unused2: *mut c_void, - pub __unused3: *mut c_void, - pub __unused4: *mut c_void, - pub __unused5: *mut c_void, - pub __unused6: *mut c_void, - pub __unused7: *mut c_void, + __unused1: *mut c_void, + __unused2: *mut c_void, + __unused3: *mut c_void, + __unused4: *mut c_void, + __unused5: *mut c_void, + __unused6: *mut c_void, + __unused7: *mut c_void, } #[cfg(any(target_os = "netbsd", target_os="openbsd"))] #[repr(C)] #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: c_int, - pub __unused1: c_int, + __unused1: c_int, pub gl_offs: c_int, - pub __unused2: c_int, + __unused2: c_int, pub gl_pathv: *mut *mut c_char, - pub __unused3: *mut c_void, + __unused3: *mut c_void, - pub __unused4: *mut c_void, - pub __unused5: *mut c_void, - pub __unused6: *mut c_void, - pub __unused7: *mut c_void, - pub __unused8: *mut c_void, - pub __unused9: *mut c_void, + __unused4: *mut c_void, + __unused5: *mut c_void, + __unused6: *mut c_void, + __unused7: *mut c_void, + __unused8: *mut c_void, + __unused9: *mut c_void, } #[repr(C)] @@ -2122,18 +2122,18 @@ pub mod types { #[repr(C)] #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: size_t, - pub __unused1: c_int, + __unused1: c_int, pub gl_offs: size_t, - pub __unused2: c_int, + __unused2: c_int, pub gl_pathv: *mut *mut c_char, - pub __unused3: *mut c_void, + __unused3: *mut c_void, - pub __unused4: *mut c_void, - pub __unused5: *mut c_void, - pub __unused6: *mut c_void, - pub __unused7: *mut c_void, - pub __unused8: *mut c_void, + __unused4: *mut c_void, + __unused5: *mut c_void, + __unused6: *mut c_void, + __unused7: *mut c_void, + __unused8: *mut c_void, } #[repr(C)]