handle more cases of packed and aligned structs when it's safe/correct · Issue #2725 · rust-lang/rust-bindgen (original) (raw)
When a C struct has both packed
and aligned(N)
attributes, in some cases bindgen generates a Rust struct with a packed(N)
attribute only that has the correct ABI. (Note, I'm assuming GCC semantics for the packed
and aligned(N)
attributes on the C side.)
In other cases, though, bindgen generates code with both attributes, which doesn't compile under rustc. Many of these cases can be handled correctly by applying only an align(N)
attribute; intuitively, this should work if the struct is "naturally packed".
Here is a minimal example:
struct mytest {
uint32_t a;
uint32_t b;
} __attribute__((packed, aligned(8)));
# bindgen generates:
#[repr(C, packed(8))]
#[repr(align(8))]
#[derive(Debug, Copy, Clone)]
pub struct mytest {
pub a: u32,
pub b: u32,
}
# but this would be correct and ABI compatible:
#[repr(C, align(8))]
#[derive(Debug, Copy, Clone)]
pub struct mytest {
pub a: u32,
pub b: u32,
}
This comes up for a handful of structs used in bcachefs. I wrote about this in a message to the rust-for-linux email list:
https://lore.kernel.org/rust-for-linux/20240122024711.GC151023@fedora-laptop/T/#m4439be01c0bcfdbaa781c379be3e227358cfab27
From that message:
In general, given a C structure like
struct A {
...
} __packed __aligned(N);I think a Rust structure can be created with the same size, alignment,
and member offsets in the following cases:(1) #[repr(packed(N))] will have the same layout if N is <= the
structure's default alignment and all members with a default
alignment >= N naturally have an offset that is a multiple of N.
Also, no member can have an alignment attribute as rustc forbids
this [2].(2) #[repr(align(N))] will have the same layout if the structure's size
without the packed attribute is equal to the sum of the size of all
its members (i.e., it is "naturally packed"), and the structure's
default alignment is <= N.
It looks like bindgen already mostly handles case (1).
However, bindgen doesn't seem to handle case (2). What do you think of adding the logic to handle that case into bindgen? This would be really helpful for bcachefs with the structs mentioned in the above email.