Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@
## Changed
## Removed
## Fixed

- Fixed a panic when generating bindings for Objective-C methods that declare C-style parameters (#3488).

## Security

# 0.73.2 (2026-09-08)
Expand Down
35 changes: 35 additions & 0 deletions bindgen-tests/tests/expectations/tests/objc_c_style_params.rs

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

8 changes: 8 additions & 0 deletions bindgen-tests/tests/headers/objc_c_style_params.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// bindgen-flags: -- -x objective-c
// bindgen-osx-only

@interface Foo
- (void)method;
- (void)multi:(int)a and:(int)b;
- (int)take:(int)t, int extra;
@end
4 changes: 3 additions & 1 deletion bindgen/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5102,7 +5102,9 @@ fn objc_method_codegen(
}
};

let methods_and_args = method.format_method_call(&fn_args);
let Some(methods_and_args) = method.format_method_call(&fn_args) else {
return;
};

let body = {
let body = if method.is_class_method() {
Expand Down
31 changes: 23 additions & 8 deletions bindgen/ir/objc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,15 @@ impl ObjCMethod {
self.is_class_method
}

/// Formats the method call
/// Formats the method call.
///
/// Returns `None` when the method cannot be represented as a `msg_send!` call, which happens
/// when the selector and the declared arguments disagree; the method is then skipped with a
/// warning.
pub(crate) fn format_method_call(
&self,
args: &[TokenStream],
) -> TokenStream {
) -> Option<TokenStream> {
let split_name: Vec<Option<Ident>> = self
.name
.split(':')
Expand Down Expand Up @@ -288,13 +292,24 @@ impl ObjCMethod {
// No arguments
if args.is_empty() && split_name.len() == 1 {
let name = &split_name[0];
return quote! {
return Some(quote! {
#name
};
});
}

// Check right amount of arguments
assert_eq!(args.len(), split_name.len() - 1, "Incorrect method name or arguments for objc method, {args:?} vs {split_name:?}");
// Check right amount of arguments. C-style parameters in Objective-C method declarations
// put parameters into clang's ParmDecl list without adding a matching selector part, and
// such a method cannot be represented by `msg_send!`, so skip it instead of panicking.
let expected_args = split_name.len() - 1;
if args.len() != expected_args {
let name = &self.name;
let declared = args.len();
warn!(
"Skipping Objective-C method `{name}`: selector takes {expected_args} \
argument(s) but {declared} were declared"
);
return None;
}

// Get arguments without type signatures to pass to `msg_send!`
let mut args_without_types = vec![];
Expand All @@ -315,9 +330,9 @@ impl ObjCMethod {
},
);

quote! {
Some(quote! {
#( #args )*
}
})
}
}

Expand Down
Loading