Skip to content

Commit

Permalink
WIP add option to use DST structs for flex arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
jsgf committed Feb 26, 2024
1 parent b5a6813 commit a56d13d
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 1 deletion.
8 changes: 8 additions & 0 deletions bindgen-cli/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,9 @@ struct BindgenCommand {
/// Wrap unsafe operations in unsafe blocks.
#[arg(long)]
wrap_unsafe_ops: bool,
/// 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>, String)>,
Expand Down Expand Up @@ -554,6 +557,7 @@ where
merge_extern_blocks,
override_abi,
wrap_unsafe_ops,
flexarray_dst,
with_derive_custom,
with_derive_custom_struct,
with_derive_custom_enum,
Expand Down Expand Up @@ -1023,6 +1027,10 @@ where
builder = builder.wrap_unsafe_ops(true);
}

if flexarray_dst {
builder = builder.flexarray_dst(true);
}

#[derive(Debug)]
struct CustomDeriveCallback {
derives: Vec<String>,
Expand Down
54 changes: 53 additions & 1 deletion bindgen/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1426,10 +1426,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_incomplete_array();

let inner = item.to_rust_ty_or_opaque(ctx, &());

if ctx.options().enable_cxx_namespaces {
if ctx.options().flexarray_dst {
syn::parse_quote! { [ #inner ] }
} else if ctx.options().enable_cxx_namespaces {
syn::parse_quote! { root::__IncompleteArrayField<#inner> }
} else {
syn::parse_quote! { __IncompleteArrayField<#inner> }
Expand Down Expand Up @@ -2194,6 +2197,7 @@ impl CodeGenerator for CompInfo {
let mut needs_default_impl = false;
let mut needs_debug_impl = false;
let mut needs_partialeq_impl = false;
let mut needs_flexarray_impl = false;
if let Some(comment) = item.comment(ctx) {
attributes.push(attributes::doc(comment));
}
Expand Down Expand Up @@ -2228,6 +2232,10 @@ impl CodeGenerator for CompInfo {
}
}

if ctx.options().flexarray_dst {
needs_flexarray_impl = struct_layout.has_incomplete_array();
}

let derivable_traits = derives_of_item(item, ctx, packed);
if !derivable_traits.contains(DerivableTraits::DEBUG) {
needs_debug_impl = ctx.options().derive_debug &&
Expand Down Expand Up @@ -2481,6 +2489,47 @@ impl CodeGenerator for CompInfo {
});
}

if needs_flexarray_impl {
let prefix = ctx.trait_prefix();

let layout = if ctx.options().rust_features().layout_for_ptr {
quote! {
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(ptr::null(), len);
::#prefix::alloc::Layout::for_value_raw(p)
}
}
}
} else {
quote!()
};

let from_ptr = if ctx.options().rust_features().ptr_metadata {
quote! {
unsafe fn from_ptr<'a>(ptr: *const (), len: usize) -> &'a Self {
let ptr: *const Self = ::#prefix::ptr::from_raw_parts(ptr, len);
&*ptr
}

unsafe fn from_ptr_mut<'a>(ptr: *mut (), len: usize) -> ::#prefix::mem::MaybeUninit<&'a mut Self> {
let ptr: *mut Self = ::#prefix::ptr::from_raw_parts_mut(ptr, len);
::#prefix::mem::MaybeUninit::new(&mut *ptr)
}
}
} else {
quote!()
};

result.push(quote! {
impl #generics #ty_for_impl {
#layout
#from_ptr
}
});
}

if needs_default_impl {
let prefix = ctx.trait_prefix();
let body = if ctx.options().rust_features().maybe_uninit {
Expand Down Expand Up @@ -5075,6 +5124,9 @@ pub(crate) mod utils {
ctx: &BindgenContext,
result: &mut Vec<proc_macro2::TokenStream>,
) {
if ctx.options().flexarray_dst {
return;
}
let prefix = ctx.trait_prefix();

// If the target supports `const fn`, declare eligible functions
Expand Down
10 changes: 10 additions & 0 deletions bindgen/codegen/struct_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub(crate) struct StructLayoutTracker<'a> {
latest_field_layout: Option<Layout>,
max_field_align: usize,
last_field_was_bitfield: bool,
last_field_was_incomplete_array: bool,
visibility: FieldVisibilityKind,
}

Expand Down Expand Up @@ -110,6 +111,7 @@ impl<'a> StructLayoutTracker<'a> {
latest_field_layout: None,
max_field_align: 0,
last_field_was_bitfield: false,
last_field_was_incomplete_array: false,
}
}

Expand All @@ -121,6 +123,10 @@ impl<'a> StructLayoutTracker<'a> {
self.is_rust_union
}

pub(crate) fn has_incomplete_array(&self) -> bool {
self.last_field_was_incomplete_array
}

pub(crate) fn saw_vtable(&mut self) {
debug!("saw vtable for {}", self.name);

Expand Down Expand Up @@ -159,6 +165,10 @@ impl<'a> StructLayoutTracker<'a> {
self.max_field_align = cmp::max(self.max_field_align, layout.align);
}

pub(crate) fn saw_incomplete_array(&mut self) {
self.last_field_was_incomplete_array = true;
}

/// Returns a padding field if necessary for a given new field _before_
/// adding that field.
pub(crate) fn saw_field(
Expand Down
2 changes: 2 additions & 0 deletions bindgen/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ macro_rules! define_rust_targets {
define_rust_targets! {
Nightly => {
vectorcall_abi,
ptr_metadata: #81513,
layout_for_ptr: #69835,
},
Stable_1_73(73) => { thiscall_abi: #42202 },
Stable_1_71(71) => { c_unwind_abi: #106075 },
Expand Down
13 changes: 13 additions & 0 deletions bindgen/options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1980,6 +1980,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 overriden.
abi_overrides: HashMap<Abi, RegexSet> {
methods: {
Expand Down

0 comments on commit a56d13d

Please sign in to comment.