From 59c9507e80438480328be91b4284ace75d6eeff2 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Wed, 19 Feb 2025 14:16:05 +0000 Subject: [PATCH] Provide option to get real virtual fn receiver. For virtual functions, bindgen has traditionally emitted a void* pointer because that's the least bad option for Rust code directly consuming the bindings. For downstream postprocessors and code generators, this throws away useful information about the actual type of the receiver. Provide a command-line option to put that back. Part of https://github.com/google/autocxx/issues/124 --- .../expectations/tests/specific_receiver.rs | 28 +++++++++++++++++++ .../tests/headers/specific_receiver.hpp | 7 +++++ bindgen/ir/function.rs | 5 +++- bindgen/options/cli.rs | 5 ++++ bindgen/options/mod.rs | 15 ++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 bindgen-tests/tests/expectations/tests/specific_receiver.rs create mode 100644 bindgen-tests/tests/headers/specific_receiver.hpp diff --git a/bindgen-tests/tests/expectations/tests/specific_receiver.rs b/bindgen-tests/tests/expectations/tests/specific_receiver.rs new file mode 100644 index 0000000000..ec001b12ad --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/specific_receiver.rs @@ -0,0 +1,28 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +pub struct Fish__bindgen_vtable { + pub Fish_swim: unsafe extern "C" fn(this: *mut Fish), +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Fish { + pub vtable_: *const Fish__bindgen_vtable, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of Fish"][::std::mem::size_of::() - 8usize]; + ["Alignment of Fish"][::std::mem::align_of::() - 8usize]; +}; +impl Default for Fish { + 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}_ZN4Fish4swimEv"] + pub fn Fish_swim(this: *mut Fish); +} diff --git a/bindgen-tests/tests/headers/specific_receiver.hpp b/bindgen-tests/tests/headers/specific_receiver.hpp new file mode 100644 index 0000000000..a521f9f0b2 --- /dev/null +++ b/bindgen-tests/tests/headers/specific_receiver.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: --use-specific-virtual-function-receiver --generate-inline-functions -- -x c++ -std=c++14 + +class Fish { +public: + virtual void swim() { + } +}; diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 83b748a5f4..52fc94d974 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -533,7 +533,10 @@ impl FunctionSig { let is_const = is_method && cursor.method_is_const(); let is_virtual = is_method && cursor.method_is_virtual(); let is_static = is_method && cursor.method_is_static(); - if !is_static && !is_virtual { + if !is_static && + (!is_virtual || + ctx.options().use_specific_virtual_function_receiver) + { let parent = cursor.semantic_parent(); let class = Item::parse(parent, None, ctx) .expect("Expected to parse the class"); diff --git a/bindgen/options/cli.rs b/bindgen/options/cli.rs index 1efddb02f3..f9a8572976 100644 --- a/bindgen/options/cli.rs +++ b/bindgen/options/cli.rs @@ -441,6 +441,9 @@ struct BindgenCommand { /// Always output explicit padding fields. #[arg(long)] explicit_padding: bool, + /// Always be specific about the 'receiver' of a virtual function. + #[arg(long)] + use_specific_virtual_function_receiver: bool, /// Use distinct char16_t #[arg(long)] use_distinct_char16_t: bool, @@ -632,6 +635,7 @@ where translate_enum_integer_types, c_naming, explicit_padding, + use_specific_virtual_function_receiver, use_distinct_char16_t, vtable_generation, sort_semantically, @@ -930,6 +934,7 @@ where translate_enum_integer_types, c_naming, explicit_padding, + use_specific_virtual_function_receiver, use_distinct_char16_t, vtable_generation, sort_semantically, diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index 74dd5c0b1d..ab6b232ec3 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -153,6 +153,21 @@ macro_rules! options { } options! { + /// Whether to specify the type of a virtual function receiver + use_specific_virtual_function_receiver: bool { + methods: { + /// Normally, virtual functions have void* as their 'this' type. + /// If this flag is enabled, override that behavior to indicate a + /// pointer of the specific type. + /// Disabled by default. + pub fn use_specific_virtual_function_receiver(mut self, doit: bool) -> Builder { + self.options.use_specific_virtual_function_receiver = doit; + self + } + }, + as_args: "--use-specific-virtual-function-receiver", + }, + /// Whether we should distinguish between C++'s 'char16_t' and 'u16'. /// The C++ type `char16_t` is its own special type; it's not a typedef /// of some other integer (this differs from C).