diff --git a/bindgen-tests/tests/expectations/tests/function-typedef-method.rs b/bindgen-tests/tests/expectations/tests/function-typedef-method.rs new file mode 100644 index 0000000000..1605cba4bf --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/function-typedef-method.rs @@ -0,0 +1,104 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub type Function = ::std::option::Option< + unsafe extern "C" fn(arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int, +>; +pub type FunctionAlias = Function; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct First { + pub value: ::std::os::raw::c_int, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of First"][::std::mem::size_of::() - 4usize]; + ["Alignment of First"][::std::mem::align_of::() - 4usize]; + ["Offset of field: First::value"][::std::mem::offset_of!(First, value) - 0usize]; +}; +unsafe extern "C" { + #[link_name = "\u{1}_ZN5First6methodEi"] + pub fn First_method( + this: *mut First, + arg1: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + #[link_name = "\u{1}_ZN5First13static_methodEi"] + pub fn First_static_method(arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +impl First { + #[inline] + pub unsafe fn method( + &mut self, + arg1: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + First_method(self, arg1) + } + #[inline] + pub unsafe fn static_method(arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int { + First_static_method(arg1) + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Second { + pub value: ::std::os::raw::c_int, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of Second"][::std::mem::size_of::() - 4usize]; + ["Alignment of Second"][::std::mem::align_of::() - 4usize]; + ["Offset of field: Second::value"][::std::mem::offset_of!(Second, value) - 0usize]; +}; +unsafe extern "C" { + #[link_name = "\u{1}_ZN6Second6methodEi"] + pub fn Second_method( + this: *mut Second, + arg1: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +impl Second { + #[inline] + pub unsafe fn method( + &mut self, + arg1: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + Second_method(self, arg1) + } +} +#[repr(C)] +pub struct Virtual__bindgen_vtable { + pub Virtual_method: unsafe extern "C" fn( + this: *mut Virtual, + arg1: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Virtual { + pub vtable_: *const Virtual__bindgen_vtable, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of Virtual"][::std::mem::size_of::() - 8usize]; + ["Alignment of Virtual"][::std::mem::align_of::() - 8usize]; +}; +impl Default for Virtual { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { + #[link_name = "\u{1}_ZN7Virtual6methodEi"] + pub fn Virtual_method( + this: *mut ::std::os::raw::c_void, + arg1: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +unsafe extern "C" { + #[link_name = "\u{1}_Z13free_functioni"] + pub fn free_function(arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} diff --git a/bindgen-tests/tests/headers/function-typedef-method.hpp b/bindgen-tests/tests/headers/function-typedef-method.hpp new file mode 100644 index 0000000000..12cf7041d5 --- /dev/null +++ b/bindgen-tests/tests/headers/function-typedef-method.hpp @@ -0,0 +1,21 @@ +// bindgen-flags: -- -std=c++17 + +typedef int Function(int); +using FunctionAlias = Function; + +struct First { + Function method; + static Function static_method; + int value; +}; + +struct Second { + FunctionAlias method; + int value; +}; + +struct Virtual { + virtual Function method; +}; + +Function free_function; diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index a249783844..9cd0405346 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -803,6 +803,28 @@ fn commandline_multiple_headers() { build_flags_output_helper(&bindings); } +#[test] +fn test_wrap_static_function_typedef() { + let directory = tempfile::tempdir().unwrap(); + let header = directory.path().join("function-typedef.h"); + fs::write( + &header, + "typedef int Function(int);\nstatic Function take;\nstatic int take(int value) { return value + 10; }\n", + ) + .unwrap(); + let wrapper = directory.path().join("wrapper.c"); + Builder::default() + .header(header.to_str().unwrap()) + .wrap_static_fns(true) + .wrap_static_fns_path(&wrapper) + .generate() + .expect( + "Function typedefs must be resolved before serializing a wrapper", + ); + let wrapper = fs::read_to_string(wrapper).unwrap(); + assert!(wrapper.contains("return take(")); +} + #[test] fn test_wrap_static_fns() { // This test is for testing diffs of the generated C source and header files diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 7cc274563c..660dc02f23 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -771,7 +771,13 @@ impl ClangSubItemParser for Function { } // Grab the signature using Item::from_ty. - let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?; + let mut ty = cursor.cur_type(); + // Parse the signature at the function cursor so that methods declared + // through a function typedef still get their implicit receiver. + if matches!(ty.kind(), CXType_Typedef | CXType_Elaborated) { + ty = ty.canonical_type(); + } + let sig = Item::from_ty(&ty, cursor, None, context)?; let mut name = cursor.spelling(); assert!(!name.is_empty(), "Empty function name?");