rust-bindgen icon indicating copy to clipboard operation
rust-bindgen copied to clipboard

`repr(packed(n))` missing on virtual classes

Open MarijnS95 opened this issue 9 months ago • 0 comments

(Apologies if this already reported in some form: GitHub search shows a lot of semi-related open issues but none seem to define exactly this scenario - even if they may share the same problem in the end)

Consider the following bindings.hpp sample:

#pragma pack(4)

class Data {
	void *test;
};

class Foo {
	virtual void foo();
};

Running bindgen bindings.hpp (with a 64-bit target) prints:

/* automatically generated by rust-bindgen 0.71.1 */

#[repr(C, packed(4))]
#[derive(Debug, Copy, Clone)]
pub struct Data {
    pub test: *mut ::std::os::raw::c_void,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
    ["Size of Data"][::std::mem::size_of::<Data>() - 8usize];
    ["Alignment of Data"][::std::mem::align_of::<Data>() - 4usize];
    ["Offset of field: Data::test"][::std::mem::offset_of!(Data, test) - 0usize];
};
#[repr(C)]
pub struct Foo__bindgen_vtable(::std::os::raw::c_void);
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Foo {
    pub vtable_: *const Foo__bindgen_vtable,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
    ["Size of Foo"][::std::mem::size_of::<Foo>() - 8usize];
    ["Alignment of Foo"][::std::mem::align_of::<Foo>() - 4usize];
};

It seems that the layout tests picked up the #pragma pack(4) and expect an alignment of 4 for both Data and Foo (both contain pointer fields that are otherwise aligned to 8 bytes). However, packed(4) is only emitted for the "POD" Data structure but not for the Foo virtual class, meaning that these layout tests will now fail:

❯ rustc bindings.rs
...

error[E0080]: evaluation of constant value failed
  --> bindings.rs:24:5
   |
24 |     ["Alignment of Foo"][::std::mem::align_of::<Foo>() - 4usize];
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 4

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0080, E0601.
For more information about an error, try `rustc --explain E0080`.

The repr(C, packed(4)) should be emitted on struct Foo, and the alignment test is correct. After all, printing alignof(Foo) for the above code is 4 in cpp too.

#include <iostream>
#pragma pack(4)
class Foo {
  virtual void foo();
};
int main() {
  std::cout << alignof(Foo) << std::endl;
}
$ clang -lstdc++ bindings.cpp && ./a.out
4

MarijnS95 avatar Feb 27 '25 13:02 MarijnS95