codegen: Look through typedefs to detect void return type. (#2379)

* codegen: Look through typedefs to detect void return type.

And reuse a bit more code.

Should fix #2377, but needs a test (can't run tests atm).

* Add tests

* Run rustfmt

* Update changelog

Co-authored-by: Christian Poveda <christian.poveda@ferrous-systems.com>
This commit is contained in:
Emilio Cobos Álvarez
2023-01-06 19:07:28 +01:00
committed by GitHub
parent a1943951f4
commit efc8293c07
6 changed files with 75 additions and 29 deletions
+2 -1
View File
@@ -159,7 +159,8 @@
* The `ParseCallbacks::generated_name_override` now receives `ItemInfo<'_>` as
argument instead of a `&str`.
* Updated the `clang-sys` crate version to 1.4.0 to support clang 15.
* The return type is now ommited in signatures of functions returning `void`.
## Removed
## Fixed
@@ -99,7 +99,7 @@ impl TestLib {
) -> ::std::os::raw::c_int {
(self.foo.as_ref().expect("Expected function, got error."))(x)
}
pub unsafe fn bar(&self) -> () {
pub unsafe fn bar(&self) {
(self.bar.as_ref().expect("Expected function, got error."))()
}
}
+18
View File
@@ -0,0 +1,18 @@
#![allow(
dead_code,
non_snake_case,
non_camel_case_types,
non_upper_case_globals
)]
pub type VOID = ::std::os::raw::c_void;
pub type ALSO_VOID = VOID;
extern "C" {
pub fn this_api_returns_nothing();
}
extern "C" {
pub fn this_api_also_returns_nothing();
}
extern "C" {
pub fn this_other_api_also_returns_nothing();
}
@@ -0,0 +1,9 @@
typedef void VOID;
typedef VOID ALSO_VOID;
void this_api_returns_nothing(void);
VOID this_api_also_returns_nothing(VOID);
ALSO_VOID this_other_api_also_returns_nothing(ALSO_VOID);
+1 -1
View File
@@ -170,7 +170,7 @@ impl DynamicItems {
if !is_variadic {
self.struct_implementation.push(quote! {
#(#attributes)*
pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty {
pub unsafe fn #ident ( &self, #( #args ),* ) #ret_ty {
#call_body
}
});
+44 -26
View File
@@ -4135,11 +4135,7 @@ impl CodeGenerator for Function {
if is_dynamic_function {
let args_identifiers =
utils::fnsig_argument_identifiers(ctx, signature);
let return_item = ctx.resolve_item(signature.return_type());
let ret_ty = match *return_item.kind().expect_type().kind() {
TypeKind::Void => quote! {()},
_ => return_item.to_rust_ty_or_opaque(ctx, &()),
};
let ret_ty = utils::fnsig_return_ty(ctx, signature);
result.dynamic_items().push(
ident,
abi,
@@ -4811,23 +4807,50 @@ pub mod utils {
})
}
fn fnsig_return_ty_internal(
ctx: &BindgenContext,
sig: &FunctionSig,
include_arrow: bool,
) -> proc_macro2::TokenStream {
if sig.is_divergent() {
return if include_arrow {
quote! { -> ! }
} else {
quote! { ! }
};
}
let canonical_type_kind = sig
.return_type()
.into_resolver()
.through_type_refs()
.through_type_aliases()
.resolve(ctx)
.kind()
.expect_type()
.kind();
if let TypeKind::Void = canonical_type_kind {
return if include_arrow {
quote! {}
} else {
quote! { () }
};
}
let ret_ty = sig.return_type().to_rust_ty_or_opaque(ctx, &());
if include_arrow {
quote! { -> #ret_ty }
} else {
ret_ty
}
}
pub fn fnsig_return_ty(
ctx: &BindgenContext,
sig: &FunctionSig,
) -> proc_macro2::TokenStream {
if sig.is_divergent() {
return quote! { -> ! };
}
let return_item = ctx.resolve_item(sig.return_type());
if let TypeKind::Void = *return_item.kind().expect_type().kind() {
quote! {}
} else {
let ret_ty = return_item.to_rust_ty_or_opaque(ctx, &());
quote! {
-> #ret_ty
}
}
fnsig_return_ty_internal(ctx, sig, /* include_arrow = */ true)
}
pub fn fnsig_arguments(
@@ -4942,14 +4965,9 @@ pub mod utils {
arg_item.to_rust_ty_or_opaque(ctx, &())
});
let return_item = ctx.resolve_item(sig.return_type());
let ret_ty =
if let TypeKind::Void = *return_item.kind().expect_type().kind() {
quote! { () }
} else {
return_item.to_rust_ty_or_opaque(ctx, &())
};
let ret_ty = fnsig_return_ty_internal(
ctx, sig, /* include_arrow = */ false,
);
quote! {
*const ::block::Block<(#(#args,)*), #ret_ty>
}