From dbe5d3e2360e0e014e7ac6355bee3699c68cc201 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Thu, 20 Feb 2025 13:03:08 +0000 Subject: [PATCH] Option to represent all C++ operators. In its default behavior, bindgen does not emit information for any C++ operatorXYZ function (unless operatorXYZ is a valid identifier, which it isn't for C++ overloaded operators). This PR introduces a new command line option to represent all operators. This is not useful for those who directly consume the output of bindgen, but is useful for post-processors. Specifically, consumers will need to implement the callback to rename these items to something more useful. Part of https://github.com/google/autocxx/issues/124 --- .../expectations/tests/operator_equals.rs | 24 +++++++++++++++++++ .../tests/headers/operator_equals.hpp | 9 +++++++ bindgen-tests/tests/parse_callbacks/mod.rs | 14 +++++++++++ bindgen/ir/function.rs | 2 +- bindgen/options/cli.rs | 5 ++++ bindgen/options/mod.rs | 18 ++++++++++++++ 6 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 bindgen-tests/tests/expectations/tests/operator_equals.rs create mode 100644 bindgen-tests/tests/headers/operator_equals.hpp diff --git a/bindgen-tests/tests/expectations/tests/operator_equals.rs b/bindgen-tests/tests/expectations/tests/operator_equals.rs new file mode 100644 index 0000000000..ff9f4fdd22 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/operator_equals.rs @@ -0,0 +1,24 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct SomeClass { + pub _address: u8, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of SomeClass"][::std::mem::size_of::() - 1usize]; + ["Alignment of SomeClass"][::std::mem::align_of::() - 1usize]; +}; +unsafe extern "C" { + #[link_name = "\u{1}_ZN9SomeClassaSERKS_"] + pub fn SomeClass_operatorequals( + this: *mut SomeClass, + another: *const SomeClass, + ) -> bool; +} +impl SomeClass { + #[inline] + pub unsafe fn operatorequals(&mut self, another: *const SomeClass) -> bool { + SomeClass_operatorequals(self, another) + } +} diff --git a/bindgen-tests/tests/headers/operator_equals.hpp b/bindgen-tests/tests/headers/operator_equals.hpp new file mode 100644 index 0000000000..38a3a092a9 --- /dev/null +++ b/bindgen-tests/tests/headers/operator_equals.hpp @@ -0,0 +1,9 @@ +// bindgen-flags: --represent-cxx-operators --generate-inline-functions -- -x c++ +// bindgen-parse-callbacks: operator-rename + +class SomeClass { +public: + bool operator=(const SomeClass& another) { + return false; + } +}; diff --git a/bindgen-tests/tests/parse_callbacks/mod.rs b/bindgen-tests/tests/parse_callbacks/mod.rs index 7aca0fd1a1..5fe8d90d4c 100644 --- a/bindgen-tests/tests/parse_callbacks/mod.rs +++ b/bindgen-tests/tests/parse_callbacks/mod.rs @@ -146,6 +146,19 @@ impl ParseCallbacks for WrapAsVariadicFn { } } +#[derive(Debug)] +pub(super) struct OperatorRename; + +impl ParseCallbacks for OperatorRename { + fn generated_name_override(&self, info: ItemInfo) -> Option { + if info.name == "operator=" { + Some("operatorequals".to_string()) + } else { + None + } + } +} + pub fn lookup(cb: &str) -> Box { match cb { "enum-variant-rename" => Box::new(EnumVariantRename), @@ -154,6 +167,7 @@ pub fn lookup(cb: &str) -> Box { } "wrap-as-variadic-fn" => Box::new(WrapAsVariadicFn), "type-visibility" => Box::new(TypeVisibility), + "operator-rename" => Box::new(OperatorRename), call_back => { if let Some(prefix) = call_back.strip_prefix("remove-function-prefix-") diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 83b748a5f4..002a078df2 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -433,7 +433,7 @@ impl FunctionSig { spelling.starts_with("operator") && !clang::is_valid_identifier(spelling) }; - if is_operator(&spelling) { + if is_operator(&spelling) && !ctx.options().represent_cxx_operators { return Err(ParseError::Continue); } diff --git a/bindgen/options/cli.rs b/bindgen/options/cli.rs index 1efddb02f3..d6f77e4862 100644 --- a/bindgen/options/cli.rs +++ b/bindgen/options/cli.rs @@ -444,6 +444,9 @@ struct BindgenCommand { /// Use distinct char16_t #[arg(long)] use_distinct_char16_t: bool, + /// Output C++ overloaded operators + #[arg(long)] + represent_cxx_operators: bool, /// Enables generation of vtable functions. #[arg(long)] vtable_generation: bool, @@ -633,6 +636,7 @@ where c_naming, explicit_padding, use_distinct_char16_t, + represent_cxx_operators, vtable_generation, sort_semantically, merge_extern_blocks, @@ -931,6 +935,7 @@ where c_naming, explicit_padding, use_distinct_char16_t, + represent_cxx_operators, vtable_generation, sort_semantically, merge_extern_blocks, diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index 74dd5c0b1d..c3ccd89014 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -177,6 +177,24 @@ options! { }, as_args: "--use-distinct-char16-t", }, + /// Whether we should output C++ overloaded operators. By itself, + /// this option is not sufficient to produce valid output, because + /// such operators will have names that are not acceptable Rust + /// names (for example `operator=`). If you use this option, you'll also + /// have to rename the resulting functions - for example by using + /// [`ParseCallbacks::generated_name_override`]. + represent_cxx_operators: bool { + methods: { + /// If this is true, output existence of C++ overloaded operators. + /// At present, only operator= is noted. + /// Disabled by default. + pub fn represent_cxx_operators(mut self, doit: bool) -> Builder { + self.options.represent_cxx_operators = doit; + self + } + }, + as_args: "--represent-cxx-operators", + }, /// Types that have been blocklisted and should not appear anywhere in the generated code. blocklisted_types: RegexSet {