Making type template opaque has undesired behavior
Input C/C++ Header
template<typename T>
struct Foo {
void* a;
};
template<typename T>
class Bar {
Foo<T> m;
};
class Baz {
Bar<int> m;
};
Bindgen Invocation
$ bindgen input.hpp --opaque-type Foo
Actual Results
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Foo {
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Bar {
pub m: u8,
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct Baz {
pub m: Bar,
}
#[test]
fn bindgen_test_layout_Baz() {
assert_eq!(::std::mem::size_of::<Baz>() , 8usize , concat ! (
"Size of: " , stringify ! ( Baz ) ));
assert_eq! (::std::mem::align_of::<Baz>() , 8usize , concat ! (
"Alignment of " , stringify ! ( Baz ) ));
assert_eq! (unsafe {
& ( * ( 0 as * const Baz ) ) . m as * const _ as usize } ,
0usize , concat ! (
"Alignment of field: " , stringify ! ( Baz ) , "::" ,
stringify ! ( m ) ));
}
impl Clone for Baz {
fn clone(&self) -> Self { *self }
}
#[test]
fn __bindgen_test_layout_Bar_open0_int_close0_instantiation() {
assert_eq!(::std::mem::size_of::<Bar>() , 8usize , concat ! (
"Size of template specialization: " , stringify ! ( Bar ) ));
assert_eq!(::std::mem::align_of::<Bar>() , 8usize , concat ! (
"Alignment of template specialization: " , stringify ! ( Bar )
));
}
Expected Results
As can be seen from the C++ code, Foo should have a pointer size, and Bar and Baz as well. However, Bar and Baz in this case only have 1 byte, while the layout test asserts they have 8 bytes.
Bar probably should have something like [u8; 8usize] or [usize; 2usize] instead.
Oh wow. Yeah, we should be doing much better with generating opaque blobs here.
I think the same thing happens when bindgen decides a type is opaque by itself (as opposed to forcing it with --opaque-type) ( due to #362 for example):
template <int> struct has_int_template { int y; };
has_int_template<0> function();
produces this:
extern "C" {
#[link_name = "\u{1}_Z8functionv"]
pub fn function() -> u8;
}
which is returning an object of the wrong size.
Looks like u8 is coming from ToOpaque::get_layout's fallback to Layout::for_size(ctx, 1). That seems unlikely to result in valid bindings. I'm not sure how to gracefully refuse to generate bindings for types which trigger that codepath though, and panicing while generating code is less friendly because then you can't even use other bindings which might be correct.