Skip to content

Options to generate uncallable C++ functions. #3139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 4, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions bindgen-tests/tests/expectations/tests/uncallable_functions.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions bindgen-tests/tests/headers/uncallable_functions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// bindgen-flags: --generate-deleted-functions --generate-private-functions --generate-pure-virtual-functions --generate-inline-functions -- -x c++ -std=c++14

class Test {
public:
virtual void a() = 0;
void b() = delete;
private:
void c() {}
};
20 changes: 13 additions & 7 deletions bindgen/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4564,14 +4564,20 @@ impl CodeGenerator for Function {
}
}

// Pure virtual methods have no actual symbol, so we can't generate
// something meaningful for them.
let is_dynamic_function = match self.kind() {
FunctionKind::Method(ref method_kind)
if method_kind.is_pure_virtual() =>
{
return None;
let is_pure_virtual = match self.kind() {
FunctionKind::Method(ref method_kind) => {
method_kind.is_pure_virtual()
}
_ => false,
};
if is_pure_virtual && !ctx.options().generate_pure_virtual_functions {
// Pure virtual methods have no actual symbol, so we can't generate
// something meaningful for them. Downstream code postprocessors
// might want to find out about them.
return None;
}

let is_dynamic_function = match self.kind() {
FunctionKind::Function => {
ctx.options().dynamic_library_name.is_some()
}
Expand Down
5 changes: 2 additions & 3 deletions bindgen/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,8 +731,7 @@ impl ClangSubItemParser for Function {
if visibility != CXVisibility_Default {
return Err(ParseError::Continue);
}

if cursor.access_specifier() == CX_CXXPrivate {
if cursor.access_specifier() == CX_CXXPrivate && !context.options().generate_private_functions {
return Err(ParseError::Continue);
}

Expand All @@ -752,7 +751,7 @@ impl ClangSubItemParser for Function {
return Err(ParseError::Continue);
}

if cursor.is_deleted_function() {
if cursor.is_deleted_function() && !context.options().generate_deleted_functions {
return Err(ParseError::Continue);
}

Expand Down
18 changes: 18 additions & 0 deletions bindgen/options/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,18 @@ struct BindgenCommand {
/// bitfields. This flag is ignored if the `--respect-cxx-access-specs` flag is used.
#[arg(long, value_name = "VISIBILITY")]
default_visibility: Option<FieldVisibilityKind>,
/// Whether to generate C++ functions marked with "=delete" even though they
/// can't be called.
#[arg(long)]
generate_deleted_functions: bool,
/// Whether to generate C++ "pure virtual" functions even though they can't
/// be called.
#[arg(long)]
generate_pure_virtual_functions: bool,
/// Whether to generate C++ private functions even though they can't
/// be called.
#[arg(long)]
generate_private_functions: bool,
/// Whether to emit diagnostics or not.
#[cfg(feature = "experimental")]
#[arg(long, requires = "experimental")]
Expand Down Expand Up @@ -653,6 +665,9 @@ where
wrap_static_fns_path,
wrap_static_fns_suffix,
default_visibility,
generate_deleted_functions,
generate_pure_virtual_functions,
generate_private_functions,
#[cfg(feature = "experimental")]
emit_diagnostics,
generate_shell_completions,
Expand Down Expand Up @@ -943,6 +958,9 @@ where
wrap_static_fns_path,
wrap_static_fns_suffix,
default_visibility,
generate_deleted_functions,
generate_pure_virtual_functions,
generate_private_functions,
}
);

Expand Down
54 changes: 54 additions & 0 deletions bindgen/options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2193,4 +2193,58 @@ options! {
},
as_args: "--clang-macro-fallback-build-dir",
}
/// Whether to always report C++ "deleted" functions.
generate_deleted_functions: bool {
methods: {
/// Set whether to generate C++ functions even marked "=deleted"
///
/// Although not useful to call these functions, downstream code
/// generators may need to know whether they've been deleted in
/// order to determine the relocatability of a C++ type
/// (specifically by virtue of which constructors exist.)
pub fn generate_deleted_functions(mut self, doit: bool) -> Self {
self.options.generate_deleted_functions = doit;
self
}

},
as_args: "--generate-deleted-functions",
},
/// Whether to always report C++ "pure virtual" functions.
generate_pure_virtual_functions: bool {
methods: {
/// Set whether to generate C++ functions that are pure virtual.
///
/// These functions can't be called, so the only reason
/// to generate them is if downstream postprocessors
/// need to know of their existence. This is necessary,
/// for instance, to determine whether a type itself is
/// pure virtual and thus can't be allocated.
/// Downstream code generators may choose to make code to
/// allow types to be allocated but need to avoid doing so
/// if the type contains pure virtual functions.
pub fn generate_pure_virtual_functions(mut self, doit: bool) -> Self {
self.options.generate_pure_virtual_functions = doit;
self
}

},
as_args: "--generate-pure-virtual-functions",
},
/// Whether to always report C++ "private" functions.
generate_private_functions: bool {
methods: {
/// Set whether to generate C++ functions that are private.
///
/// These functions can't be called, so the only reason
/// to generate them is if downstream postprocessors
/// need to know of their existence.
pub fn generate_private_functions(mut self, doit: bool) -> Self {
self.options.generate_private_functions = doit;
self
}

},
as_args: "--generate-private-functions",
},
}
Loading