From 06bfb06a6c9527c56d705b4af928c1c59f9eac0a Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sun, 25 Feb 2024 00:38:34 -0800 Subject: [PATCH 01/10] Add --flexarray-dst option This option uses Rust DST types to model C structures with flexible array members. For example, if you declare: ```c struct record { int len; float values[]; } ``` this means it's a C structure with a well-defined prefix, but a tail of `values` which depends on how much memory we've allocated for it. We can model this in Rust with: ```rust struct record { len: c_int, values: [f32], } ``` which means more or less the same thing - there's a type which has a known prefix, but its suffix is not directly known. --- bindgen-cli/options.rs | 8 ++ bindgen/codegen/mod.rs | 165 ++++++++++++++++++++++++++++--- bindgen/codegen/struct_layout.rs | 11 +++ bindgen/features.rs | 2 + bindgen/ir/comp.rs | 26 +++++ bindgen/options/mod.rs | 13 +++ 6 files changed, 213 insertions(+), 12 deletions(-) diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index 815a28f42a..5edc8c95e5 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -406,6 +406,9 @@ struct BindgenCommand { /// Set path for temporary files generated by fallback for clang macro parsing. #[arg(long)] clang_macro_fallback_build_dir: Option, + /// Use DSTs to represent structures with flexible array members. + #[arg(long)] + flexarray_dst: bool, /// Derive custom traits on any kind of type. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a coma-separated list of derive macros. #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)] with_derive_custom: Vec<(Vec, String)>, @@ -562,6 +565,7 @@ where wrap_unsafe_ops, clang_macro_fallback, clang_macro_fallback_build_dir, + flexarray_dst, with_derive_custom, with_derive_custom_struct, with_derive_custom_enum, @@ -1039,6 +1043,10 @@ where builder = builder.clang_macro_fallback_build_dir(path); } + if flexarray_dst { + builder = builder.flexarray_dst(true); + } + #[derive(Debug)] struct CustomDeriveCallback { derives: Vec, diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index b6f915a833..c2da991e1f 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -1454,10 +1454,13 @@ impl<'a> FieldCodegen<'a> for FieldData { wrap_union_field_if_needed(ctx, struct_layout, ty, result) } else if let Some(item) = field_ty.is_incomplete_array(ctx) { result.saw_incomplete_array(); + struct_layout.saw_flexible_array(); let inner = item.to_rust_ty_or_opaque(ctx, &()); - if ctx.options().enable_cxx_namespaces { + if ctx.options().flexarray_dst { + syn::parse_quote! { FAM } + } else if ctx.options().enable_cxx_namespaces { syn::parse_quote! { root::__IncompleteArrayField<#inner> } } else { syn::parse_quote! { __IncompleteArrayField<#inner> } @@ -2208,20 +2211,60 @@ impl CodeGenerator for CompInfo { }); } - let generics = if !generic_param_names.is_empty() { - let generic_param_names = generic_param_names.clone(); - quote! { - < #( #generic_param_names ),* > + let (flex_array_generic, flex_inner_ty) = if ctx.options().flexarray_dst + { + match self.flex_array_member(ctx) { + Some(ty) => { + let inner = ty.to_rust_ty_or_opaque(ctx, &()); + ( + Some(quote! { FAM: ?Sized = [ #inner; 0 ] }), + Some(quote! { #inner }), + ) + } + None => (None, None), } } else { - quote! {} + (None, None) }; + // Generics, including the flexible array member. + // + // generics - generic parameters for the struct declaration + // impl_generics_labels - generic parameters for `impl<...>` + // impl_generics_params - generic parameters for `impl structname<...>` + // + // `impl` blocks are for non-FAM related impls like Default, etc + let (generics, impl_generics_labels, impl_generics_params) = + if !generic_param_names.is_empty() || flex_array_generic.is_some() { + let (flex_sized, flex_fam) = match flex_inner_ty.as_ref() { + None => (None, None), + Some(ty) => ( + Some(quote! { [ #ty; 0 ] }), + Some(quote! { FAM: ?Sized = [ #ty; 0 ] }), + ), + }; + + ( + quote! { + < #( #generic_param_names , )* #flex_fam > + }, + quote! { + < #( #generic_param_names , )* > + }, + quote! { + < #( #generic_param_names , )* #flex_sized > + }, + ) + } else { + (quote! {}, quote! {}, quote! {}) + }; + let mut attributes = vec![]; let mut needs_clone_impl = false; let mut needs_default_impl = false; let mut needs_debug_impl = false; let mut needs_partialeq_impl = false; + let needs_flexarray_impl = flex_array_generic.is_some(); if let Some(comment) = item.comment(ctx) { attributes.push(attributes::doc(comment)); } @@ -2525,17 +2568,112 @@ impl CodeGenerator for CompInfo { // NB: We can't use to_rust_ty here since for opaque types this tries to // use the specialization knowledge to generate a blob field. let ty_for_impl = quote! { - #canonical_ident #generics + #canonical_ident #impl_generics_params }; if needs_clone_impl { result.push(quote! { - impl #generics Clone for #ty_for_impl { + impl #impl_generics_labels Clone for #ty_for_impl { fn clone(&self) -> Self { *self } } }); } + if needs_flexarray_impl { + let prefix = ctx.trait_prefix(); + + let flex_array = + flex_inner_ty.as_ref().map(|ty| quote! { [ #ty ] }); + + let dst_ty_for_impl = quote! { + #canonical_ident < #( #generic_param_names , )* #flex_array > + + }; + let sized_ty_for_impl = quote! { + #canonical_ident < #( #generic_param_names , )* [ #flex_inner_ty; 0 ] > + }; + + let turbo_dst_ty = quote! { + #canonical_ident :: < #( #generic_param_names , )* [ #flex_inner_ty ] > + }; + + let layout = if ctx.options().rust_features().layout_for_ptr { + quote! { + pub fn layout(len: usize) -> ::#prefix::alloc::Layout { + // SAFETY: Null pointers are OK if we don't deref them + unsafe { + let p: *const Self = ::#prefix::ptr::from_raw_parts(::#prefix::ptr::null(), len); + ::#prefix::alloc::Layout::for_value_raw(p) + } + } + } + } else { + quote!() + }; + + let (from_ptr_dst, from_ptr_sized) = if ctx + .options() + .rust_features() + .ptr_metadata + { + ( + quote! { + /// Construct a DST for `#canonical_ident` from a thin + /// pointer. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr<'a>(ptr: *const #sized_ty_for_impl, len: usize) -> &'a Self { + let ptr: *const Self = ::#prefix::ptr::from_raw_parts(ptr as *const (), len); + &*ptr + } + + /// Construct a mutable DST for `#canonical_ident` from + /// a thin pointer. This is `MaybeUninit` to allow for + /// initialization. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr_mut<'a>(ptr: *mut #sized_ty_for_impl, len: usize) -> ::#prefix::mem::MaybeUninit<&'a mut Self> { + let ptr: *mut Self = ::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len); + ::#prefix::mem::MaybeUninit::new(&mut *ptr) + } + }, + quote! { + /// Turn a sized reference for `#canonical_ident` into + /// DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref(&self, len: usize) -> & #dst_ty_for_impl { + // SAFETY: caller guarantees `len` is good + unsafe { #turbo_dst_ty :: from_ptr(self, len) } + } + + /// Turn a mutable sized reference for + /// `#canonical_ident` into DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref_mut(&mut self, len: usize) -> &mut #dst_ty_for_impl { + unsafe { #turbo_dst_ty :: from_ptr_mut(self, len).assume_init() } + } + }, + ) + } else { + (quote!(), quote!()) + }; + + result.push(quote! { + impl #impl_generics_labels #dst_ty_for_impl { + #layout + #from_ptr_dst + } + + impl #impl_generics_labels #sized_ty_for_impl { + #from_ptr_sized + } + }); + } + if needs_default_impl { let prefix = ctx.trait_prefix(); let body = if ctx.options().rust_features().maybe_uninit { @@ -2560,7 +2698,7 @@ impl CodeGenerator for CompInfo { // non-zero padding bytes, especially when forwards/backwards compatibility is // involved. result.push(quote! { - impl #generics Default for #ty_for_impl { + impl #impl_generics_labels Default for #ty_for_impl { fn default() -> Self { #body } @@ -2579,7 +2717,7 @@ impl CodeGenerator for CompInfo { let prefix = ctx.trait_prefix(); result.push(quote! { - impl #generics ::#prefix::fmt::Debug for #ty_for_impl { + impl #impl_generics_labels ::#prefix::fmt::Debug for #ty_for_impl { #impl_ } }); @@ -2603,7 +2741,7 @@ impl CodeGenerator for CompInfo { let prefix = ctx.trait_prefix(); result.push(quote! { - impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds { + impl #impl_generics_labels ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds { #impl_ } }); @@ -2612,7 +2750,7 @@ impl CodeGenerator for CompInfo { if !methods.is_empty() { result.push(quote! { - impl #generics #ty_for_impl { + impl #impl_generics_labels #ty_for_impl { #( #methods )* } }); @@ -5130,6 +5268,9 @@ pub(crate) mod utils { ctx: &BindgenContext, result: &mut Vec, ) { + if ctx.options().flexarray_dst { + return; + } let prefix = ctx.trait_prefix(); // If the target supports `const fn`, declare eligible functions diff --git a/bindgen/codegen/struct_layout.rs b/bindgen/codegen/struct_layout.rs index 7349669871..507c8d40e2 100644 --- a/bindgen/codegen/struct_layout.rs +++ b/bindgen/codegen/struct_layout.rs @@ -28,6 +28,7 @@ pub(crate) struct StructLayoutTracker<'a> { max_field_align: usize, last_field_was_bitfield: bool, visibility: FieldVisibilityKind, + last_field_was_flexible_array: bool, } /// Returns a size aligned to a given value. @@ -110,6 +111,7 @@ impl<'a> StructLayoutTracker<'a> { latest_field_layout: None, max_field_align: 0, last_field_was_bitfield: false, + last_field_was_flexible_array: false, } } @@ -121,6 +123,10 @@ impl<'a> StructLayoutTracker<'a> { self.is_rust_union } + pub(crate) fn saw_flexible_array(&mut self) { + self.last_field_was_flexible_array = true; + } + pub(crate) fn saw_vtable(&mut self) { debug!("saw vtable for {}", self.name); @@ -295,6 +301,11 @@ impl<'a> StructLayoutTracker<'a> { return None; } + // Also doesn't make sense for structs with flexible array members + if self.last_field_was_flexible_array { + return None; + } + if self.latest_offset == comp_layout.size { // This struct does not contain tail padding. return None; diff --git a/bindgen/features.rs b/bindgen/features.rs index 6ac1d6a16d..c07318c5e2 100644 --- a/bindgen/features.rs +++ b/bindgen/features.rs @@ -96,6 +96,8 @@ macro_rules! define_rust_targets { define_rust_targets! { Nightly => { vectorcall_abi, + ptr_metadata: #81513, + layout_for_ptr: #69835, }, Stable_1_77(77) => { offset_of: #106655 }, Stable_1_73(73) => { thiscall_abi: #42202 }, diff --git a/bindgen/ir/comp.rs b/bindgen/ir/comp.rs index bd4d016261..5ae2d68747 100644 --- a/bindgen/ir/comp.rs +++ b/bindgen/ir/comp.rs @@ -825,6 +825,24 @@ impl CompFields { } } } + + /// Return the flex array member for the struct/class, if any. + fn flex_array_member(&self, ctx: &BindgenContext) -> Option { + let fields = match self { + CompFields::Before(_) => panic!("raw fields"), + CompFields::After { fields, .. } => fields, + CompFields::Error => return None, // panic? + }; + + // XXX correct with padding on end? + match fields.last() { + None | Some(Field::Bitfields(..)) => None, + Some(Field::DataMember(FieldData { ty, .. })) => ctx + .resolve_type(*ty) + .is_incomplete_array(ctx) + .map(|item| item.expect_type_id(ctx)), + } + } } impl Trace for CompFields { @@ -1122,6 +1140,14 @@ impl CompInfo { } } + /// Return the flex array member and its element type if any + pub(crate) fn flex_array_member( + &self, + ctx: &BindgenContext, + ) -> Option { + self.fields.flex_array_member(ctx) + } + fn has_fields(&self) -> bool { match self.fields { CompFields::Error => false, diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index f374d20732..d1486397bd 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -1981,6 +1981,19 @@ options! { }, as_args: "--wrap-unsafe-ops", }, + /// Use DSTs to represent structures with flexible array members. + flexarray_dst: bool { + methods: { + /// Use DSTs to represent structures with flexible array members. + /// + /// This option is disabled by default. + pub fn flexarray_dst(mut self, doit: bool) -> Self { + self.options.flexarray_dst = doit; + self + } + }, + as_args: "--flexarray-dst", + }, /// Patterns for functions whose ABI should be overridden. abi_overrides: HashMap { methods: { From e9eb68d1a3fb5f3b93005cc6ed81a625598e581e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 1 Mar 2024 23:06:58 -0500 Subject: [PATCH 02/10] Only generate flex array member for last field There are some tests which have two incomplete array fields; only the very last one is valid as a flexible array member (in C) or can be a DST field in Rust. --- bindgen/codegen/mod.rs | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index c2da991e1f..2c6aafe5a2 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -1333,6 +1333,7 @@ trait FieldCodegen<'a> { accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, @@ -1353,6 +1354,7 @@ impl<'a> FieldCodegen<'a> for Field { accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, @@ -1370,6 +1372,7 @@ impl<'a> FieldCodegen<'a> for Field { accessor_kind, parent, parent_item, + last_field, result, struct_layout, fields, @@ -1384,6 +1387,7 @@ impl<'a> FieldCodegen<'a> for Field { accessor_kind, parent, parent_item, + last_field, result, struct_layout, fields, @@ -1428,6 +1432,7 @@ impl<'a> FieldCodegen<'a> for FieldData { accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, @@ -1453,17 +1458,20 @@ impl<'a> FieldCodegen<'a> for FieldData { let ty = if parent.is_union() { wrap_union_field_if_needed(ctx, struct_layout, ty, result) } else if let Some(item) = field_ty.is_incomplete_array(ctx) { - result.saw_incomplete_array(); - struct_layout.saw_flexible_array(); - - let inner = item.to_rust_ty_or_opaque(ctx, &()); - - if ctx.options().flexarray_dst { + // Only FAM if its the last field + if ctx.options().flexarray_dst && last_field { + struct_layout.saw_flexible_array(); syn::parse_quote! { FAM } - } else if ctx.options().enable_cxx_namespaces { - syn::parse_quote! { root::__IncompleteArrayField<#inner> } } else { - syn::parse_quote! { __IncompleteArrayField<#inner> } + result.saw_incomplete_array(); + + let inner = item.to_rust_ty_or_opaque(ctx, &()); + + if ctx.options().enable_cxx_namespaces { + syn::parse_quote! { root::__IncompleteArrayField<#inner> } + } else { + syn::parse_quote! { __IncompleteArrayField<#inner> } + } } } else { ty @@ -1685,6 +1693,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + _last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, @@ -1745,7 +1754,8 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT; let mut unit_visibility = visibility_kind; - for bf in self.bitfields() { + let bfields = self.bitfields(); + for (idx, bf) in bfields.iter().enumerate() { // Codegen not allowed for anonymous bitfields if bf.name().is_none() { continue; @@ -1765,6 +1775,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { accessor_kind, parent, parent_item, + idx == bfields.len() - 1, result, struct_layout, fields, @@ -1847,6 +1858,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { _accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + _last_field: bool, _result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, _fields: &mut F, @@ -2080,13 +2092,15 @@ impl CodeGenerator for CompInfo { .annotations() .accessor_kind() .unwrap_or(FieldAccessorKind::None); - for field in self.fields() { + let field_decls = self.fields(); + for (idx, field) in field_decls.iter().enumerate() { field.codegen( ctx, visibility, struct_accessor_kind, self, item, + idx == field_decls.len() - 1, result, &mut struct_layout, &mut fields, @@ -5268,9 +5282,6 @@ pub(crate) mod utils { ctx: &BindgenContext, result: &mut Vec, ) { - if ctx.options().flexarray_dst { - return; - } let prefix = ctx.trait_prefix(); // If the target supports `const fn`, declare eligible functions From 907a51035c4d94bc1afcf8475ce44ea10fb318fc Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sat, 2 Mar 2024 18:32:42 -0500 Subject: [PATCH 03/10] Add flex array member tests --- .../tests/expectations/tests/flexarray.rs | 525 ++++++++++++++++++ bindgen-tests/tests/headers/flexarray.hpp | 32 ++ 2 files changed, 557 insertions(+) create mode 100644 bindgen-tests/tests/expectations/tests/flexarray.rs create mode 100644 bindgen-tests/tests/headers/flexarray.hpp diff --git a/bindgen-tests/tests/expectations/tests/flexarray.rs b/bindgen-tests/tests/expectations/tests/flexarray.rs new file mode 100644 index 0000000000..bbe7c4f202 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/flexarray.rs @@ -0,0 +1,525 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#![cfg(feature = "nightly")] +#![feature(ptr_metadata, layout_for_ptr)] +#[repr(C)] +#[derive(Default)] +pub struct __IncompleteArrayField(::std::marker::PhantomData, [T; 0]); +impl __IncompleteArrayField { + #[inline] + pub const fn new() -> Self { + __IncompleteArrayField(::std::marker::PhantomData, []) + } + #[inline] + pub fn as_ptr(&self) -> *const T { + self as *const _ as *const T + } + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + self as *mut _ as *mut T + } + #[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)] +#[derive(Debug, Default)] +pub struct flexarray { + pub count: ::std::os::raw::c_int, + pub data: FAM, +} +#[test] +fn bindgen_test_layout_flexarray() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(flexarray)), + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(flexarray)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, + 0usize, + concat!("Offset of field: ", stringify!(flexarray), "::", stringify!(count)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 4usize, + concat!("Offset of field: ", stringify!(flexarray), "::", stringify!(data)), + ); +} +impl flexarray<[::std::os::raw::c_int]> { + pub fn layout(len: usize) -> ::std::alloc::Layout { + unsafe { + let p: *const Self = ::std::ptr::from_raw_parts(::std::ptr::null(), len); + ::std::alloc::Layout::for_value_raw(p) + } + } + /// Construct a DST for `#canonical_ident` from a thin + /// pointer. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr<'a>( + ptr: *const flexarray<[::std::os::raw::c_int; 0]>, + len: usize, + ) -> &'a Self { + let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); + &*ptr + } + /// Construct a mutable DST for `#canonical_ident` from + /// a thin pointer. This is `MaybeUninit` to allow for + /// initialization. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr_mut<'a>( + ptr: *mut flexarray<[::std::os::raw::c_int; 0]>, + len: usize, + ) -> ::std::mem::MaybeUninit<&'a mut Self> { + let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); + ::std::mem::MaybeUninit::new(&mut *ptr) + } +} +impl flexarray<[::std::os::raw::c_int; 0]> { + /// Turn a sized reference for `#canonical_ident` into + /// DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref(&self, len: usize) -> &flexarray<[::std::os::raw::c_int]> { + unsafe { flexarray::<[::std::os::raw::c_int]>::from_ptr(self, len) } + } + /// Turn a mutable sized reference for + /// `#canonical_ident` into DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref_mut( + &mut self, + len: usize, + ) -> &mut flexarray<[::std::os::raw::c_int]> { + unsafe { + flexarray::<[::std::os::raw::c_int]>::from_ptr_mut(self, len).assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Default)] +pub struct flexarray_zero { + pub count: ::std::os::raw::c_int, + pub data: FAM, +} +#[test] +fn bindgen_test_layout_flexarray_zero() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(flexarray_zero)), + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(flexarray_zero)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, + 0usize, + concat!("Offset of field: ", stringify!(flexarray_zero), "::", stringify!(count)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 4usize, + concat!("Offset of field: ", stringify!(flexarray_zero), "::", stringify!(data)), + ); +} +impl flexarray_zero<[::std::os::raw::c_int]> { + pub fn layout(len: usize) -> ::std::alloc::Layout { + unsafe { + let p: *const Self = ::std::ptr::from_raw_parts(::std::ptr::null(), len); + ::std::alloc::Layout::for_value_raw(p) + } + } + /// Construct a DST for `#canonical_ident` from a thin + /// pointer. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr<'a>( + ptr: *const flexarray_zero<[::std::os::raw::c_int; 0]>, + len: usize, + ) -> &'a Self { + let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); + &*ptr + } + /// Construct a mutable DST for `#canonical_ident` from + /// a thin pointer. This is `MaybeUninit` to allow for + /// initialization. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr_mut<'a>( + ptr: *mut flexarray_zero<[::std::os::raw::c_int; 0]>, + len: usize, + ) -> ::std::mem::MaybeUninit<&'a mut Self> { + let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); + ::std::mem::MaybeUninit::new(&mut *ptr) + } +} +impl flexarray_zero<[::std::os::raw::c_int; 0]> { + /// Turn a sized reference for `#canonical_ident` into + /// DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref( + &self, + len: usize, + ) -> &flexarray_zero<[::std::os::raw::c_int]> { + unsafe { flexarray_zero::<[::std::os::raw::c_int]>::from_ptr(self, len) } + } + /// Turn a mutable sized reference for + /// `#canonical_ident` into DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref_mut( + &mut self, + len: usize, + ) -> &mut flexarray_zero<[::std::os::raw::c_int]> { + unsafe { + flexarray_zero::<[::std::os::raw::c_int]>::from_ptr_mut(self, len) + .assume_init() + } + } +} +#[repr(C)] +#[derive(Debug)] +pub struct flexarray_template { + pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + pub count: ::std::os::raw::c_int, + pub data: FAM, +} +impl flexarray_template { + pub fn layout(len: usize) -> ::std::alloc::Layout { + unsafe { + let p: *const Self = ::std::ptr::from_raw_parts(::std::ptr::null(), len); + ::std::alloc::Layout::for_value_raw(p) + } + } + /// Construct a DST for `#canonical_ident` from a thin + /// pointer. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr<'a>( + ptr: *const flexarray_template, + len: usize, + ) -> &'a Self { + let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); + &*ptr + } + /// Construct a mutable DST for `#canonical_ident` from + /// a thin pointer. This is `MaybeUninit` to allow for + /// initialization. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr_mut<'a>( + ptr: *mut flexarray_template, + len: usize, + ) -> ::std::mem::MaybeUninit<&'a mut Self> { + let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); + ::std::mem::MaybeUninit::new(&mut *ptr) + } +} +impl flexarray_template { + /// Turn a sized reference for `#canonical_ident` into + /// DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref(&self, len: usize) -> &flexarray_template { + unsafe { flexarray_template::::from_ptr(self, len) } + } + /// Turn a mutable sized reference for + /// `#canonical_ident` into DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref_mut( + &mut self, + len: usize, + ) -> &mut flexarray_template { + unsafe { flexarray_template::::from_ptr_mut(self, len).assume_init() } + } +} +impl Default for flexarray_template { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct flexarray_ref { + pub things: *mut flexarray, +} +#[test] +fn bindgen_test_layout_flexarray_ref() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(flexarray_ref)), + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(flexarray_ref)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).things) as usize - ptr as usize }, + 0usize, + concat!("Offset of field: ", stringify!(flexarray_ref), "::", stringify!(things)), + ); +} +impl Default for flexarray_ref { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Default)] +pub struct flexarray_bogus_zero_fam { + pub count: ::std::os::raw::c_int, + pub data1: __IncompleteArrayField<::std::os::raw::c_int>, + pub data2: FAM, +} +#[test] +fn bindgen_test_layout_flexarray_bogus_zero_fam() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(flexarray_bogus_zero_fam)), + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(flexarray_bogus_zero_fam)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(flexarray_bogus_zero_fam), + "::", + stringify!(count), + ), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data1) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(flexarray_bogus_zero_fam), + "::", + stringify!(data1), + ), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data2) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(flexarray_bogus_zero_fam), + "::", + stringify!(data2), + ), + ); +} +impl flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { + pub fn layout(len: usize) -> ::std::alloc::Layout { + unsafe { + let p: *const Self = ::std::ptr::from_raw_parts(::std::ptr::null(), len); + ::std::alloc::Layout::for_value_raw(p) + } + } + /// Construct a DST for `#canonical_ident` from a thin + /// pointer. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr<'a>( + ptr: *const flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>, + len: usize, + ) -> &'a Self { + let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); + &*ptr + } + /// Construct a mutable DST for `#canonical_ident` from + /// a thin pointer. This is `MaybeUninit` to allow for + /// initialization. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr_mut<'a>( + ptr: *mut flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>, + len: usize, + ) -> ::std::mem::MaybeUninit<&'a mut Self> { + let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); + ::std::mem::MaybeUninit::new(&mut *ptr) + } +} +impl flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]> { + /// Turn a sized reference for `#canonical_ident` into + /// DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref( + &self, + len: usize, + ) -> &flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { + unsafe { + flexarray_bogus_zero_fam::<[::std::os::raw::c_char]>::from_ptr(self, len) + } + } + /// Turn a mutable sized reference for + /// `#canonical_ident` into DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref_mut( + &mut self, + len: usize, + ) -> &mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { + unsafe { + flexarray_bogus_zero_fam::<[::std::os::raw::c_char]>::from_ptr_mut(self, len) + .assume_init() + } + } +} +#[repr(C)] +#[repr(align(128))] +#[derive(Debug)] +pub struct flexarray_align { + pub count: ::std::os::raw::c_int, + pub data: FAM, +} +#[test] +fn bindgen_test_layout_flexarray_align() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 128usize, + concat!("Size of: ", stringify!(flexarray_align)), + ); + assert_eq!( + ::std::mem::align_of::(), + 128usize, + concat!("Alignment of ", stringify!(flexarray_align)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(flexarray_align), + "::", + stringify!(count), + ), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 4usize, + concat!("Offset of field: ", stringify!(flexarray_align), "::", stringify!(data)), + ); +} +impl flexarray_align<[::std::os::raw::c_int]> { + pub fn layout(len: usize) -> ::std::alloc::Layout { + unsafe { + let p: *const Self = ::std::ptr::from_raw_parts(::std::ptr::null(), len); + ::std::alloc::Layout::for_value_raw(p) + } + } + /// Construct a DST for `#canonical_ident` from a thin + /// pointer. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr<'a>( + ptr: *const flexarray_align<[::std::os::raw::c_int; 0]>, + len: usize, + ) -> &'a Self { + let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); + &*ptr + } + /// Construct a mutable DST for `#canonical_ident` from + /// a thin pointer. This is `MaybeUninit` to allow for + /// initialization. + /// + /// SAFETY: the `len` must be <= the underlying storage. + /// Note: returned lifetime is unbounded. + pub unsafe fn from_ptr_mut<'a>( + ptr: *mut flexarray_align<[::std::os::raw::c_int; 0]>, + len: usize, + ) -> ::std::mem::MaybeUninit<&'a mut Self> { + let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); + ::std::mem::MaybeUninit::new(&mut *ptr) + } +} +impl flexarray_align<[::std::os::raw::c_int; 0]> { + /// Turn a sized reference for `#canonical_ident` into + /// DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref( + &self, + len: usize, + ) -> &flexarray_align<[::std::os::raw::c_int]> { + unsafe { flexarray_align::<[::std::os::raw::c_int]>::from_ptr(self, len) } + } + /// Turn a mutable sized reference for + /// `#canonical_ident` into DST with the given `len`. + /// + /// SAFETY: the `len` must be <= the underlying storage. + pub unsafe fn from_ref_mut( + &mut self, + len: usize, + ) -> &mut flexarray_align<[::std::os::raw::c_int]> { + unsafe { + flexarray_align::<[::std::os::raw::c_int]>::from_ptr_mut(self, len) + .assume_init() + } + } +} +impl Default for flexarray_align<[::std::os::raw::c_int; 0]> { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} diff --git a/bindgen-tests/tests/headers/flexarray.hpp b/bindgen-tests/tests/headers/flexarray.hpp new file mode 100644 index 0000000000..b698c38d19 --- /dev/null +++ b/bindgen-tests/tests/headers/flexarray.hpp @@ -0,0 +1,32 @@ +// bindgen-flags: --rust-target nightly --flexarray-dst --raw-line '#![cfg(feature = "nightly")]' --raw-line '#![feature(ptr_metadata, layout_for_ptr)]' + +struct flexarray { + int count; + int data[]; +}; + +struct flexarray_zero { + int count; + int data[0]; +}; + +template +struct flexarray_template { + int count; + T data[]; +}; + +struct flexarray_ref { + flexarray *things; +}; + +struct flexarray_bogus_zero_fam { + int count; + int data1[0]; + char data2[]; +}; + +struct flexarray_align { + int count; + int data[]; +} __attribute__((aligned(128))); From 474c38bb33e97682d437d16f8e887758fc197017 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 5 Mar 2024 15:14:04 -0800 Subject: [PATCH 04/10] Rework methods on flexarray types Put the pointer converting methods on the sized prefix types ([T; 0]) since they're the default type and what you're likely to be starting with. Emphasize the ones which work on references since they have safe lifetimes, but also have raw pointer variants, esp for handling uninitialized cases. The flex types have methods which return the sized type along with the length. --- .../tests/expectations/tests/flexarray.rs | 424 +++++++++++------- bindgen/codegen/mod.rs | 82 ++-- 2 files changed, 304 insertions(+), 202 deletions(-) diff --git a/bindgen-tests/tests/expectations/tests/flexarray.rs b/bindgen-tests/tests/expectations/tests/flexarray.rs index bbe7c4f202..0e735317ba 100644 --- a/bindgen-tests/tests/expectations/tests/flexarray.rs +++ b/bindgen-tests/tests/expectations/tests/flexarray.rs @@ -69,50 +69,63 @@ impl flexarray<[::std::os::raw::c_int]> { ::std::alloc::Layout::for_value_raw(p) } } - /// Construct a DST for `#canonical_ident` from a thin - /// pointer. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr<'a>( - ptr: *const flexarray<[::std::os::raw::c_int; 0]>, - len: usize, - ) -> &'a Self { - let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); - &*ptr + pub fn fixed(&self) -> (&flexarray<[::std::os::raw::c_int; 0]>, usize) { + unsafe { + let (ptr, len) = (self as *const Self).to_raw_parts(); + (&*(ptr as *const flexarray<[::std::os::raw::c_int; 0]>), len) + } } - /// Construct a mutable DST for `#canonical_ident` from - /// a thin pointer. This is `MaybeUninit` to allow for - /// initialization. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr_mut<'a>( - ptr: *mut flexarray<[::std::os::raw::c_int; 0]>, - len: usize, - ) -> ::std::mem::MaybeUninit<&'a mut Self> { - let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); - ::std::mem::MaybeUninit::new(&mut *ptr) + pub fn fixed_mut(&mut self) -> (&mut flexarray<[::std::os::raw::c_int; 0]>, usize) { + unsafe { + let (ptr, len) = (self as *mut Self).to_raw_parts(); + (&mut *(ptr as *mut flexarray<[::std::os::raw::c_int; 0]>), len) + } } } impl flexarray<[::std::os::raw::c_int; 0]> { - /// Turn a sized reference for `#canonical_ident` into - /// DST with the given `len`. + /// Convert a sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref(&self, len: usize) -> &flexarray<[::std::os::raw::c_int]> { - unsafe { flexarray::<[::std::os::raw::c_int]>::from_ptr(self, len) } + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_ref(&self, len: usize) -> &flexarray<[::std::os::raw::c_int]> { + unsafe { Self::flex_ptr(self, len) } } - /// Turn a mutable sized reference for - /// `#canonical_ident` into DST with the given `len`. + /// Convert a mutable sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref_mut( + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_mut_ref( &mut self, len: usize, ) -> &mut flexarray<[::std::os::raw::c_int]> { + unsafe { Self::flex_ptr_mut(self, len).assume_init() } + } + /// Construct DST variant from a pointer and a size. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + pub unsafe fn flex_ptr<'unbounded>( + ptr: *const Self, + len: usize, + ) -> &'unbounded flexarray<[::std::os::raw::c_int]> { + unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + } + /// Construct mutable DST variant from a pointer and a + /// size. The returned `&mut` reference is initialized + /// pointing to memory referenced by `ptr`, but there's + /// no requirement that that memory be initialized. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + pub unsafe fn flex_ptr_mut<'unbounded>( + ptr: *mut Self, + len: usize, + ) -> ::std::mem::MaybeUninit<&'unbounded mut flexarray<[::std::os::raw::c_int]>> { unsafe { - flexarray::<[::std::os::raw::c_int]>::from_ptr_mut(self, len).assume_init() + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray<[::std::os::raw::c_int]>, + >::uninit(); + (uninit.as_mut_ptr() as *mut *mut flexarray<[::std::os::raw::c_int]>) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit } } } @@ -154,54 +167,70 @@ impl flexarray_zero<[::std::os::raw::c_int]> { ::std::alloc::Layout::for_value_raw(p) } } - /// Construct a DST for `#canonical_ident` from a thin - /// pointer. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr<'a>( - ptr: *const flexarray_zero<[::std::os::raw::c_int; 0]>, - len: usize, - ) -> &'a Self { - let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); - &*ptr + pub fn fixed(&self) -> (&flexarray_zero<[::std::os::raw::c_int; 0]>, usize) { + unsafe { + let (ptr, len) = (self as *const Self).to_raw_parts(); + (&*(ptr as *const flexarray_zero<[::std::os::raw::c_int; 0]>), len) + } } - /// Construct a mutable DST for `#canonical_ident` from - /// a thin pointer. This is `MaybeUninit` to allow for - /// initialization. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr_mut<'a>( - ptr: *mut flexarray_zero<[::std::os::raw::c_int; 0]>, - len: usize, - ) -> ::std::mem::MaybeUninit<&'a mut Self> { - let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); - ::std::mem::MaybeUninit::new(&mut *ptr) + pub fn fixed_mut( + &mut self, + ) -> (&mut flexarray_zero<[::std::os::raw::c_int; 0]>, usize) { + unsafe { + let (ptr, len) = (self as *mut Self).to_raw_parts(); + (&mut *(ptr as *mut flexarray_zero<[::std::os::raw::c_int; 0]>), len) + } } } impl flexarray_zero<[::std::os::raw::c_int; 0]> { - /// Turn a sized reference for `#canonical_ident` into - /// DST with the given `len`. + /// Convert a sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref( + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_ref( &self, len: usize, ) -> &flexarray_zero<[::std::os::raw::c_int]> { - unsafe { flexarray_zero::<[::std::os::raw::c_int]>::from_ptr(self, len) } + unsafe { Self::flex_ptr(self, len) } } - /// Turn a mutable sized reference for - /// `#canonical_ident` into DST with the given `len`. + /// Convert a mutable sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref_mut( + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_mut_ref( &mut self, len: usize, ) -> &mut flexarray_zero<[::std::os::raw::c_int]> { + unsafe { Self::flex_ptr_mut(self, len).assume_init() } + } + /// Construct DST variant from a pointer and a size. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + pub unsafe fn flex_ptr<'unbounded>( + ptr: *const Self, + len: usize, + ) -> &'unbounded flexarray_zero<[::std::os::raw::c_int]> { + unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + } + /// Construct mutable DST variant from a pointer and a + /// size. The returned `&mut` reference is initialized + /// pointing to memory referenced by `ptr`, but there's + /// no requirement that that memory be initialized. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + pub unsafe fn flex_ptr_mut<'unbounded>( + ptr: *mut Self, + len: usize, + ) -> ::std::mem::MaybeUninit< + &'unbounded mut flexarray_zero<[::std::os::raw::c_int]>, + > { unsafe { - flexarray_zero::<[::std::os::raw::c_int]>::from_ptr_mut(self, len) - .assume_init() + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray_zero<[::std::os::raw::c_int]>, + >::uninit(); + (uninit.as_mut_ptr() as *mut *mut flexarray_zero<[::std::os::raw::c_int]>) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit } } } @@ -219,49 +248,64 @@ impl flexarray_template { ::std::alloc::Layout::for_value_raw(p) } } - /// Construct a DST for `#canonical_ident` from a thin - /// pointer. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr<'a>( - ptr: *const flexarray_template, - len: usize, - ) -> &'a Self { - let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); - &*ptr + pub fn fixed(&self) -> (&flexarray_template, usize) { + unsafe { + let (ptr, len) = (self as *const Self).to_raw_parts(); + (&*(ptr as *const flexarray_template), len) + } } - /// Construct a mutable DST for `#canonical_ident` from - /// a thin pointer. This is `MaybeUninit` to allow for - /// initialization. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr_mut<'a>( - ptr: *mut flexarray_template, - len: usize, - ) -> ::std::mem::MaybeUninit<&'a mut Self> { - let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); - ::std::mem::MaybeUninit::new(&mut *ptr) + pub fn fixed_mut(&mut self) -> (&mut flexarray_template, usize) { + unsafe { + let (ptr, len) = (self as *mut Self).to_raw_parts(); + (&mut *(ptr as *mut flexarray_template), len) + } } } impl flexarray_template { - /// Turn a sized reference for `#canonical_ident` into - /// DST with the given `len`. + /// Convert a sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref(&self, len: usize) -> &flexarray_template { - unsafe { flexarray_template::::from_ptr(self, len) } + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_ref(&self, len: usize) -> &flexarray_template { + unsafe { Self::flex_ptr(self, len) } } - /// Turn a mutable sized reference for - /// `#canonical_ident` into DST with the given `len`. + /// Convert a mutable sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref_mut( + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_mut_ref( &mut self, len: usize, ) -> &mut flexarray_template { - unsafe { flexarray_template::::from_ptr_mut(self, len).assume_init() } + unsafe { Self::flex_ptr_mut(self, len).assume_init() } + } + /// Construct DST variant from a pointer and a size. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + pub unsafe fn flex_ptr<'unbounded>( + ptr: *const Self, + len: usize, + ) -> &'unbounded flexarray_template { + unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + } + /// Construct mutable DST variant from a pointer and a + /// size. The returned `&mut` reference is initialized + /// pointing to memory referenced by `ptr`, but there's + /// no requirement that that memory be initialized. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + pub unsafe fn flex_ptr_mut<'unbounded>( + ptr: *mut Self, + len: usize, + ) -> ::std::mem::MaybeUninit<&'unbounded mut flexarray_template> { + unsafe { + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray_template, + >::uninit(); + (uninit.as_mut_ptr() as *mut *mut flexarray_template) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit + } } } impl Default for flexarray_template { @@ -366,56 +410,80 @@ impl flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { ::std::alloc::Layout::for_value_raw(p) } } - /// Construct a DST for `#canonical_ident` from a thin - /// pointer. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr<'a>( - ptr: *const flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>, - len: usize, - ) -> &'a Self { - let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); - &*ptr + pub fn fixed( + &self, + ) -> (&flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>, usize) { + unsafe { + let (ptr, len) = (self as *const Self).to_raw_parts(); + ( + &*(ptr as *const flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>), + len, + ) + } } - /// Construct a mutable DST for `#canonical_ident` from - /// a thin pointer. This is `MaybeUninit` to allow for - /// initialization. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr_mut<'a>( - ptr: *mut flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>, - len: usize, - ) -> ::std::mem::MaybeUninit<&'a mut Self> { - let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); - ::std::mem::MaybeUninit::new(&mut *ptr) + pub fn fixed_mut( + &mut self, + ) -> (&mut flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>, usize) { + unsafe { + let (ptr, len) = (self as *mut Self).to_raw_parts(); + ( + &mut *(ptr + as *mut flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>), + len, + ) + } } } impl flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]> { - /// Turn a sized reference for `#canonical_ident` into - /// DST with the given `len`. + /// Convert a sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref( + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_ref( &self, len: usize, ) -> &flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { - unsafe { - flexarray_bogus_zero_fam::<[::std::os::raw::c_char]>::from_ptr(self, len) - } + unsafe { Self::flex_ptr(self, len) } } - /// Turn a mutable sized reference for - /// `#canonical_ident` into DST with the given `len`. + /// Convert a mutable sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref_mut( + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_mut_ref( &mut self, len: usize, ) -> &mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { + unsafe { Self::flex_ptr_mut(self, len).assume_init() } + } + /// Construct DST variant from a pointer and a size. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + pub unsafe fn flex_ptr<'unbounded>( + ptr: *const Self, + len: usize, + ) -> &'unbounded flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { + unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + } + /// Construct mutable DST variant from a pointer and a + /// size. The returned `&mut` reference is initialized + /// pointing to memory referenced by `ptr`, but there's + /// no requirement that that memory be initialized. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + pub unsafe fn flex_ptr_mut<'unbounded>( + ptr: *mut Self, + len: usize, + ) -> ::std::mem::MaybeUninit< + &'unbounded mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]>, + > { unsafe { - flexarray_bogus_zero_fam::<[::std::os::raw::c_char]>::from_ptr_mut(self, len) - .assume_init() + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]>, + >::uninit(); + (uninit.as_mut_ptr() + as *mut *mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]>) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit } } } @@ -463,54 +531,70 @@ impl flexarray_align<[::std::os::raw::c_int]> { ::std::alloc::Layout::for_value_raw(p) } } - /// Construct a DST for `#canonical_ident` from a thin - /// pointer. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr<'a>( - ptr: *const flexarray_align<[::std::os::raw::c_int; 0]>, - len: usize, - ) -> &'a Self { - let ptr: *const Self = ::std::ptr::from_raw_parts(ptr as *const (), len); - &*ptr + pub fn fixed(&self) -> (&flexarray_align<[::std::os::raw::c_int; 0]>, usize) { + unsafe { + let (ptr, len) = (self as *const Self).to_raw_parts(); + (&*(ptr as *const flexarray_align<[::std::os::raw::c_int; 0]>), len) + } } - /// Construct a mutable DST for `#canonical_ident` from - /// a thin pointer. This is `MaybeUninit` to allow for - /// initialization. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr_mut<'a>( - ptr: *mut flexarray_align<[::std::os::raw::c_int; 0]>, - len: usize, - ) -> ::std::mem::MaybeUninit<&'a mut Self> { - let ptr: *mut Self = ::std::ptr::from_raw_parts_mut(ptr as *mut (), len); - ::std::mem::MaybeUninit::new(&mut *ptr) + pub fn fixed_mut( + &mut self, + ) -> (&mut flexarray_align<[::std::os::raw::c_int; 0]>, usize) { + unsafe { + let (ptr, len) = (self as *mut Self).to_raw_parts(); + (&mut *(ptr as *mut flexarray_align<[::std::os::raw::c_int; 0]>), len) + } } } impl flexarray_align<[::std::os::raw::c_int; 0]> { - /// Turn a sized reference for `#canonical_ident` into - /// DST with the given `len`. + /// Convert a sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref( + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_ref( &self, len: usize, ) -> &flexarray_align<[::std::os::raw::c_int]> { - unsafe { flexarray_align::<[::std::os::raw::c_int]>::from_ptr(self, len) } + unsafe { Self::flex_ptr(self, len) } } - /// Turn a mutable sized reference for - /// `#canonical_ident` into DST with the given `len`. + /// Convert a mutable sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref_mut( + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_mut_ref( &mut self, len: usize, ) -> &mut flexarray_align<[::std::os::raw::c_int]> { + unsafe { Self::flex_ptr_mut(self, len).assume_init() } + } + /// Construct DST variant from a pointer and a size. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + pub unsafe fn flex_ptr<'unbounded>( + ptr: *const Self, + len: usize, + ) -> &'unbounded flexarray_align<[::std::os::raw::c_int]> { + unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + } + /// Construct mutable DST variant from a pointer and a + /// size. The returned `&mut` reference is initialized + /// pointing to memory referenced by `ptr`, but there's + /// no requirement that that memory be initialized. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + pub unsafe fn flex_ptr_mut<'unbounded>( + ptr: *mut Self, + len: usize, + ) -> ::std::mem::MaybeUninit< + &'unbounded mut flexarray_align<[::std::os::raw::c_int]>, + > { unsafe { - flexarray_align::<[::std::os::raw::c_int]>::from_ptr_mut(self, len) - .assume_init() + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray_align<[::std::os::raw::c_int]>, + >::uninit(); + (uninit.as_mut_ptr() as *mut *mut flexarray_align<[::std::os::raw::c_int]>) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit } } } diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 2c6aafe5a2..a0a57f1608 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -2607,10 +2607,6 @@ impl CodeGenerator for CompInfo { #canonical_ident < #( #generic_param_names , )* [ #flex_inner_ty; 0 ] > }; - let turbo_dst_ty = quote! { - #canonical_ident :: < #( #generic_param_names , )* [ #flex_inner_ty ] > - }; - let layout = if ctx.options().rust_features().layout_for_ptr { quote! { pub fn layout(len: usize) -> ::#prefix::alloc::Layout { @@ -2632,43 +2628,65 @@ impl CodeGenerator for CompInfo { { ( quote! { - /// Construct a DST for `#canonical_ident` from a thin - /// pointer. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr<'a>(ptr: *const #sized_ty_for_impl, len: usize) -> &'a Self { - let ptr: *const Self = ::#prefix::ptr::from_raw_parts(ptr as *const (), len); - &*ptr + pub fn fixed(&self) -> (& #sized_ty_for_impl, usize) { + unsafe { + let (ptr, len) = (self as *const Self).to_raw_parts(); + (&*(ptr as *const #sized_ty_for_impl), len) + } } - /// Construct a mutable DST for `#canonical_ident` from - /// a thin pointer. This is `MaybeUninit` to allow for - /// initialization. - /// - /// SAFETY: the `len` must be <= the underlying storage. - /// Note: returned lifetime is unbounded. - pub unsafe fn from_ptr_mut<'a>(ptr: *mut #sized_ty_for_impl, len: usize) -> ::#prefix::mem::MaybeUninit<&'a mut Self> { - let ptr: *mut Self = ::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len); - ::#prefix::mem::MaybeUninit::new(&mut *ptr) + pub fn fixed_mut(&mut self) -> (&mut #sized_ty_for_impl, usize) { + unsafe { + let (ptr, len) = (self as *mut Self).to_raw_parts(); + (&mut *(ptr as *mut #sized_ty_for_impl), len) + + } } }, quote! { - /// Turn a sized reference for `#canonical_ident` into - /// DST with the given `len`. + /// Convert a sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref(&self, len: usize) -> & #dst_ty_for_impl { - // SAFETY: caller guarantees `len` is good - unsafe { #turbo_dst_ty :: from_ptr(self, len) } + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_ref(&self, len: usize) -> &#dst_ty_for_impl { + // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. + unsafe { Self::flex_ptr(self, len) } } - /// Turn a mutable sized reference for - /// `#canonical_ident` into DST with the given `len`. + /// Convert a mutable sized prefix to an unsized structure with the given length. /// - /// SAFETY: the `len` must be <= the underlying storage. - pub unsafe fn from_ref_mut(&mut self, len: usize) -> &mut #dst_ty_for_impl { - unsafe { #turbo_dst_ty :: from_ptr_mut(self, len).assume_init() } + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_mut_ref(&mut self, len: usize) -> &mut #dst_ty_for_impl { + // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. + unsafe { Self::flex_ptr_mut(self, len).assume_init() } + } + + /// Construct DST variant from a pointer and a size. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + pub unsafe fn flex_ptr<'unbounded>(ptr: *const Self, len: usize) -> &'unbounded #dst_ty_for_impl { + unsafe { &*::#prefix::ptr::from_raw_parts(ptr as *const (), len) } + } + + /// Construct mutable DST variant from a pointer and a + /// size. The returned `&mut` reference is initialized + /// pointing to memory referenced by `ptr`, but there's + /// no requirement that that memory be initialized. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + pub unsafe fn flex_ptr_mut<'unbounded>( + ptr: *mut Self, + len: usize, + ) -> ::#prefix::mem::MaybeUninit<&'unbounded mut #dst_ty_for_impl> { + unsafe { + // Initialize reference without ever exposing it, as its possibly uninitialized + let mut uninit = ::#prefix::mem::MaybeUninit::<&mut #dst_ty_for_impl>::uninit(); + (uninit.as_mut_ptr() as *mut *mut #dst_ty_for_impl) + .write(::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len)); + + uninit + } } }, ) From c6c141d1699a240fbec3007e7fc315f87220bae6 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 5 Mar 2024 19:34:07 -0800 Subject: [PATCH 05/10] Add documentation --- book/src/SUMMARY.md | 1 + book/src/using-fam.md | 163 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 book/src/using-fam.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index dbdf3f700c..daaed04081 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -27,4 +27,5 @@ - [Generating Bindings to Objective-c](./objc.md) - [Using Unions](./using-unions.md) - [Using Bitfields](./using-bitfields.md) +- [Using Flexible Array Members](./using-fam.md) - [FAQ](./faq.md) diff --git a/book/src/using-fam.md b/book/src/using-fam.md new file mode 100644 index 0000000000..473a1764e2 --- /dev/null +++ b/book/src/using-fam.md @@ -0,0 +1,163 @@ +# Using C structures with Flexible Array Members + +Since time immemorial, C programmers have been using what was called "the struct +hack". This is a technique for packing a fixed-size structure and a +variable-sized tail within the same memory allocation. Typically this looks +like: + +```c +struct MyRecord { + time_t timestamp; + unsigned seq; + size_t len; + char payload[0]; +}; +``` + +Because this is so useful, it was standardized in C99 as "flexible array +members", using almost identical syntax: +```c +struct MyRecord { + time_t timestamp; + unsigned seq; + size_t len; + char payload[]; // NOTE: empty [] +}; +``` + +Bindgen supports these structures in two different ways. + +## `__IncompleteArrayField` + +By default, bindgen will the corresponding Rust structure: +```rust,ignore +#[repr(C)] +struct MyRecord { + pub timestamp: time_t, + pub seq: ::std::os::raw::c_uint, + pub len: usize, + pub payload: __IncompleteArrayField<::std::os::raw::c_char>, +} +``` + +The `__IncompleteArrayField` type is zero-sized, so this structure represents +the prefix without any trailing data. In order to access that data, it provides +the `as_slice` unsafe method: +```rust,ignore + // SAFETY: there's at least `len` bytes allocated and initialized after `myrecord` + let payload = unsafe { myrecord.payload.as_slice(myrecord.len) }; +``` +There's also `as_mut_slice` which does the obvious. + +These are `unsafe` simply because it's up to you to provide the right length (in +elements of whatever type `payload` is) as there's no way for Rust or Bindgen to +know. In this example, the length is a very straightforward `len` field in the +structure, but it could be encoded in any number of ways within the structure, +or come from somewhere else entirely. + +One big caveat with this technique is that `std::mem::size_of` (or +`size_of_val`) will *only* include the size of the prefix structure. if you're +working out how much storage the whole structure is using, you'll need to add +the suffix yourself. + +## Using Dynamically Sized Types + +If you invoke bindgen with the `--flexarray-dst` option, it will generate +something not quite like this: + +```rust,ignore +#[repr(C)] +struct MyRecord { + pub timestamp: time_t, + pub seq: ::std::os::raw::c_uint, + pub len: usize, + pub payload: [::std::os::raw::c_char], +} +``` +Rust has a set of types which are almost exact analogs for these Flexible Array +Member types: the Dynamically Sized Type ("DST"). For example: + +This looks almost identical to a normal Rust structure, except that you'll note +the type of the `payload` field is a raw slice `[...]` rather than the usual +reference to slice `&[...]`. + +That `payload: [c_char]` is telling Rust that it can't directly know the total +size of this structure - the `payload` field takes an amount of space that's +determined at runtime. This means you can't directly use values of this type, +only references: `&MyRecord`. + +In practice, this is very awkward. So instead, bindgen generates: +```rust,ignore +#[repr(C)] +struct MyRecord { + pub timestamp: time_t, + pub seq: ::std::os::raw::c_uint, + pub len: usize, + pub payload: FAM, +} +``` + +That is: +1. a type parameter `FAM` which represents the type of the `payload` field, +2. it's `?Sized` meaning it can be unsigned (ie, a DST) +3. it has the default type of `[c_char; 0]` - that is a zero-sized array of characters + +This means that referencing plain `MyRecord` will be exactly like `MyRecord` +with `__IncompleteArrayField`: it is a fixed-sized structure which you can +manipulate like a normal Rust value. + +But how do you get to the DST part? + +Bindgen will also implement a set of helper methods for this: + +```rust,ignore +// Static sized variant +impl MyRecord<[::std::os::raw::c_char; 0]> { + pub unsafe fn flex_ref(&self, len: usize) -> &MyRecord<[::std::os::raw::c_char]> { ... } + pub unsafe fn flex_mut_ref(&mut self, len: usize) -> &mut MyRecord<[::std::os::raw::c_char]> { ... } + // And some raw pointer variants +} +``` +These will take a sized `MyRecord<[c_char; 0]>` and a length in elements, and +return a reference to a DST `MyRecord<[c_char]>` where the `payload` field is a +fully usable slice of `len` characters. + +The magic here is that the reference is a fat pointer, which not only encodes +the address, but also the dynamic size of the final field, just like a reference +to a slice is. This means that you get full bounds checked access to the +`payload` field like any other Rust slice. + +It also means that doing `mem::size_of_val(myrecord)` will return the *complete* +size of this structure, including the suffix. + +You can go the other way: +```rust,ignore +// Dynamic sized variant +impl MyRecord<[::std::os::raw::c_char]> { + pub fn fixed(&self) -> (&MyRecord<[::std::os::raw::c_char; 0]>, usize) { ... } + pub fn fixed_mut(&mut self) -> (&mut MyRecord<[::std::os::raw::c_char; 0]>, usize) { ... } + pub fn layout(len: usize) -> std::alloc::Layout { ... } +} +``` +which takes the DST variant of the structure and returns the sized variant, +along with the number of elements are after it. These are all completely safe +because all the information needed is part of the fat `&self` reference. + +The `layout` function takes a length and returns the `Layout` - that is, size +and alignment, so that you can allocate memory for the structure (for example, +using `malloc` so you can pass it to a C function). + +Unfortunately the language features needed to support these methods are still unstable: +- [ptr_metadata](https://doc.rust-lang.org/beta/unstable-book/library-features/ptr-metadata.html), + which enables all the fixed<->DST conversions, and +- [layout_for_ptr](https://doc.rust-lang.org/beta/unstable-book/library-features/layout-for-ptr.html), + which allows he `layout` method + +As a result, if you don't specify `--rust-target nightly` you'll just get the +bare type definitions, but no real way to use them. It's often convenient to add +the +```bash +--raw-line '#![feature(ptr_metadata,layout_for_ptr)]' +``` +option if you're generating Rust as a stand-alone crate. Otherwise you'll need +to add the feature line to your containing crate. From d2f810ec21de95f5e645c4f80906db875d8cb431 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 19 Mar 2024 14:49:02 -0700 Subject: [PATCH 06/10] Update with review comments --- bindgen/codegen/mod.rs | 242 ++++++++++++++++++++++------------------- bindgen/ir/comp.rs | 7 +- 2 files changed, 133 insertions(+), 116 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index a0a57f1608..fd6d877042 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -1693,7 +1693,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, - _last_field: bool, + last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, @@ -1775,7 +1775,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { accessor_kind, parent, parent_item, - idx == bfields.len() - 1, + last_field && idx == bfields.len() - 1, result, struct_layout, fields, @@ -2594,116 +2594,13 @@ impl CodeGenerator for CompInfo { } if needs_flexarray_impl { - let prefix = ctx.trait_prefix(); - - let flex_array = - flex_inner_ty.as_ref().map(|ty| quote! { [ #ty ] }); - - let dst_ty_for_impl = quote! { - #canonical_ident < #( #generic_param_names , )* #flex_array > - - }; - let sized_ty_for_impl = quote! { - #canonical_ident < #( #generic_param_names , )* [ #flex_inner_ty; 0 ] > - }; - - let layout = if ctx.options().rust_features().layout_for_ptr { - quote! { - pub fn layout(len: usize) -> ::#prefix::alloc::Layout { - // SAFETY: Null pointers are OK if we don't deref them - unsafe { - let p: *const Self = ::#prefix::ptr::from_raw_parts(::#prefix::ptr::null(), len); - ::#prefix::alloc::Layout::for_value_raw(p) - } - } - } - } else { - quote!() - }; - - let (from_ptr_dst, from_ptr_sized) = if ctx - .options() - .rust_features() - .ptr_metadata - { - ( - quote! { - pub fn fixed(&self) -> (& #sized_ty_for_impl, usize) { - unsafe { - let (ptr, len) = (self as *const Self).to_raw_parts(); - (&*(ptr as *const #sized_ty_for_impl), len) - } - } - - pub fn fixed_mut(&mut self) -> (&mut #sized_ty_for_impl, usize) { - unsafe { - let (ptr, len) = (self as *mut Self).to_raw_parts(); - (&mut *(ptr as *mut #sized_ty_for_impl), len) - - } - } - }, - quote! { - /// Convert a sized prefix to an unsized structure with the given length. - /// - /// SAFETY: Underlying storage is initialized up to at least `len` elements. - pub unsafe fn flex_ref(&self, len: usize) -> &#dst_ty_for_impl { - // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. - unsafe { Self::flex_ptr(self, len) } - } - - /// Convert a mutable sized prefix to an unsized structure with the given length. - /// - /// SAFETY: Underlying storage is initialized up to at least `len` elements. - pub unsafe fn flex_mut_ref(&mut self, len: usize) -> &mut #dst_ty_for_impl { - // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. - unsafe { Self::flex_ptr_mut(self, len).assume_init() } - } - - /// Construct DST variant from a pointer and a size. - /// - /// NOTE: lifetime of returned reference is not tied to any underlying storage. - /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. - pub unsafe fn flex_ptr<'unbounded>(ptr: *const Self, len: usize) -> &'unbounded #dst_ty_for_impl { - unsafe { &*::#prefix::ptr::from_raw_parts(ptr as *const (), len) } - } - - /// Construct mutable DST variant from a pointer and a - /// size. The returned `&mut` reference is initialized - /// pointing to memory referenced by `ptr`, but there's - /// no requirement that that memory be initialized. - /// - /// NOTE: lifetime of returned reference is not tied to any underlying storage. - /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. - pub unsafe fn flex_ptr_mut<'unbounded>( - ptr: *mut Self, - len: usize, - ) -> ::#prefix::mem::MaybeUninit<&'unbounded mut #dst_ty_for_impl> { - unsafe { - // Initialize reference without ever exposing it, as its possibly uninitialized - let mut uninit = ::#prefix::mem::MaybeUninit::<&mut #dst_ty_for_impl>::uninit(); - (uninit.as_mut_ptr() as *mut *mut #dst_ty_for_impl) - .write(::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len)); - - uninit - } - } - }, - ) - } else { - (quote!(), quote!()) - }; - - result.push(quote! { - impl #impl_generics_labels #dst_ty_for_impl { - #layout - #from_ptr_dst - } - - impl #impl_generics_labels #sized_ty_for_impl { - #from_ptr_sized - } - }); + result.push(self.generate_flexarray( + ctx, + &canonical_ident, + flex_inner_ty, + &*generic_param_names, + &impl_generics_labels, + )); } if needs_default_impl { @@ -2790,6 +2687,127 @@ impl CodeGenerator for CompInfo { } } +impl CompInfo { + fn generate_flexarray( + &self, + ctx: &BindgenContext, + canonical_ident: &Ident, + flex_inner_ty: Option, + generic_param_names: &[Ident], + impl_generics_labels: &proc_macro2::TokenStream, + ) -> proc_macro2::TokenStream { + let prefix = ctx.trait_prefix(); + + let flex_array = flex_inner_ty.as_ref().map(|ty| quote! { [ #ty ] }); + + let dst_ty_for_impl = quote! { + #canonical_ident < #( #generic_param_names , )* #flex_array > + + }; + let sized_ty_for_impl = quote! { + #canonical_ident < #( #generic_param_names , )* [ #flex_inner_ty; 0 ] > + }; + + let layout = if ctx.options().rust_features().layout_for_ptr { + quote! { + pub fn layout(len: usize) -> ::#prefix::alloc::Layout { + // SAFETY: Null pointers are OK if we don't deref them + unsafe { + let p: *const Self = ::#prefix::ptr::from_raw_parts(::#prefix::ptr::null(), len); + ::#prefix::alloc::Layout::for_value_raw(p) + } + } + } + } else { + quote!() + }; + + let (from_ptr_dst, from_ptr_sized) = if ctx + .options() + .rust_features() + .ptr_metadata + { + ( + quote! { + pub fn fixed(&self) -> (& #sized_ty_for_impl, usize) { + unsafe { + let (ptr, len) = (self as *const Self).to_raw_parts(); + (&*(ptr as *const #sized_ty_for_impl), len) + } + } + + pub fn fixed_mut(&mut self) -> (&mut #sized_ty_for_impl, usize) { + unsafe { + let (ptr, len) = (self as *mut Self).to_raw_parts(); + (&mut *(ptr as *mut #sized_ty_for_impl), len) + + } + } + }, + quote! { + /// Convert a sized prefix to an unsized structure with the given length. + /// + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_ref(&self, len: usize) -> &#dst_ty_for_impl { + // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. + unsafe { Self::flex_ptr(self, len) } + } + + /// Convert a mutable sized prefix to an unsized structure with the given length. + /// + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_mut_ref(&mut self, len: usize) -> &mut #dst_ty_for_impl { + // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. + unsafe { Self::flex_ptr_mut(self, len).assume_init() } + } + + /// Construct DST variant from a pointer and a size. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + pub unsafe fn flex_ptr<'unbounded>(ptr: *const Self, len: usize) -> &'unbounded #dst_ty_for_impl { + unsafe { &*::#prefix::ptr::from_raw_parts(ptr as *const (), len) } + } + + /// Construct mutable DST variant from a pointer and a + /// size. The returned `&mut` reference is initialized + /// pointing to memory referenced by `ptr`, but there's + /// no requirement that that memory be initialized. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + pub unsafe fn flex_ptr_mut<'unbounded>( + ptr: *mut Self, + len: usize, + ) -> ::#prefix::mem::MaybeUninit<&'unbounded mut #dst_ty_for_impl> { + unsafe { + // Initialize reference without ever exposing it, as its possibly uninitialized + let mut uninit = ::#prefix::mem::MaybeUninit::<&mut #dst_ty_for_impl>::uninit(); + (uninit.as_mut_ptr() as *mut *mut #dst_ty_for_impl) + .write(::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len)); + + uninit + } + } + }, + ) + } else { + (quote!(), quote!()) + }; + + quote! { + impl #impl_generics_labels #dst_ty_for_impl { + #layout + #from_ptr_dst + } + + impl #impl_generics_labels #sized_ty_for_impl { + #from_ptr_sized + } + } + } +} + impl Method { fn codegen_method( &self, diff --git a/bindgen/ir/comp.rs b/bindgen/ir/comp.rs index 5ae2d68747..f6c9e629a1 100644 --- a/bindgen/ir/comp.rs +++ b/bindgen/ir/comp.rs @@ -834,10 +834,9 @@ impl CompFields { CompFields::Error => return None, // panic? }; - // XXX correct with padding on end? - match fields.last() { - None | Some(Field::Bitfields(..)) => None, - Some(Field::DataMember(FieldData { ty, .. })) => ctx + match fields.last()? { + Field::Bitfields(..) => None, + Field::DataMember(FieldData { ty, .. }) => ctx .resolve_type(*ty) .is_incomplete_array(ctx) .map(|item| item.expect_type_id(ctx)), From 75e42d76934e34051c4743b39234802a3ba0d23a Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 20 Mar 2024 09:00:46 -0700 Subject: [PATCH 07/10] Small doc tweaks --- book/src/using-fam.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/book/src/using-fam.md b/book/src/using-fam.md index 473a1764e2..aaf19c90fd 100644 --- a/book/src/using-fam.md +++ b/book/src/using-fam.md @@ -29,7 +29,7 @@ Bindgen supports these structures in two different ways. ## `__IncompleteArrayField` -By default, bindgen will the corresponding Rust structure: +By default, bindgen will generate the corresponding Rust structure: ```rust,ignore #[repr(C)] struct MyRecord { @@ -75,7 +75,7 @@ struct MyRecord { } ``` Rust has a set of types which are almost exact analogs for these Flexible Array -Member types: the Dynamically Sized Type ("DST"). For example: +Member types: the Dynamically Sized Type ("DST"). This looks almost identical to a normal Rust structure, except that you'll note the type of the `payload` field is a raw slice `[...]` rather than the usual @@ -99,7 +99,7 @@ struct MyRecord { That is: 1. a type parameter `FAM` which represents the type of the `payload` field, -2. it's `?Sized` meaning it can be unsigned (ie, a DST) +2. it's `?Sized` meaning it can be unsized (ie, a DST) 3. it has the default type of `[c_char; 0]` - that is a zero-sized array of characters This means that referencing plain `MyRecord` will be exactly like `MyRecord` From 998c8a5061dc2380f91331ff203fb7fae1323668 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 27 Mar 2024 12:36:07 -0700 Subject: [PATCH 08/10] Honour --wrap-unsafe-ops Previously it was generating inner `unsafe` blocks for all unsafe functions in conformance with Rust 2024, but now only do it when `--wrap-unsafe-ops` is enabled for consistency with other generated code. Also rename `flex_mut_ref` -> `flex_ref_mut` to make it consistent with `flex_ptr_mut` and general Rust convention. --- .../tests/expectations/tests/flexarray.rs | 112 ++++++++---------- bindgen/codegen/mod.rs | 36 ++++-- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/bindgen-tests/tests/expectations/tests/flexarray.rs b/bindgen-tests/tests/expectations/tests/flexarray.rs index 0e735317ba..46579f2cf2 100644 --- a/bindgen-tests/tests/expectations/tests/flexarray.rs +++ b/bindgen-tests/tests/expectations/tests/flexarray.rs @@ -87,16 +87,16 @@ impl flexarray<[::std::os::raw::c_int; 0]> { /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. pub unsafe fn flex_ref(&self, len: usize) -> &flexarray<[::std::os::raw::c_int]> { - unsafe { Self::flex_ptr(self, len) } + Self::flex_ptr(self, len) } /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. - pub unsafe fn flex_mut_ref( + pub unsafe fn flex_ref_mut( &mut self, len: usize, ) -> &mut flexarray<[::std::os::raw::c_int]> { - unsafe { Self::flex_ptr_mut(self, len).assume_init() } + Self::flex_ptr_mut(self, len).assume_init() } /// Construct DST variant from a pointer and a size. /// @@ -106,7 +106,7 @@ impl flexarray<[::std::os::raw::c_int; 0]> { ptr: *const Self, len: usize, ) -> &'unbounded flexarray<[::std::os::raw::c_int]> { - unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + &*::std::ptr::from_raw_parts(ptr as *const (), len) } /// Construct mutable DST variant from a pointer and a /// size. The returned `&mut` reference is initialized @@ -119,14 +119,12 @@ impl flexarray<[::std::os::raw::c_int; 0]> { ptr: *mut Self, len: usize, ) -> ::std::mem::MaybeUninit<&'unbounded mut flexarray<[::std::os::raw::c_int]>> { - unsafe { - let mut uninit = ::std::mem::MaybeUninit::< - &mut flexarray<[::std::os::raw::c_int]>, - >::uninit(); - (uninit.as_mut_ptr() as *mut *mut flexarray<[::std::os::raw::c_int]>) - .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); - uninit - } + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray<[::std::os::raw::c_int]>, + >::uninit(); + (uninit.as_mut_ptr() as *mut *mut flexarray<[::std::os::raw::c_int]>) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit } } #[repr(C)] @@ -190,16 +188,16 @@ impl flexarray_zero<[::std::os::raw::c_int; 0]> { &self, len: usize, ) -> &flexarray_zero<[::std::os::raw::c_int]> { - unsafe { Self::flex_ptr(self, len) } + Self::flex_ptr(self, len) } /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. - pub unsafe fn flex_mut_ref( + pub unsafe fn flex_ref_mut( &mut self, len: usize, ) -> &mut flexarray_zero<[::std::os::raw::c_int]> { - unsafe { Self::flex_ptr_mut(self, len).assume_init() } + Self::flex_ptr_mut(self, len).assume_init() } /// Construct DST variant from a pointer and a size. /// @@ -209,7 +207,7 @@ impl flexarray_zero<[::std::os::raw::c_int; 0]> { ptr: *const Self, len: usize, ) -> &'unbounded flexarray_zero<[::std::os::raw::c_int]> { - unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + &*::std::ptr::from_raw_parts(ptr as *const (), len) } /// Construct mutable DST variant from a pointer and a /// size. The returned `&mut` reference is initialized @@ -224,14 +222,12 @@ impl flexarray_zero<[::std::os::raw::c_int; 0]> { ) -> ::std::mem::MaybeUninit< &'unbounded mut flexarray_zero<[::std::os::raw::c_int]>, > { - unsafe { - let mut uninit = ::std::mem::MaybeUninit::< - &mut flexarray_zero<[::std::os::raw::c_int]>, - >::uninit(); - (uninit.as_mut_ptr() as *mut *mut flexarray_zero<[::std::os::raw::c_int]>) - .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); - uninit - } + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray_zero<[::std::os::raw::c_int]>, + >::uninit(); + (uninit.as_mut_ptr() as *mut *mut flexarray_zero<[::std::os::raw::c_int]>) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit } } #[repr(C)] @@ -266,16 +262,16 @@ impl flexarray_template { /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. pub unsafe fn flex_ref(&self, len: usize) -> &flexarray_template { - unsafe { Self::flex_ptr(self, len) } + Self::flex_ptr(self, len) } /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. - pub unsafe fn flex_mut_ref( + pub unsafe fn flex_ref_mut( &mut self, len: usize, ) -> &mut flexarray_template { - unsafe { Self::flex_ptr_mut(self, len).assume_init() } + Self::flex_ptr_mut(self, len).assume_init() } /// Construct DST variant from a pointer and a size. /// @@ -285,7 +281,7 @@ impl flexarray_template { ptr: *const Self, len: usize, ) -> &'unbounded flexarray_template { - unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + &*::std::ptr::from_raw_parts(ptr as *const (), len) } /// Construct mutable DST variant from a pointer and a /// size. The returned `&mut` reference is initialized @@ -298,14 +294,12 @@ impl flexarray_template { ptr: *mut Self, len: usize, ) -> ::std::mem::MaybeUninit<&'unbounded mut flexarray_template> { - unsafe { - let mut uninit = ::std::mem::MaybeUninit::< - &mut flexarray_template, - >::uninit(); - (uninit.as_mut_ptr() as *mut *mut flexarray_template) - .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); - uninit - } + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray_template, + >::uninit(); + (uninit.as_mut_ptr() as *mut *mut flexarray_template) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit } } impl Default for flexarray_template { @@ -442,16 +436,16 @@ impl flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]> { &self, len: usize, ) -> &flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { - unsafe { Self::flex_ptr(self, len) } + Self::flex_ptr(self, len) } /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. - pub unsafe fn flex_mut_ref( + pub unsafe fn flex_ref_mut( &mut self, len: usize, ) -> &mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { - unsafe { Self::flex_ptr_mut(self, len).assume_init() } + Self::flex_ptr_mut(self, len).assume_init() } /// Construct DST variant from a pointer and a size. /// @@ -461,7 +455,7 @@ impl flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]> { ptr: *const Self, len: usize, ) -> &'unbounded flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { - unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + &*::std::ptr::from_raw_parts(ptr as *const (), len) } /// Construct mutable DST variant from a pointer and a /// size. The returned `&mut` reference is initialized @@ -476,15 +470,13 @@ impl flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]> { ) -> ::std::mem::MaybeUninit< &'unbounded mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]>, > { - unsafe { - let mut uninit = ::std::mem::MaybeUninit::< - &mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]>, - >::uninit(); - (uninit.as_mut_ptr() - as *mut *mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]>) - .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); - uninit - } + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]>, + >::uninit(); + (uninit.as_mut_ptr() + as *mut *mut flexarray_bogus_zero_fam<[::std::os::raw::c_char]>) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit } } #[repr(C)] @@ -554,16 +546,16 @@ impl flexarray_align<[::std::os::raw::c_int; 0]> { &self, len: usize, ) -> &flexarray_align<[::std::os::raw::c_int]> { - unsafe { Self::flex_ptr(self, len) } + Self::flex_ptr(self, len) } /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. - pub unsafe fn flex_mut_ref( + pub unsafe fn flex_ref_mut( &mut self, len: usize, ) -> &mut flexarray_align<[::std::os::raw::c_int]> { - unsafe { Self::flex_ptr_mut(self, len).assume_init() } + Self::flex_ptr_mut(self, len).assume_init() } /// Construct DST variant from a pointer and a size. /// @@ -573,7 +565,7 @@ impl flexarray_align<[::std::os::raw::c_int; 0]> { ptr: *const Self, len: usize, ) -> &'unbounded flexarray_align<[::std::os::raw::c_int]> { - unsafe { &*::std::ptr::from_raw_parts(ptr as *const (), len) } + &*::std::ptr::from_raw_parts(ptr as *const (), len) } /// Construct mutable DST variant from a pointer and a /// size. The returned `&mut` reference is initialized @@ -588,14 +580,12 @@ impl flexarray_align<[::std::os::raw::c_int; 0]> { ) -> ::std::mem::MaybeUninit< &'unbounded mut flexarray_align<[::std::os::raw::c_int]>, > { - unsafe { - let mut uninit = ::std::mem::MaybeUninit::< - &mut flexarray_align<[::std::os::raw::c_int]>, - >::uninit(); - (uninit.as_mut_ptr() as *mut *mut flexarray_align<[::std::os::raw::c_int]>) - .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); - uninit - } + let mut uninit = ::std::mem::MaybeUninit::< + &mut flexarray_align<[::std::os::raw::c_int]>, + >::uninit(); + (uninit.as_mut_ptr() as *mut *mut flexarray_align<[::std::os::raw::c_int]>) + .write(::std::ptr::from_raw_parts_mut(ptr as *mut (), len)); + uninit } } impl Default for flexarray_align<[::std::os::raw::c_int; 0]> { diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index fd6d877042..0ceac5e9ee 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -2727,6 +2727,24 @@ impl CompInfo { .rust_features() .ptr_metadata { + let flex_ref_inner = ctx.wrap_unsafe_ops(quote! { + Self::flex_ptr(self, len) + }); + let flex_ref_mut_inner = ctx.wrap_unsafe_ops(quote! { + Self::flex_ptr_mut(self, len).assume_init() + }); + let flex_ptr_inner = ctx.wrap_unsafe_ops(quote! { + &*::#prefix::ptr::from_raw_parts(ptr as *const (), len) + }); + let flex_ptr_mut_inner = ctx.wrap_unsafe_ops(quote! { + // Initialize reference without ever exposing it, as its possibly uninitialized + let mut uninit = ::#prefix::mem::MaybeUninit::<&mut #dst_ty_for_impl>::uninit(); + (uninit.as_mut_ptr() as *mut *mut #dst_ty_for_impl) + .write(::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len)); + + uninit + }); + ( quote! { pub fn fixed(&self) -> (& #sized_ty_for_impl, usize) { @@ -2740,7 +2758,6 @@ impl CompInfo { unsafe { let (ptr, len) = (self as *mut Self).to_raw_parts(); (&mut *(ptr as *mut #sized_ty_for_impl), len) - } } }, @@ -2750,15 +2767,15 @@ impl CompInfo { /// SAFETY: Underlying storage is initialized up to at least `len` elements. pub unsafe fn flex_ref(&self, len: usize) -> &#dst_ty_for_impl { // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. - unsafe { Self::flex_ptr(self, len) } + #flex_ref_inner } /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. - pub unsafe fn flex_mut_ref(&mut self, len: usize) -> &mut #dst_ty_for_impl { + pub unsafe fn flex_ref_mut(&mut self, len: usize) -> &mut #dst_ty_for_impl { // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. - unsafe { Self::flex_ptr_mut(self, len).assume_init() } + #flex_ref_mut_inner } /// Construct DST variant from a pointer and a size. @@ -2766,7 +2783,7 @@ impl CompInfo { /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. pub unsafe fn flex_ptr<'unbounded>(ptr: *const Self, len: usize) -> &'unbounded #dst_ty_for_impl { - unsafe { &*::#prefix::ptr::from_raw_parts(ptr as *const (), len) } + #flex_ptr_inner } /// Construct mutable DST variant from a pointer and a @@ -2780,14 +2797,7 @@ impl CompInfo { ptr: *mut Self, len: usize, ) -> ::#prefix::mem::MaybeUninit<&'unbounded mut #dst_ty_for_impl> { - unsafe { - // Initialize reference without ever exposing it, as its possibly uninitialized - let mut uninit = ::#prefix::mem::MaybeUninit::<&mut #dst_ty_for_impl>::uninit(); - (uninit.as_mut_ptr() as *mut *mut #dst_ty_for_impl) - .write(::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len)); - - uninit - } + #flex_ptr_mut_inner } }, ) From 81356cb0f8845e6a7ab0f7a7843e6ffb6019e559 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 27 Mar 2024 12:42:27 -0700 Subject: [PATCH 09/10] Make all the flexarray helpers inline The conversions between fixed and dynamically sized forms are essentially type-level transforms which should have trivial implementations in terms of generated code, so there's no reason not to make them inline. --- .../tests/expectations/tests/flexarray.rs | 25 +++++++++++++++++++ bindgen/codegen/mod.rs | 5 ++++ 2 files changed, 30 insertions(+) diff --git a/bindgen-tests/tests/expectations/tests/flexarray.rs b/bindgen-tests/tests/expectations/tests/flexarray.rs index 46579f2cf2..41d07311c5 100644 --- a/bindgen-tests/tests/expectations/tests/flexarray.rs +++ b/bindgen-tests/tests/expectations/tests/flexarray.rs @@ -69,12 +69,14 @@ impl flexarray<[::std::os::raw::c_int]> { ::std::alloc::Layout::for_value_raw(p) } } + #[inline] pub fn fixed(&self) -> (&flexarray<[::std::os::raw::c_int; 0]>, usize) { unsafe { let (ptr, len) = (self as *const Self).to_raw_parts(); (&*(ptr as *const flexarray<[::std::os::raw::c_int; 0]>), len) } } + #[inline] pub fn fixed_mut(&mut self) -> (&mut flexarray<[::std::os::raw::c_int; 0]>, usize) { unsafe { let (ptr, len) = (self as *mut Self).to_raw_parts(); @@ -92,6 +94,7 @@ impl flexarray<[::std::os::raw::c_int; 0]> { /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ref_mut( &mut self, len: usize, @@ -102,6 +105,7 @@ impl flexarray<[::std::os::raw::c_int; 0]> { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ptr<'unbounded>( ptr: *const Self, len: usize, @@ -115,6 +119,7 @@ impl flexarray<[::std::os::raw::c_int; 0]> { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + #[inline] pub unsafe fn flex_ptr_mut<'unbounded>( ptr: *mut Self, len: usize, @@ -165,12 +170,14 @@ impl flexarray_zero<[::std::os::raw::c_int]> { ::std::alloc::Layout::for_value_raw(p) } } + #[inline] pub fn fixed(&self) -> (&flexarray_zero<[::std::os::raw::c_int; 0]>, usize) { unsafe { let (ptr, len) = (self as *const Self).to_raw_parts(); (&*(ptr as *const flexarray_zero<[::std::os::raw::c_int; 0]>), len) } } + #[inline] pub fn fixed_mut( &mut self, ) -> (&mut flexarray_zero<[::std::os::raw::c_int; 0]>, usize) { @@ -193,6 +200,7 @@ impl flexarray_zero<[::std::os::raw::c_int; 0]> { /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ref_mut( &mut self, len: usize, @@ -203,6 +211,7 @@ impl flexarray_zero<[::std::os::raw::c_int; 0]> { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ptr<'unbounded>( ptr: *const Self, len: usize, @@ -216,6 +225,7 @@ impl flexarray_zero<[::std::os::raw::c_int; 0]> { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + #[inline] pub unsafe fn flex_ptr_mut<'unbounded>( ptr: *mut Self, len: usize, @@ -244,12 +254,14 @@ impl flexarray_template { ::std::alloc::Layout::for_value_raw(p) } } + #[inline] pub fn fixed(&self) -> (&flexarray_template, usize) { unsafe { let (ptr, len) = (self as *const Self).to_raw_parts(); (&*(ptr as *const flexarray_template), len) } } + #[inline] pub fn fixed_mut(&mut self) -> (&mut flexarray_template, usize) { unsafe { let (ptr, len) = (self as *mut Self).to_raw_parts(); @@ -267,6 +279,7 @@ impl flexarray_template { /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ref_mut( &mut self, len: usize, @@ -277,6 +290,7 @@ impl flexarray_template { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ptr<'unbounded>( ptr: *const Self, len: usize, @@ -290,6 +304,7 @@ impl flexarray_template { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + #[inline] pub unsafe fn flex_ptr_mut<'unbounded>( ptr: *mut Self, len: usize, @@ -404,6 +419,7 @@ impl flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { ::std::alloc::Layout::for_value_raw(p) } } + #[inline] pub fn fixed( &self, ) -> (&flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>, usize) { @@ -415,6 +431,7 @@ impl flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { ) } } + #[inline] pub fn fixed_mut( &mut self, ) -> (&mut flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]>, usize) { @@ -441,6 +458,7 @@ impl flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]> { /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ref_mut( &mut self, len: usize, @@ -451,6 +469,7 @@ impl flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]> { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ptr<'unbounded>( ptr: *const Self, len: usize, @@ -464,6 +483,7 @@ impl flexarray_bogus_zero_fam<[::std::os::raw::c_char; 0]> { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + #[inline] pub unsafe fn flex_ptr_mut<'unbounded>( ptr: *mut Self, len: usize, @@ -523,12 +543,14 @@ impl flexarray_align<[::std::os::raw::c_int]> { ::std::alloc::Layout::for_value_raw(p) } } + #[inline] pub fn fixed(&self) -> (&flexarray_align<[::std::os::raw::c_int; 0]>, usize) { unsafe { let (ptr, len) = (self as *const Self).to_raw_parts(); (&*(ptr as *const flexarray_align<[::std::os::raw::c_int; 0]>), len) } } + #[inline] pub fn fixed_mut( &mut self, ) -> (&mut flexarray_align<[::std::os::raw::c_int; 0]>, usize) { @@ -551,6 +573,7 @@ impl flexarray_align<[::std::os::raw::c_int; 0]> { /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ref_mut( &mut self, len: usize, @@ -561,6 +584,7 @@ impl flexarray_align<[::std::os::raw::c_int; 0]> { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ptr<'unbounded>( ptr: *const Self, len: usize, @@ -574,6 +598,7 @@ impl flexarray_align<[::std::os::raw::c_int; 0]> { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + #[inline] pub unsafe fn flex_ptr_mut<'unbounded>( ptr: *mut Self, len: usize, diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 0ceac5e9ee..070d9dec6f 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -2747,6 +2747,7 @@ impl CompInfo { ( quote! { + #[inline] pub fn fixed(&self) -> (& #sized_ty_for_impl, usize) { unsafe { let (ptr, len) = (self as *const Self).to_raw_parts(); @@ -2754,6 +2755,7 @@ impl CompInfo { } } + #[inline] pub fn fixed_mut(&mut self) -> (&mut #sized_ty_for_impl, usize) { unsafe { let (ptr, len) = (self as *mut Self).to_raw_parts(); @@ -2773,6 +2775,7 @@ impl CompInfo { /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ref_mut(&mut self, len: usize) -> &mut #dst_ty_for_impl { // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. #flex_ref_mut_inner @@ -2782,6 +2785,7 @@ impl CompInfo { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + #[inline] pub unsafe fn flex_ptr<'unbounded>(ptr: *const Self, len: usize) -> &'unbounded #dst_ty_for_impl { #flex_ptr_inner } @@ -2793,6 +2797,7 @@ impl CompInfo { /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + #[inline] pub unsafe fn flex_ptr_mut<'unbounded>( ptr: *mut Self, len: usize, From 8a7291d1387f5f1da0e71e183b3be521992e32b5 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 1 Apr 2024 15:13:09 -0700 Subject: [PATCH 10/10] Update test fixtures --- .../tests/expectations/tests/flexarray.rs | 201 +++++------------- 1 file changed, 56 insertions(+), 145 deletions(-) diff --git a/bindgen-tests/tests/expectations/tests/flexarray.rs b/bindgen-tests/tests/expectations/tests/flexarray.rs index 41d07311c5..2c47f0ec55 100644 --- a/bindgen-tests/tests/expectations/tests/flexarray.rs +++ b/bindgen-tests/tests/expectations/tests/flexarray.rs @@ -37,31 +37,16 @@ pub struct flexarray { pub count: ::std::os::raw::c_int, pub data: FAM, } -#[test] -fn bindgen_test_layout_flexarray() { - const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(flexarray)), - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(flexarray)), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, - 0usize, - concat!("Offset of field: ", stringify!(flexarray), "::", stringify!(count)), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, - 4usize, - concat!("Offset of field: ", stringify!(flexarray), "::", stringify!(data)), - ); -} +const _: () = { + ["Size of flexarray"][::std::mem::size_of::() - 4usize]; + ["Alignment of flexarray"][::std::mem::align_of::() - 4usize]; + [ + "Offset of field: flexarray::count", + ][::std::mem::offset_of!(flexarray, count) - 0usize]; + [ + "Offset of field: flexarray::data", + ][::std::mem::offset_of!(flexarray, data) - 4usize]; +}; impl flexarray<[::std::os::raw::c_int]> { pub fn layout(len: usize) -> ::std::alloc::Layout { unsafe { @@ -138,31 +123,16 @@ pub struct flexarray_zero { pub count: ::std::os::raw::c_int, pub data: FAM, } -#[test] -fn bindgen_test_layout_flexarray_zero() { - const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(flexarray_zero)), - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(flexarray_zero)), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, - 0usize, - concat!("Offset of field: ", stringify!(flexarray_zero), "::", stringify!(count)), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, - 4usize, - concat!("Offset of field: ", stringify!(flexarray_zero), "::", stringify!(data)), - ); -} +const _: () = { + ["Size of flexarray_zero"][::std::mem::size_of::() - 4usize]; + ["Alignment of flexarray_zero"][::std::mem::align_of::() - 4usize]; + [ + "Offset of field: flexarray_zero::count", + ][::std::mem::offset_of!(flexarray_zero, count) - 0usize]; + [ + "Offset of field: flexarray_zero::data", + ][::std::mem::offset_of!(flexarray_zero, data) - 4usize]; +}; impl flexarray_zero<[::std::os::raw::c_int]> { pub fn layout(len: usize) -> ::std::alloc::Layout { unsafe { @@ -331,26 +301,13 @@ impl Default for flexarray_template { pub struct flexarray_ref { pub things: *mut flexarray, } -#[test] -fn bindgen_test_layout_flexarray_ref() { - const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 8usize, - concat!("Size of: ", stringify!(flexarray_ref)), - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(flexarray_ref)), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).things) as usize - ptr as usize }, - 0usize, - concat!("Offset of field: ", stringify!(flexarray_ref), "::", stringify!(things)), - ); -} +const _: () = { + ["Size of flexarray_ref"][::std::mem::size_of::() - 8usize]; + ["Alignment of flexarray_ref"][::std::mem::align_of::() - 8usize]; + [ + "Offset of field: flexarray_ref::things", + ][::std::mem::offset_of!(flexarray_ref, things) - 0usize]; +}; impl Default for flexarray_ref { fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); @@ -367,51 +324,23 @@ pub struct flexarray_bogus_zero_fam { pub data1: __IncompleteArrayField<::std::os::raw::c_int>, pub data2: FAM, } -#[test] -fn bindgen_test_layout_flexarray_bogus_zero_fam() { - const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(flexarray_bogus_zero_fam)), - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(flexarray_bogus_zero_fam)), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(flexarray_bogus_zero_fam), - "::", - stringify!(count), - ), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).data1) as usize - ptr as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(flexarray_bogus_zero_fam), - "::", - stringify!(data1), - ), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).data2) as usize - ptr as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(flexarray_bogus_zero_fam), - "::", - stringify!(data2), - ), - ); -} +const _: () = { + [ + "Size of flexarray_bogus_zero_fam", + ][::std::mem::size_of::() - 4usize]; + [ + "Alignment of flexarray_bogus_zero_fam", + ][::std::mem::align_of::() - 4usize]; + [ + "Offset of field: flexarray_bogus_zero_fam::count", + ][::std::mem::offset_of!(flexarray_bogus_zero_fam, count) - 0usize]; + [ + "Offset of field: flexarray_bogus_zero_fam::data1", + ][::std::mem::offset_of!(flexarray_bogus_zero_fam, data1) - 4usize]; + [ + "Offset of field: flexarray_bogus_zero_fam::data2", + ][::std::mem::offset_of!(flexarray_bogus_zero_fam, data2) - 4usize]; +}; impl flexarray_bogus_zero_fam<[::std::os::raw::c_char]> { pub fn layout(len: usize) -> ::std::alloc::Layout { unsafe { @@ -506,36 +435,18 @@ pub struct flexarray_align { pub count: ::std::os::raw::c_int, pub data: FAM, } -#[test] -fn bindgen_test_layout_flexarray_align() { - const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 128usize, - concat!("Size of: ", stringify!(flexarray_align)), - ); - assert_eq!( - ::std::mem::align_of::(), - 128usize, - concat!("Alignment of ", stringify!(flexarray_align)), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).count) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(flexarray_align), - "::", - stringify!(count), - ), - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, - 4usize, - concat!("Offset of field: ", stringify!(flexarray_align), "::", stringify!(data)), - ); -} +const _: () = { + ["Size of flexarray_align"][::std::mem::size_of::() - 128usize]; + [ + "Alignment of flexarray_align", + ][::std::mem::align_of::() - 128usize]; + [ + "Offset of field: flexarray_align::count", + ][::std::mem::offset_of!(flexarray_align, count) - 0usize]; + [ + "Offset of field: flexarray_align::data", + ][::std::mem::offset_of!(flexarray_align, data) - 4usize]; +}; impl flexarray_align<[::std::os::raw::c_int]> { pub fn layout(len: usize) -> ::std::alloc::Layout { unsafe {