diff options
-rw-r--r-- | src/codegen/mod.rs | 66 | ||||
-rw-r--r-- | tests/expectations/tests/virtual_interface.rs | 125 | ||||
-rw-r--r-- | tests/headers/virtual_interface.hpp | 24 |
3 files changed, 207 insertions, 8 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index bee299ed..7b72722a 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1049,15 +1049,65 @@ impl<'a> CodeGenerator for Vtable<'a> { ) { assert_eq!(item.id(), self.item_id); debug_assert!(item.is_enabled_for_codegen(ctx)); - - // For now, generate an empty struct, later we should generate function - // pointers and whatnot. let name = ctx.rust_ident(&self.canonical_name(ctx)); - let void = helpers::ast_ty::c_void(ctx); - result.push(quote! { - #[repr(C)] - pub struct #name ( #void ); - }); + + // For now, we will only generate vtables for classes that do not inherit from others. + if self.base_classes.is_empty() { + let methods = self + .methods + .iter() + .filter_map(|m| { + if !m.is_virtual() { + return None; + } + + let function_item = ctx.resolve_item(m.signature()); + if !function_item.process_before_codegen(ctx, result) { + return None; + } + + let function = function_item.expect_function(); + let signature_item = ctx.resolve_item(function.signature()); + let signature = match signature_item.expect_type().kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("Function signature type mismatch"), + }; + + // FIXME: Is there a canonical name without the class prepended? + let function_name = function_item.canonical_name(ctx); + + // FIXME: Need to account for overloading with times_seen (separately from regular function path). + let function_name = ctx.rust_ident(function_name); + let mut args = utils::fnsig_arguments(ctx, signature); + let ret = utils::fnsig_return_ty(ctx, signature); + + args[0] = if m.is_const() { + quote! { &self } + } else { + quote! { &mut self } + }; + + Some(quote! { + #function_name : fn( #( #args ),* ) #ret + }) + }) + .collect::<Vec<_>>(); + + result.push(quote! { + #[repr(C)] + pub struct #name { + #( #methods ),* + } + }) + } else { + // For the cases we don't support, simply generate an empty struct. + let void = helpers::ast_ty::c_void(ctx); + + result.push(quote! { + #[repr(C)] + pub struct #name ( #void ); + }); + } } } diff --git a/tests/expectations/tests/virtual_interface.rs b/tests/expectations/tests/virtual_interface.rs new file mode 100644 index 00000000..5d4f1bbc --- /dev/null +++ b/tests/expectations/tests/virtual_interface.rs @@ -0,0 +1,125 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[repr(C)] +pub struct PureVirtualIFace__bindgen_vtable { + PureVirtualIFace_Foo: fn(&mut self), + PureVirtualIFace_Bar: fn(&mut self, arg1: ::std::os::raw::c_uint), +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PureVirtualIFace { + pub vtable_: *const PureVirtualIFace__bindgen_vtable, +} +#[test] +fn bindgen_test_layout_PureVirtualIFace() { + assert_eq!( + ::std::mem::size_of::<PureVirtualIFace>(), + 8usize, + concat!("Size of: ", stringify!(PureVirtualIFace)) + ); + assert_eq!( + ::std::mem::align_of::<PureVirtualIFace>(), + 8usize, + concat!("Alignment of ", stringify!(PureVirtualIFace)) + ); +} +impl Default for PureVirtualIFace { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::<Self>::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +pub struct AnotherInterface__bindgen_vtable { + AnotherInterface_Baz: fn(&mut self), +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct AnotherInterface { + pub vtable_: *const AnotherInterface__bindgen_vtable, +} +#[test] +fn bindgen_test_layout_AnotherInterface() { + assert_eq!( + ::std::mem::size_of::<AnotherInterface>(), + 8usize, + concat!("Size of: ", stringify!(AnotherInterface)) + ); + assert_eq!( + ::std::mem::align_of::<AnotherInterface>(), + 8usize, + concat!("Alignment of ", stringify!(AnotherInterface)) + ); +} +impl Default for AnotherInterface { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::<Self>::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Implementation { + pub _base: PureVirtualIFace, +} +#[test] +fn bindgen_test_layout_Implementation() { + assert_eq!( + ::std::mem::size_of::<Implementation>(), + 8usize, + concat!("Size of: ", stringify!(Implementation)) + ); + assert_eq!( + ::std::mem::align_of::<Implementation>(), + 8usize, + concat!("Alignment of ", stringify!(Implementation)) + ); +} +impl Default for Implementation { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::<Self>::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoubleImpl { + pub _base: PureVirtualIFace, + pub _base_1: AnotherInterface, +} +#[test] +fn bindgen_test_layout_DoubleImpl() { + assert_eq!( + ::std::mem::size_of::<DoubleImpl>(), + 16usize, + concat!("Size of: ", stringify!(DoubleImpl)) + ); + assert_eq!( + ::std::mem::align_of::<DoubleImpl>(), + 8usize, + concat!("Alignment of ", stringify!(DoubleImpl)) + ); +} +impl Default for DoubleImpl { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::<Self>::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} diff --git a/tests/headers/virtual_interface.hpp b/tests/headers/virtual_interface.hpp new file mode 100644 index 00000000..00ab0737 --- /dev/null +++ b/tests/headers/virtual_interface.hpp @@ -0,0 +1,24 @@ +class PureVirtualIFace { +public: + virtual void Foo() = 0; + virtual void Bar(unsigned int) = 0; +}; + +class AnotherInterface { +public: + virtual void Baz() = 0; +}; + +class Implementation : public PureVirtualIFace { +public: + void Foo() override {} + void Bar(unsigned int) override {} +}; + +class DoubleImpl : public PureVirtualIFace, public AnotherInterface { +public: + void Foo() override {} + void Bar(unsigned int) override {} + + void Baz() override {} +}; |