Skip to content

Commit 3a8a60c

Browse files
ian-h-chamberlainemilio
authored andcommitted
Look for must_use on typdefs in function return
Closes #2206
1 parent 2cf7ba9 commit 3a8a60c

File tree

4 files changed

+142
-5
lines changed

4 files changed

+142
-5
lines changed

src/codegen/mod.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3965,11 +3965,35 @@ impl CodeGenerator for Function {
39653965

39663966
let mut attributes = vec![];
39673967

3968-
if signature.must_use() &&
3969-
ctx.options().rust_features().must_use_function
3970-
{
3971-
attributes.push(attributes::must_use());
3968+
if ctx.options().rust_features().must_use_function {
3969+
let must_use = signature.must_use() || {
3970+
let ret_ty = signature.return_type();
3971+
3972+
let resolved_ret = ret_ty
3973+
.into_resolver()
3974+
.through_type_refs()
3975+
.through_type_aliases()
3976+
.resolve(ctx);
3977+
3978+
let must_use_resolved_ty =
3979+
resolved_ret.annotations().must_use_type() ||
3980+
ctx.must_use_type_by_name(resolved_ret);
3981+
3982+
let ret = ctx.resolve_item(ret_ty);
3983+
let must_use_ty = ret.annotations().must_use_type() ||
3984+
ctx.must_use_type_by_name(ret);
3985+
3986+
// If the return type already has #[must_use], the function does not
3987+
// need the annotation. This preserves the codegen behavior before
3988+
// type aliases with #[must_use] were supported.
3989+
!must_use_resolved_ty && must_use_ty
3990+
};
3991+
3992+
if must_use {
3993+
attributes.push(attributes::must_use());
3994+
}
39723995
}
3996+
39733997
if let Some(comment) = item.comment(ctx) {
39743998
attributes.push(attributes::doc(comment));
39753999
}

src/ir/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1921,7 +1921,8 @@ If you encounter an error missing from this list, please file an issue or a PR!"
19211921
let item = Item::new(
19221922
with_id,
19231923
None,
1924-
None,
1924+
self.resolve_item_fallible(wrapped_id)
1925+
.map(|item| item.annotations().clone()),
19251926
parent_id.unwrap_or_else(|| self.current_module.into()),
19261927
ItemKind::Type(ty),
19271928
Some(location),
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#![allow(
2+
dead_code,
3+
non_snake_case,
4+
non_camel_case_types,
5+
non_upper_case_globals
6+
)]
7+
8+
pub type MustUseInt = ::std::os::raw::c_int;
9+
extern "C" {
10+
#[must_use]
11+
pub fn return_int() -> MustUseInt;
12+
}
13+
#[repr(C)]
14+
#[derive(Debug, Copy, Clone)]
15+
#[must_use]
16+
pub struct MustUseStruct {
17+
_unused: [u8; 0],
18+
}
19+
extern "C" {
20+
pub fn return_struct() -> MustUseStruct;
21+
}
22+
/// <div rustbindgen mustusetype></div>
23+
pub type AnnotatedInt = ::std::os::raw::c_int;
24+
extern "C" {
25+
#[must_use]
26+
pub fn return_annotated_int() -> AnnotatedInt;
27+
}
28+
extern "C" {
29+
pub fn return_plain_int() -> ::std::os::raw::c_int;
30+
}
31+
/// <div rustbindgen mustusetype></div>
32+
#[repr(C)]
33+
#[derive(Debug, Default, Copy, Clone)]
34+
#[must_use]
35+
pub struct AnnotatedStruct {}
36+
#[test]
37+
fn bindgen_test_layout_AnnotatedStruct() {
38+
assert_eq!(
39+
::std::mem::size_of::<AnnotatedStruct>(),
40+
0usize,
41+
concat!("Size of: ", stringify!(AnnotatedStruct))
42+
);
43+
assert_eq!(
44+
::std::mem::align_of::<AnnotatedStruct>(),
45+
1usize,
46+
concat!("Alignment of ", stringify!(AnnotatedStruct))
47+
);
48+
}
49+
extern "C" {
50+
pub fn return_annotated_struct() -> AnnotatedStruct;
51+
}
52+
#[repr(C)]
53+
#[derive(Debug, Default, Copy, Clone)]
54+
pub struct PlainStruct {}
55+
#[test]
56+
fn bindgen_test_layout_PlainStruct() {
57+
assert_eq!(
58+
::std::mem::size_of::<PlainStruct>(),
59+
0usize,
60+
concat!("Size of: ", stringify!(PlainStruct))
61+
);
62+
assert_eq!(
63+
::std::mem::align_of::<PlainStruct>(),
64+
1usize,
65+
concat!("Alignment of ", stringify!(PlainStruct))
66+
);
67+
}
68+
/// <div rustbindgen mustusetype></div>
69+
pub type TypedefPlainStruct = PlainStruct;
70+
extern "C" {
71+
pub fn return_plain_struct() -> PlainStruct;
72+
}
73+
extern "C" {
74+
#[must_use]
75+
pub fn return_typedef_struct() -> TypedefPlainStruct;
76+
}

tests/headers/func_return_must_use.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// bindgen-flags: --must-use-type 'MustUse.*'
2+
3+
typedef int MustUseInt;
4+
5+
MustUseInt return_int();
6+
7+
struct MustUseStruct;
8+
9+
struct MustUseStruct return_struct();
10+
11+
/**
12+
* <div rustbindgen mustusetype></div>
13+
*/
14+
typedef int AnnotatedInt;
15+
16+
AnnotatedInt return_annotated_int();
17+
18+
int return_plain_int();
19+
20+
/**
21+
* <div rustbindgen mustusetype></div>
22+
*/
23+
struct AnnotatedStruct {};
24+
25+
struct AnnotatedStruct return_annotated_struct();
26+
27+
struct PlainStruct {};
28+
29+
/**
30+
* <div rustbindgen mustusetype></div>
31+
*/
32+
typedef struct PlainStruct TypedefPlainStruct;
33+
34+
struct PlainStruct return_plain_struct();
35+
36+
TypedefPlainStruct return_typedef_struct();

0 commit comments

Comments
 (0)