From 919130612d7261849ef7444bdee517c7e3c4e737 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Thu, 19 May 2022 21:54:46 -0400 Subject: [PATCH] Look for `must_use` on typdefs in function return Closes #2206 --- src/codegen/mod.rs | 32 +++++++- src/ir/context.rs | 3 +- .../tests/func_return_must_use.rs | 76 +++++++++++++++++++ tests/headers/func_return_must_use.h | 36 +++++++++ 4 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 tests/expectations/tests/func_return_must_use.rs create mode 100644 tests/headers/func_return_must_use.h diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index e4ce95264f..fdc9b5ed16 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -3965,11 +3965,35 @@ impl CodeGenerator for Function { let mut attributes = vec![]; - if signature.must_use() && - ctx.options().rust_features().must_use_function - { - attributes.push(attributes::must_use()); + if ctx.options().rust_features().must_use_function { + let must_use = signature.must_use() || { + let ret_ty = signature.return_type(); + + let resolved_ret = ret_ty + .into_resolver() + .through_type_refs() + .through_type_aliases() + .resolve(ctx); + + let must_use_resolved_ty = + resolved_ret.annotations().must_use_type() || + ctx.must_use_type_by_name(resolved_ret); + + let ret = ctx.resolve_item(ret_ty); + let must_use_ty = ret.annotations().must_use_type() || + ctx.must_use_type_by_name(ret); + + // If the return type already has #[must_use], the function does not + // need the annotation. This preserves the codegen behavior before + // type aliases with #[must_use] were supported. + !must_use_resolved_ty && must_use_ty + }; + + if must_use { + attributes.push(attributes::must_use()); + } } + if let Some(comment) = item.comment(ctx) { attributes.push(attributes::doc(comment)); } diff --git a/src/ir/context.rs b/src/ir/context.rs index 9cf43ec3c6..2f71debd00 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -1921,7 +1921,8 @@ If you encounter an error missing from this list, please file an issue or a PR!" let item = Item::new( with_id, None, - None, + self.resolve_item_fallible(wrapped_id) + .map(|item| item.annotations().clone()), parent_id.unwrap_or_else(|| self.current_module.into()), ItemKind::Type(ty), Some(location), diff --git a/tests/expectations/tests/func_return_must_use.rs b/tests/expectations/tests/func_return_must_use.rs new file mode 100644 index 0000000000..9f40aaa61a --- /dev/null +++ b/tests/expectations/tests/func_return_must_use.rs @@ -0,0 +1,76 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +pub type MustUseInt = ::std::os::raw::c_int; +extern "C" { + #[must_use] + pub fn return_int() -> MustUseInt; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[must_use] +pub struct MustUseStruct { + _unused: [u8; 0], +} +extern "C" { + pub fn return_struct() -> MustUseStruct; +} +///
+pub type AnnotatedInt = ::std::os::raw::c_int; +extern "C" { + #[must_use] + pub fn return_annotated_int() -> AnnotatedInt; +} +extern "C" { + pub fn return_plain_int() -> ::std::os::raw::c_int; +} +///
+#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +#[must_use] +pub struct AnnotatedStruct {} +#[test] +fn bindgen_test_layout_AnnotatedStruct() { + assert_eq!( + ::std::mem::size_of::(), + 0usize, + concat!("Size of: ", stringify!(AnnotatedStruct)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(AnnotatedStruct)) + ); +} +extern "C" { + pub fn return_annotated_struct() -> AnnotatedStruct; +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct PlainStruct {} +#[test] +fn bindgen_test_layout_PlainStruct() { + assert_eq!( + ::std::mem::size_of::(), + 0usize, + concat!("Size of: ", stringify!(PlainStruct)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(PlainStruct)) + ); +} +///
+pub type TypedefPlainStruct = PlainStruct; +extern "C" { + pub fn return_plain_struct() -> PlainStruct; +} +extern "C" { + #[must_use] + pub fn return_typedef_struct() -> TypedefPlainStruct; +} diff --git a/tests/headers/func_return_must_use.h b/tests/headers/func_return_must_use.h new file mode 100644 index 0000000000..f05bd2de40 --- /dev/null +++ b/tests/headers/func_return_must_use.h @@ -0,0 +1,36 @@ +// bindgen-flags: --must-use-type 'MustUse.*' + +typedef int MustUseInt; + +MustUseInt return_int(); + +struct MustUseStruct; + +struct MustUseStruct return_struct(); + +/** + *
+ */ +typedef int AnnotatedInt; + +AnnotatedInt return_annotated_int(); + +int return_plain_int(); + +/** + *
+ */ +struct AnnotatedStruct {}; + +struct AnnotatedStruct return_annotated_struct(); + +struct PlainStruct {}; + +/** + *
+ */ +typedef struct PlainStruct TypedefPlainStruct; + +struct PlainStruct return_plain_struct(); + +TypedefPlainStruct return_typedef_struct();