Skip to content
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

Generate #[must_use] on functions returing a typedef to a must-use-type #2206

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 28 additions & 4 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
3 changes: 2 additions & 1 deletion src/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
76 changes: 76 additions & 0 deletions tests/expectations/tests/func_return_must_use.rs
Original file line number Diff line number Diff line change
@@ -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;
}
/// <div rustbindgen mustusetype></div>
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;
}
/// <div rustbindgen mustusetype></div>
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
#[must_use]
pub struct AnnotatedStruct {}
#[test]
fn bindgen_test_layout_AnnotatedStruct() {
assert_eq!(
::std::mem::size_of::<AnnotatedStruct>(),
0usize,
concat!("Size of: ", stringify!(AnnotatedStruct))
);
assert_eq!(
::std::mem::align_of::<AnnotatedStruct>(),
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::<PlainStruct>(),
0usize,
concat!("Size of: ", stringify!(PlainStruct))
);
assert_eq!(
::std::mem::align_of::<PlainStruct>(),
1usize,
concat!("Alignment of ", stringify!(PlainStruct))
);
}
/// <div rustbindgen mustusetype></div>
pub type TypedefPlainStruct = PlainStruct;
extern "C" {
pub fn return_plain_struct() -> PlainStruct;
}
extern "C" {
#[must_use]
pub fn return_typedef_struct() -> TypedefPlainStruct;
}
36 changes: 36 additions & 0 deletions tests/headers/func_return_must_use.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// bindgen-flags: --must-use-type 'MustUse.*'

typedef int MustUseInt;

MustUseInt return_int();

struct MustUseStruct;

struct MustUseStruct return_struct();

/**
* <div rustbindgen mustusetype></div>
*/
typedef int AnnotatedInt;

AnnotatedInt return_annotated_int();

int return_plain_int();

/**
* <div rustbindgen mustusetype></div>
*/
struct AnnotatedStruct {};

struct AnnotatedStruct return_annotated_struct();

struct PlainStruct {};

/**
* <div rustbindgen mustusetype></div>
*/
typedef struct PlainStruct TypedefPlainStruct;

struct PlainStruct return_plain_struct();

TypedefPlainStruct return_typedef_struct();