diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 7af70e9890..0a6737bb66 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -84,6 +84,9 @@ struct CodegenResult<'a> { /// Whether an union has been generated at least once. saw_union: bool, + /// Whether an incomplete array has been generated at least once. + saw_incomplete_array: bool, + items_seen: HashSet, /// The set of generated function/var names, needed because in C/C++ is /// legal to do something like: @@ -115,6 +118,7 @@ impl<'a> CodegenResult<'a> { CodegenResult { items: vec![], saw_union: false, + saw_incomplete_array: false, codegen_id: codegen_id, items_seen: Default::default(), functions_seen: Default::default(), @@ -132,6 +136,10 @@ impl<'a> CodegenResult<'a> { self.saw_union = true; } + fn saw_incomplete_array(&mut self) { + self.saw_incomplete_array = true; + } + fn seen(&self, item: ItemId) -> bool { self.items_seen.contains(&item) } @@ -175,6 +183,7 @@ impl<'a> CodegenResult<'a> { cb(&mut new); self.saw_union |= new.saw_union; + self.saw_incomplete_array |= new.saw_incomplete_array; new.items } @@ -344,6 +353,9 @@ impl CodeGenerator for Module { if saw_union && !ctx.options().unstable_rust { utils::prepend_union_types(ctx, &mut *result); } + if result.saw_incomplete_array { + utils::prepend_incomplete_array_types(ctx, &mut *result); + } if ctx.need_bindegen_complex_type() { utils::prepend_complex_type(ctx, &mut *result); } @@ -1013,6 +1025,16 @@ impl CodeGenerator for CompInfo { } else { quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) } + } else if let Some(item) = field_ty.is_incomplete_array(ctx) { + result.saw_incomplete_array(); + + let inner = item.to_rust_ty(ctx); + + if ctx.options().enable_cxx_namespaces { + quote_ty!(ctx.ext_cx(), root::__IncompleteArrayField<$inner>) + } else { + quote_ty!(ctx.ext_cx(), __IncompleteArrayField<$inner>) + } } else { ty }; @@ -2333,6 +2355,67 @@ mod utils { result.extend(old_items.into_iter()); } + pub fn prepend_incomplete_array_types(ctx: &BindgenContext, + result: &mut Vec>) { + let prefix = ctx.trait_prefix(); + + let incomplete_array_decl = quote_item!(ctx.ext_cx(), + #[repr(C)] + pub struct __IncompleteArrayField( + ::$prefix::marker::PhantomData); + ) + .unwrap(); + + let incomplete_array_impl = quote_item!(&ctx.ext_cx(), + impl __IncompleteArrayField { + #[inline] + pub fn new() -> Self { + __IncompleteArrayField(::$prefix::marker::PhantomData) + } + + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { + ::$prefix::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ::$prefix::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::std::slice::from_raw_parts(self.as_ptr(), len) + } + + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } + } + ) + .unwrap(); + + let incomplete_array_debug_impl = quote_item!(ctx.ext_cx(), + impl ::std::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> ::std::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } + } + ) + .unwrap(); + + let items = vec![ + incomplete_array_decl, + incomplete_array_impl, + incomplete_array_debug_impl, + ]; + + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + pub fn prepend_complex_type(ctx: &BindgenContext, result: &mut Vec>) { let complex_type = quote_item!(ctx.ext_cx(), diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 1e87beb466..f120e180c5 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -194,6 +194,15 @@ impl Type { } } + /// Is this a incomplete array type? + pub fn is_incomplete_array(&self, ctx: &BindgenContext) -> Option { + match self.kind { + TypeKind::Array(item, len) => if len == 0 { Some(item) } else { None }, + TypeKind::ResolvedTypeRef(inner) => ctx.resolve_type(inner).is_incomplete_array(ctx), + _ => None, + } + } + /// What is the layout of this type? pub fn layout(&self, ctx: &BindgenContext) -> Option { use std::mem; @@ -816,8 +825,7 @@ impl Type { } // XXX DependentSizedArray is wrong CXType_VariableArray | - CXType_DependentSizedArray | - CXType_IncompleteArray => { + CXType_DependentSizedArray => { let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), location, parent_id, @@ -825,6 +833,14 @@ impl Type { .expect("Not able to resolve array element?"); TypeKind::Pointer(inner) } + CXType_IncompleteArray => { + let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), + location, + parent_id, + ctx) + .expect("Not able to resolve array element?"); + TypeKind::Array(inner, 0) + } CXType_FunctionNoProto | CXType_FunctionProto => { let signature = try!(FunctionSig::from_ty(ty, diff --git a/tests/expectations/tests/class.rs b/tests/expectations/tests/class.rs index 579c24a44b..29d1e90480 100644 --- a/tests/expectations/tests/class.rs +++ b/tests/expectations/tests/class.rs @@ -4,6 +4,33 @@ #![allow(non_snake_case)] +#[repr(C)] +pub struct __IncompleteArrayField(::std::marker::PhantomData); +impl __IncompleteArrayField { + #[inline] + pub fn new() -> Self { + __IncompleteArrayField(::std::marker::PhantomData) + } + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { ::std::mem::transmute(self) } + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ::std::mem::transmute(self) + } + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::std::slice::from_raw_parts(self.as_ptr(), len) + } + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } +} +impl ::std::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } +} #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -39,6 +66,42 @@ fn bindgen_test_layout_C() { assert_eq!(::std::mem::align_of::() , 4usize); } #[repr(C)] +pub struct C_with_zero_length_array { + pub a: ::std::os::raw::c_int, + pub big_array: [::std::os::raw::c_char; 33usize], + pub zero_length_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_C_with_zero_length_array() { + assert_eq!(::std::mem::size_of::() , 40usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +#[repr(C)] +pub struct C_with_incomplete_array { + pub a: ::std::os::raw::c_int, + pub big_array: [::std::os::raw::c_char; 33usize], + pub incomplete_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_C_with_incomplete_array() { + assert_eq!(::std::mem::size_of::() , 40usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +#[repr(C)] +pub struct C_with_zero_length_array_and_incomplete_array { + pub a: ::std::os::raw::c_int, + pub big_array: [::std::os::raw::c_char; 33usize], + pub zero_length_array: __IncompleteArrayField<::std::os::raw::c_char>, + pub incomplete_array: __IncompleteArrayField<::std::os::raw::c_char>, +} +#[test] +fn bindgen_test_layout_C_with_zero_length_array_and_incomplete_array() { + assert_eq!(::std::mem::size_of::() + , 40usize); + assert_eq!(::std::mem::align_of::() + , 4usize); +} +#[repr(C)] #[derive(Debug)] pub struct WithDtor { pub b: ::std::os::raw::c_int, diff --git a/tests/expectations/tests/var-tracing.rs b/tests/expectations/tests/var-tracing.rs index 75c5ebe3be..ef5660eb57 100644 --- a/tests/expectations/tests/var-tracing.rs +++ b/tests/expectations/tests/var-tracing.rs @@ -36,7 +36,7 @@ pub struct Baz { } extern "C" { #[link_name = "_ZN3Baz3FOOE"] - pub static mut Baz_FOO: *const Bar; + pub static mut Baz_FOO: [Bar; 0usize]; } #[test] fn bindgen_test_layout_Baz() { diff --git a/tests/headers/class.hpp b/tests/headers/class.hpp index e753f186cf..67ecb37b24 100644 --- a/tests/headers/class.hpp +++ b/tests/headers/class.hpp @@ -4,6 +4,28 @@ class C { char big_array[33]; }; +class C_with_zero_length_array { + int a; + // More than rust limits (32) + char big_array[33]; + char zero_length_array[0]; +}; + +class C_with_incomplete_array { + int a; + // More than rust limits (32) + char big_array[33]; + char incomplete_array[]; +}; + +class C_with_zero_length_array_and_incomplete_array { + int a; + // More than rust limits (32) + char big_array[33]; + char zero_length_array[0]; + char incomplete_array[]; +}; + class WithDtor { int b;