Skip to content

Commit ca4e774

Browse files
committed
Add #[must_use] to functions annotated with __attribute__((warn_unused_result))
1 parent 1e527e2 commit ca4e774

8 files changed

+153
-2
lines changed

src/codegen/helpers.rs

+6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ pub mod attributes {
3636
}
3737
}
3838

39+
pub fn must_use() -> quote::Tokens {
40+
quote! {
41+
#[must_use]
42+
}
43+
}
44+
3945
pub fn doc(comment: String) -> quote::Tokens {
4046
// Doc comments are already preprocessed into nice `///` formats by the
4147
// time they get here. Just make sure that we have newlines around it so

src/codegen/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -2154,9 +2154,13 @@ impl MethodCodegen for Method {
21542154
let mut attrs = vec![];
21552155
attrs.push(attributes::inline());
21562156

2157+
if signature.must_use() && ctx.options().rust_features().must_use_function {
2158+
attrs.push(attributes::must_use());
2159+
}
2160+
21572161
let name = ctx.rust_ident(&name);
21582162
methods.push(quote! {
2159-
#[inline]
2163+
#(#attrs)*
21602164
pub unsafe fn #name ( #( #args ),* ) #ret {
21612165
#block
21622166
}
@@ -3374,6 +3378,10 @@ impl CodeGenerator for Function {
33743378

33753379
let mut attributes = vec![];
33763380

3381+
if signature.must_use() && ctx.options().rust_features().must_use_function {
3382+
attributes.push(attributes::must_use());
3383+
}
3384+
33773385
if let Some(comment) = item.comment(ctx) {
33783386
attributes.push(attributes::doc(comment));
33793387
}

src/features.rs

+6
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ macro_rules! rust_target_base {
9898
=> Stable_1_25 => 1.25;
9999
/// Rust stable 1.26
100100
=> Stable_1_26 => 1.26;
101+
/// Rust stable 1.27
102+
=> Stable_1_27 => 1.27;
101103
/// Nightly rust
102104
=> Nightly => nightly;
103105
);
@@ -178,6 +180,10 @@ rust_feature_def!(
178180
/// [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html)
179181
=> i128_and_u128;
180182
}
183+
Stable_1_27 {
184+
/// `must_use` attribute on functions ([PR](https://github.com/rust-lang/rust/pull/48925))
185+
=> must_use_function;
186+
}
181187
Nightly {
182188
/// `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202))
183189
=> thiscall_abi;

src/ir/function.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ pub struct FunctionSig {
221221
/// Whether this function is variadic.
222222
is_variadic: bool,
223223

224+
/// Whether this function's return value must be used.
225+
must_use: bool,
226+
224227
/// The ABI of this function.
225228
abi: Abi,
226229
}
@@ -310,12 +313,14 @@ impl FunctionSig {
310313
return_type: TypeId,
311314
arguments: Vec<(Option<String>, TypeId)>,
312315
is_variadic: bool,
316+
must_use: bool,
313317
abi: Abi,
314318
) -> Self {
315319
FunctionSig {
316320
return_type: return_type,
317321
argument_types: arguments,
318322
is_variadic: is_variadic,
323+
must_use: must_use,
319324
abi: abi,
320325
}
321326
}
@@ -387,6 +392,24 @@ impl FunctionSig {
387392
}
388393
};
389394

395+
let mut must_use = false;
396+
cursor.visit(|cur| {
397+
if cur.kind() == CXCursor_UnexposedAttr {
398+
let attr_warn_unused_result = cur.tokens().map(|tokens| {
399+
tokens.iter().any(|t| {
400+
t.kind == CXToken_Identifier && t.spelling == "warn_unused_result"
401+
})
402+
}).unwrap_or(false);
403+
404+
if attr_warn_unused_result {
405+
must_use = true;
406+
return CXChildVisit_Break;
407+
}
408+
}
409+
410+
CXChildVisit_Continue
411+
});
412+
390413
let is_method = cursor.kind() == CXCursor_CXXMethod;
391414
let is_constructor = cursor.kind() == CXCursor_Constructor;
392415
let is_destructor = cursor.kind() == CXCursor_Destructor;
@@ -458,7 +481,7 @@ impl FunctionSig {
458481
warn!("Unknown calling convention: {:?}", call_conv);
459482
}
460483

461-
Ok(Self::new(ret.into(), args, ty.is_variadic(), abi))
484+
Ok(Self::new(ret.into(), args, ty.is_variadic(), must_use, abi))
462485
}
463486

464487
/// Get this function signature's return type.
@@ -484,6 +507,11 @@ impl FunctionSig {
484507
self.is_variadic && !self.argument_types.is_empty()
485508
}
486509

510+
/// Must this function's return value be used?
511+
pub fn must_use(&self) -> bool {
512+
self.must_use
513+
}
514+
487515
/// Are function pointers with this signature able to derive Rust traits?
488516
/// Rust only supports deriving traits for function pointers with a limited
489517
/// number of parameters and a couple ABIs.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
9+
10+
#[repr(C)]
11+
#[derive(Debug, Default, Copy, Clone)]
12+
pub struct Foo {
13+
pub _address: u8,
14+
}
15+
#[test]
16+
fn bindgen_test_layout_Foo() {
17+
assert_eq!(
18+
::std::mem::size_of::<Foo>(),
19+
1usize,
20+
concat!("Size of: ", stringify!(Foo))
21+
);
22+
assert_eq!(
23+
::std::mem::align_of::<Foo>(),
24+
1usize,
25+
concat!("Alignment of ", stringify!(Foo))
26+
);
27+
}
28+
extern "C" {
29+
#[must_use]
30+
#[link_name = "\u{1}_ZN3Foo3fooEi"]
31+
pub fn Foo_foo(this: *mut Foo, arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
32+
}
33+
impl Foo {
34+
#[inline]
35+
#[must_use]
36+
pub unsafe fn foo(&mut self, arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int {
37+
Foo_foo(self, arg1)
38+
}
39+
}
40+
extern "C" {
41+
#[must_use]
42+
#[link_name = "\u{1}_Z3fooi"]
43+
pub fn foo(arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
9+
10+
#[repr(C)]
11+
#[derive(Debug, Default, Copy, Clone)]
12+
pub struct Foo {
13+
pub _address: u8,
14+
}
15+
#[test]
16+
fn bindgen_test_layout_Foo() {
17+
assert_eq!(
18+
::std::mem::size_of::<Foo>(),
19+
1usize,
20+
concat!("Size of: ", stringify!(Foo))
21+
);
22+
assert_eq!(
23+
::std::mem::align_of::<Foo>(),
24+
1usize,
25+
concat!("Alignment of ", stringify!(Foo))
26+
);
27+
}
28+
extern "C" {
29+
#[link_name = "\u{1}_ZN3Foo3fooEi"]
30+
pub fn Foo_foo(this: *mut Foo, arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
31+
}
32+
impl Foo {
33+
#[inline]
34+
pub unsafe fn foo(&mut self, arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int {
35+
Foo_foo(self, arg1)
36+
}
37+
}
38+
extern "C" {
39+
#[link_name = "\u{1}_Z3fooi"]
40+
pub fn foo(arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// bindgen-flags: --rust-target 1.27
2+
3+
class Foo {
4+
public:
5+
__attribute__((warn_unused_result))
6+
int foo(int);
7+
};
8+
9+
__attribute__((warn_unused_result))
10+
int foo(int);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class Foo {
2+
public:
3+
__attribute__((warn_unused_result))
4+
int foo(int);
5+
};
6+
7+
__attribute__((warn_unused_result))
8+
int foo(int);

0 commit comments

Comments
 (0)