summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/clang.rs25
-rw-r--r--src/codegen/helpers.rs6
-rw-r--r--src/codegen/mod.rs10
-rw-r--r--src/features.rs6
-rw-r--r--src/ir/function.rs21
-rw-r--r--tests/expectations/tests/attribute_warn_unused_result.rs44
-rw-r--r--tests/expectations/tests/attribute_warn_unused_result_pre_1_27.rs41
-rw-r--r--tests/headers/attribute_warn_unused_result.hpp10
-rw-r--r--tests/headers/attribute_warn_unused_result_pre_1_27.hpp8
9 files changed, 165 insertions, 6 deletions
diff --git a/src/clang.rs b/src/clang.rs
index f8f7e581..a31cba31 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -499,6 +499,31 @@ impl Cursor {
}
}
+ /// Does this cursor have the given simple attribute?
+ ///
+ /// Note that this will only work for attributes that don't have an existing libclang
+ /// CursorKind, e.g. pure, const, etc.
+ pub fn has_simple_attr(&self, attr: &str) -> bool {
+ let mut found_attr = false;
+ self.visit(|cur| {
+ if cur.kind() == CXCursor_UnexposedAttr {
+ found_attr = cur.tokens().map(|tokens| {
+ tokens.iter().any(|t| {
+ t.kind == CXToken_Identifier && t.spelling == attr
+ })
+ }).unwrap_or(false);
+
+ if found_attr {
+ return CXChildVisit_Break;
+ }
+ }
+
+ CXChildVisit_Continue
+ });
+
+ found_attr
+ }
+
/// Given that this cursor's referent is a `typedef`, get the `Type` that is
/// being aliased.
pub fn typedef_type(&self) -> Option<Type> {
diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs
index 343f1e30..02909d57 100644
--- a/src/codegen/helpers.rs
+++ b/src/codegen/helpers.rs
@@ -36,6 +36,12 @@ pub mod attributes {
}
}
+ pub fn must_use() -> quote::Tokens {
+ quote! {
+ #[must_use]
+ }
+ }
+
pub fn doc(comment: String) -> quote::Tokens {
// Doc comments are already preprocessed into nice `///` formats by the
// time they get here. Just make sure that we have newlines around it so
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 34b5b4d9..073745b1 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -2154,9 +2154,13 @@ impl MethodCodegen for Method {
let mut attrs = vec![];
attrs.push(attributes::inline());
+ if signature.must_use() && ctx.options().rust_features().must_use_function {
+ attrs.push(attributes::must_use());
+ }
+
let name = ctx.rust_ident(&name);
methods.push(quote! {
- #[inline]
+ #(#attrs)*
pub unsafe fn #name ( #( #args ),* ) #ret {
#block
}
@@ -3374,6 +3378,10 @@ 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 let Some(comment) = item.comment(ctx) {
attributes.push(attributes::doc(comment));
}
diff --git a/src/features.rs b/src/features.rs
index 671464ab..6f10f11b 100644
--- a/src/features.rs
+++ b/src/features.rs
@@ -98,6 +98,8 @@ macro_rules! rust_target_base {
=> Stable_1_25 => 1.25;
/// Rust stable 1.26
=> Stable_1_26 => 1.26;
+ /// Rust stable 1.27
+ => Stable_1_27 => 1.27;
/// Nightly rust
=> Nightly => nightly;
);
@@ -178,6 +180,10 @@ rust_feature_def!(
/// [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html)
=> i128_and_u128;
}
+ Stable_1_27 {
+ /// `must_use` attribute on functions ([PR](https://github.com/rust-lang/rust/pull/48925))
+ => must_use_function;
+ }
Nightly {
/// `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202))
=> thiscall_abi;
diff --git a/src/ir/function.rs b/src/ir/function.rs
index 883203e9..0b83a74d 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -221,6 +221,9 @@ pub struct FunctionSig {
/// Whether this function is variadic.
is_variadic: bool,
+ /// Whether this function's return value must be used.
+ must_use: bool,
+
/// The ABI of this function.
abi: Abi,
}
@@ -308,14 +311,16 @@ impl FunctionSig {
/// Construct a new function signature.
pub fn new(
return_type: TypeId,
- arguments: Vec<(Option<String>, TypeId)>,
+ argument_types: Vec<(Option<String>, TypeId)>,
is_variadic: bool,
+ must_use: bool,
abi: Abi,
) -> Self {
FunctionSig {
- return_type: return_type,
- argument_types: arguments,
- is_variadic: is_variadic,
+ return_type,
+ argument_types,
+ is_variadic,
+ must_use,
abi: abi,
}
}
@@ -387,6 +392,7 @@ impl FunctionSig {
}
};
+ let must_use = cursor.has_simple_attr("warn_unused_result");
let is_method = cursor.kind() == CXCursor_CXXMethod;
let is_constructor = cursor.kind() == CXCursor_Constructor;
let is_destructor = cursor.kind() == CXCursor_Destructor;
@@ -458,7 +464,7 @@ impl FunctionSig {
warn!("Unknown calling convention: {:?}", call_conv);
}
- Ok(Self::new(ret.into(), args, ty.is_variadic(), abi))
+ Ok(Self::new(ret.into(), args, ty.is_variadic(), must_use, abi))
}
/// Get this function signature's return type.
@@ -484,6 +490,11 @@ impl FunctionSig {
self.is_variadic && !self.argument_types.is_empty()
}
+ /// Must this function's return value be used?
+ pub fn must_use(&self) -> bool {
+ self.must_use
+ }
+
/// Are function pointers with this signature able to derive Rust traits?
/// Rust only supports deriving traits for function pointers with a limited
/// number of parameters and a couple ABIs.
diff --git a/tests/expectations/tests/attribute_warn_unused_result.rs b/tests/expectations/tests/attribute_warn_unused_result.rs
new file mode 100644
index 00000000..35ac4dd2
--- /dev/null
+++ b/tests/expectations/tests/attribute_warn_unused_result.rs
@@ -0,0 +1,44 @@
+/* automatically generated by rust-bindgen */
+
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Foo {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_Foo() {
+ assert_eq!(
+ ::std::mem::size_of::<Foo>(),
+ 1usize,
+ concat!("Size of: ", stringify!(Foo))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Foo>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(Foo))
+ );
+}
+extern "C" {
+ #[must_use]
+ #[link_name = "\u{1}_ZN3Foo3fooEi"]
+ pub fn Foo_foo(this: *mut Foo, arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
+}
+impl Foo {
+ #[inline]
+ #[must_use]
+ pub unsafe fn foo(&mut self, arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int {
+ Foo_foo(self, arg1)
+ }
+}
+extern "C" {
+ #[must_use]
+ #[link_name = "\u{1}_Z3fooi"]
+ pub fn foo(arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
+}
diff --git a/tests/expectations/tests/attribute_warn_unused_result_pre_1_27.rs b/tests/expectations/tests/attribute_warn_unused_result_pre_1_27.rs
new file mode 100644
index 00000000..c60b19c6
--- /dev/null
+++ b/tests/expectations/tests/attribute_warn_unused_result_pre_1_27.rs
@@ -0,0 +1,41 @@
+/* automatically generated by rust-bindgen */
+
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Foo {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_Foo() {
+ assert_eq!(
+ ::std::mem::size_of::<Foo>(),
+ 1usize,
+ concat!("Size of: ", stringify!(Foo))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Foo>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(Foo))
+ );
+}
+extern "C" {
+ #[link_name = "\u{1}_ZN3Foo3fooEi"]
+ pub fn Foo_foo(this: *mut Foo, arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
+}
+impl Foo {
+ #[inline]
+ pub unsafe fn foo(&mut self, arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int {
+ Foo_foo(self, arg1)
+ }
+}
+extern "C" {
+ #[link_name = "\u{1}_Z3fooi"]
+ pub fn foo(arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
+}
diff --git a/tests/headers/attribute_warn_unused_result.hpp b/tests/headers/attribute_warn_unused_result.hpp
new file mode 100644
index 00000000..21550307
--- /dev/null
+++ b/tests/headers/attribute_warn_unused_result.hpp
@@ -0,0 +1,10 @@
+// bindgen-flags: --rust-target 1.27
+
+class Foo {
+public:
+ __attribute__((warn_unused_result))
+ int foo(int);
+};
+
+__attribute__((warn_unused_result))
+int foo(int);
diff --git a/tests/headers/attribute_warn_unused_result_pre_1_27.hpp b/tests/headers/attribute_warn_unused_result_pre_1_27.hpp
new file mode 100644
index 00000000..25127d9c
--- /dev/null
+++ b/tests/headers/attribute_warn_unused_result_pre_1_27.hpp
@@ -0,0 +1,8 @@
+class Foo {
+public:
+ __attribute__((warn_unused_result))
+ int foo(int);
+};
+
+__attribute__((warn_unused_result))
+int foo(int);