Skip to content

Commit 1f9175c

Browse files
committed
WIP add option to use DST structs for flex arrays
1 parent b5a6813 commit 1f9175c

File tree

5 files changed

+86
-1
lines changed

5 files changed

+86
-1
lines changed

bindgen-cli/options.rs

+8
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,9 @@ struct BindgenCommand {
400400
/// Wrap unsafe operations in unsafe blocks.
401401
#[arg(long)]
402402
wrap_unsafe_ops: bool,
403+
/// Use DSTs to represent structures with flexible array members.
404+
#[arg(long)]
405+
flexarray_dst: bool,
403406
/// 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.
404407
#[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)]
405408
with_derive_custom: Vec<(Vec<String>, String)>,
@@ -554,6 +557,7 @@ where
554557
merge_extern_blocks,
555558
override_abi,
556559
wrap_unsafe_ops,
560+
flexarray_dst,
557561
with_derive_custom,
558562
with_derive_custom_struct,
559563
with_derive_custom_enum,
@@ -1023,6 +1027,10 @@ where
10231027
builder = builder.wrap_unsafe_ops(true);
10241028
}
10251029

1030+
if flexarray_dst {
1031+
builder = builder.flexarray_dst(true);
1032+
}
1033+
10261034
#[derive(Debug)]
10271035
struct CustomDeriveCallback {
10281036
derives: Vec<String>,

bindgen/codegen/mod.rs

+53-1
Original file line numberDiff line numberDiff line change
@@ -1426,10 +1426,13 @@ impl<'a> FieldCodegen<'a> for FieldData {
14261426
wrap_union_field_if_needed(ctx, struct_layout, ty, result)
14271427
} else if let Some(item) = field_ty.is_incomplete_array(ctx) {
14281428
result.saw_incomplete_array();
1429+
struct_layout.saw_incomplete_array();
14291430

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

1432-
if ctx.options().enable_cxx_namespaces {
1433+
if ctx.options().flexarray_dst {
1434+
syn::parse_quote! { [ #inner ] }
1435+
} else if ctx.options().enable_cxx_namespaces {
14331436
syn::parse_quote! { root::__IncompleteArrayField<#inner> }
14341437
} else {
14351438
syn::parse_quote! { __IncompleteArrayField<#inner> }
@@ -2194,6 +2197,7 @@ impl CodeGenerator for CompInfo {
21942197
let mut needs_default_impl = false;
21952198
let mut needs_debug_impl = false;
21962199
let mut needs_partialeq_impl = false;
2200+
let mut needs_flexarray_impl = false;
21972201
if let Some(comment) = item.comment(ctx) {
21982202
attributes.push(attributes::doc(comment));
21992203
}
@@ -2228,6 +2232,10 @@ impl CodeGenerator for CompInfo {
22282232
}
22292233
}
22302234

2235+
if ctx.options().flexarray_dst {
2236+
needs_flexarray_impl = struct_layout.has_incomplete_array();
2237+
}
2238+
22312239
let derivable_traits = derives_of_item(item, ctx, packed);
22322240
if !derivable_traits.contains(DerivableTraits::DEBUG) {
22332241
needs_debug_impl = ctx.options().derive_debug &&
@@ -2481,6 +2489,47 @@ impl CodeGenerator for CompInfo {
24812489
});
24822490
}
24832491

2492+
if needs_flexarray_impl {
2493+
let prefix = ctx.trait_prefix();
2494+
2495+
let layout = if ctx.options().rust_features().layout_for_ptr {
2496+
quote! {
2497+
fn layout(len: usize) -> ::#prefix::alloc::Layout {
2498+
// SAFETY: Null pointers are OK if we don't deref them
2499+
unsafe {
2500+
let p: *const Self = ::#prefix::ptr::from_raw_parts(ptr::null(), len);
2501+
::#prefix::alloc::Layout::for_value_raw(p)
2502+
}
2503+
}
2504+
}
2505+
} else {
2506+
quote!()
2507+
};
2508+
2509+
let from_ptr = if ctx.options().rust_features().ptr_metadata {
2510+
quote! {
2511+
unsafe fn from_ptr<'a>(ptr: *const (), len: usize) -> &'a Self {
2512+
let ptr: *const Self = ::#prefix::ptr::from_raw_parts(ptr, len);
2513+
&*ptr
2514+
}
2515+
2516+
unsafe fn from_ptr_mut<'a>(ptr: *mut (), len: usize) -> ::#prefix::mem::MaybeUninit<&'a mut Self> {
2517+
let ptr: *mut Self = ::#prefix::ptr::from_raw_parts_mut(ptr, len);
2518+
::#prefix::mem::MaybeUninit::new(&mut *ptr)
2519+
}
2520+
}
2521+
} else {
2522+
quote!()
2523+
};
2524+
2525+
result.push(quote! {
2526+
impl #generics #ty_for_impl {
2527+
#layout
2528+
#from_ptr
2529+
}
2530+
});
2531+
}
2532+
24842533
if needs_default_impl {
24852534
let prefix = ctx.trait_prefix();
24862535
let body = if ctx.options().rust_features().maybe_uninit {
@@ -5075,6 +5124,9 @@ pub(crate) mod utils {
50755124
ctx: &BindgenContext,
50765125
result: &mut Vec<proc_macro2::TokenStream>,
50775126
) {
5127+
if ctx.options().flexarray_dst {
5128+
return;
5129+
}
50785130
let prefix = ctx.trait_prefix();
50795131

50805132
// If the target supports `const fn`, declare eligible functions

bindgen/codegen/struct_layout.rs

+10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub(crate) struct StructLayoutTracker<'a> {
2727
latest_field_layout: Option<Layout>,
2828
max_field_align: usize,
2929
last_field_was_bitfield: bool,
30+
last_field_was_incomplete_array: bool,
3031
visibility: FieldVisibilityKind,
3132
}
3233

@@ -110,6 +111,7 @@ impl<'a> StructLayoutTracker<'a> {
110111
latest_field_layout: None,
111112
max_field_align: 0,
112113
last_field_was_bitfield: false,
114+
last_field_was_incomplete_array: false,
113115
}
114116
}
115117

@@ -121,6 +123,10 @@ impl<'a> StructLayoutTracker<'a> {
121123
self.is_rust_union
122124
}
123125

126+
pub(crate) fn has_incomplete_array(&self) -> bool {
127+
self.last_field_was_incomplete_array
128+
}
129+
124130
pub(crate) fn saw_vtable(&mut self) {
125131
debug!("saw vtable for {}", self.name);
126132

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

168+
pub(crate) fn saw_incomplete_array(&mut self) {
169+
self.last_field_was_incomplete_array = true;
170+
}
171+
162172
/// Returns a padding field if necessary for a given new field _before_
163173
/// adding that field.
164174
pub(crate) fn saw_field(

bindgen/features.rs

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ macro_rules! define_rust_targets {
9696
define_rust_targets! {
9797
Nightly => {
9898
vectorcall_abi,
99+
ptr_metadata: #81513,
100+
layout_for_ptr: #69835,
99101
},
100102
Stable_1_73(73) => { thiscall_abi: #42202 },
101103
Stable_1_71(71) => { c_unwind_abi: #106075 },

bindgen/options/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1980,6 +1980,19 @@ options! {
19801980
},
19811981
as_args: "--wrap-unsafe-ops",
19821982
},
1983+
/// Use DSTs to represent structures with flexible array members.
1984+
flexarray_dst: bool {
1985+
methods: {
1986+
/// Use DSTs to represent structures with flexible array members.
1987+
///
1988+
/// This option is disabled by default.
1989+
pub fn flexarray_dst(mut self, doit: bool) -> Self {
1990+
self.options.flexarray_dst = doit;
1991+
self
1992+
}
1993+
},
1994+
as_args: "--flexarray-dst",
1995+
},
19831996
/// Patterns for functions whose ABI should be overriden.
19841997
abi_overrides: HashMap<Abi, RegexSet> {
19851998
methods: {

0 commit comments

Comments
 (0)