summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/clang.rs21
-rw-r--r--src/ir/function.rs11
-rw-r--r--tests/expectations/tests/deleted-function.rs91
-rw-r--r--tests/headers/deleted-function.hpp35
4 files changed, 154 insertions, 4 deletions
diff --git a/src/clang.rs b/src/clang.rs
index 66125089..96f77254 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -469,6 +469,27 @@ impl Cursor {
unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 }
}
+ /// Is the referent a defaulted function?
+ pub fn is_defaulted_function(&self) -> bool {
+ unsafe { clang_CXXMethod_isDefaulted(self.x) != 0 }
+ }
+
+ /// Is the referent a deleted function?
+ pub fn is_deleted_function(&self) -> bool {
+ // Unfortunately, libclang doesn't yet have an API for checking if a
+ // member function is deleted, but the following should be a good
+ // enough approximation.
+ // Deleted functions are implicitly inline according to paragraph 4 of
+ // [dcl.fct.def.delete] in the C++ standard. Normal inline functions
+ // have a definition in the same translation unit, so if this is an
+ // inline function without a definition, and it's not a defaulted
+ // function, we can reasonably safely conclude that it's a deleted
+ // function.
+ self.is_inlined_function() &&
+ self.definition().is_none() &&
+ !self.is_defaulted_function()
+ }
+
/// Get the width of this cursor's referent bit field, or `None` if the
/// referent is not a bit field.
pub fn bit_width(&self) -> Option<u32> {
diff --git a/src/ir/function.rs b/src/ir/function.rs
index c0938b65..661ee593 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -597,10 +597,13 @@ impl ClangSubItemParser for Function {
return Err(ParseError::Continue);
}
- if !context.options().generate_inline_functions &&
- cursor.is_inlined_function()
- {
- return Err(ParseError::Continue);
+ if cursor.is_inlined_function() {
+ if !context.options().generate_inline_functions {
+ return Err(ParseError::Continue);
+ }
+ if cursor.is_deleted_function() {
+ return Err(ParseError::Continue);
+ }
}
let linkage = cursor.linkage();
diff --git a/tests/expectations/tests/deleted-function.rs b/tests/expectations/tests/deleted-function.rs
new file mode 100644
index 00000000..96967bb4
--- /dev/null
+++ b/tests/expectations/tests/deleted-function.rs
@@ -0,0 +1,91 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct A {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_A() {
+ assert_eq!(
+ ::std::mem::size_of::<A>(),
+ 1usize,
+ concat!("Size of: ", stringify!(A))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<A>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(A))
+ );
+}
+extern "C" {
+ #[link_name = "\u{1}_ZN1A17inline_definitionEv"]
+ pub fn A_inline_definition(this: *mut A);
+}
+extern "C" {
+ #[link_name = "\u{1}_ZN1A22out_of_line_definitionEv"]
+ pub fn A_out_of_line_definition(this: *mut A);
+}
+impl A {
+ #[inline]
+ pub unsafe fn inline_definition(&mut self) {
+ A_inline_definition(self)
+ }
+ #[inline]
+ pub unsafe fn out_of_line_definition(&mut self) {
+ A_out_of_line_definition(self)
+ }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct B {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_B() {
+ assert_eq!(
+ ::std::mem::size_of::<B>(),
+ 1usize,
+ concat!("Size of: ", stringify!(B))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<B>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(B))
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct C {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_C() {
+ assert_eq!(
+ ::std::mem::size_of::<C>(),
+ 1usize,
+ concat!("Size of: ", stringify!(C))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<C>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(C))
+ );
+}
+extern "C" {
+ #[link_name = "\u{1}_ZN1CC1ERS_"]
+ pub fn C_C(this: *mut C, arg1: *mut C);
+}
+impl C {
+ #[inline]
+ pub unsafe fn new(arg1: *mut C) -> Self {
+ let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
+ C_C(__bindgen_tmp.as_mut_ptr(), arg1);
+ __bindgen_tmp.assume_init()
+ }
+}
diff --git a/tests/headers/deleted-function.hpp b/tests/headers/deleted-function.hpp
new file mode 100644
index 00000000..61848a0a
--- /dev/null
+++ b/tests/headers/deleted-function.hpp
@@ -0,0 +1,35 @@
+// bindgen-flags: --generate-inline-functions -- -std=c++11
+
+class A {
+public:
+ // Deleted function should not get a binding.
+ void deleted() = delete;
+
+ // Inline functions should get bindings, whether they are defined inline
+ // (in the class) or out of line.
+ inline void inline_definition() {}
+ inline void out_of_line_definition();
+
+ // TODO: This is an edge case that we get wrong: An inline function
+ // without a definition in the same translation unit should still get a
+ // binding. We currently can't distinguish this case from a deleted member
+ // function because libclang doesn't provide a direct way to query for
+ // deleted member functions. This seems acceptable, however, as an inline
+ // function without a definition in the same translation unit is unlikely
+ // to be useful in practice.
+ inline void inline_without_definition();
+};
+
+void A::out_of_line_definition() {}
+
+class B {
+public:
+ // Deleted copy constructor should not get a binding.
+ B(B&) = delete;
+};
+
+class C {
+public:
+ // Defaulted copy constructor should get a binding.
+ C(C&) = default;
+}; \ No newline at end of file