Skip to content

Commit 910d2be

Browse files
martinboehmeemilio
authored andcommitted
Don't generate bindings for deleted member functions. (rust-lang#2044)
Closes rust-lang#2044 Fixes rust-lang#2043 See rust-lang#2043 for details.
1 parent f26d57d commit 910d2be

File tree

4 files changed

+154
-4
lines changed

4 files changed

+154
-4
lines changed

src/clang.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,27 @@ impl Cursor {
469469
unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 }
470470
}
471471

472+
/// Is the referent a defaulted function?
473+
pub fn is_defaulted_function(&self) -> bool {
474+
unsafe { clang_CXXMethod_isDefaulted(self.x) != 0 }
475+
}
476+
477+
/// Is the referent a deleted function?
478+
pub fn is_deleted_function(&self) -> bool {
479+
// Unfortunately, libclang doesn't yet have an API for checking if a
480+
// member function is deleted, but the following should be a good
481+
// enough approximation.
482+
// Deleted functions are implicitly inline according to paragraph 4 of
483+
// [dcl.fct.def.delete] in the C++ standard. Normal inline functions
484+
// have a definition in the same translation unit, so if this is an
485+
// inline function without a definition, and it's not a defaulted
486+
// function, we can reasonably safely conclude that it's a deleted
487+
// function.
488+
self.is_inlined_function() &&
489+
self.definition().is_none() &&
490+
!self.is_defaulted_function()
491+
}
492+
472493
/// Get the width of this cursor's referent bit field, or `None` if the
473494
/// referent is not a bit field.
474495
pub fn bit_width(&self) -> Option<u32> {

src/ir/function.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -597,10 +597,13 @@ impl ClangSubItemParser for Function {
597597
return Err(ParseError::Continue);
598598
}
599599

600-
if !context.options().generate_inline_functions &&
601-
cursor.is_inlined_function()
602-
{
603-
return Err(ParseError::Continue);
600+
if cursor.is_inlined_function() {
601+
if !context.options().generate_inline_functions {
602+
return Err(ParseError::Continue);
603+
}
604+
if cursor.is_deleted_function() {
605+
return Err(ParseError::Continue);
606+
}
604607
}
605608

606609
let linkage = cursor.linkage();
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#![allow(
2+
dead_code,
3+
non_snake_case,
4+
non_camel_case_types,
5+
non_upper_case_globals
6+
)]
7+
8+
#[repr(C)]
9+
#[derive(Debug, Default, Copy, Clone)]
10+
pub struct A {
11+
pub _address: u8,
12+
}
13+
#[test]
14+
fn bindgen_test_layout_A() {
15+
assert_eq!(
16+
::std::mem::size_of::<A>(),
17+
1usize,
18+
concat!("Size of: ", stringify!(A))
19+
);
20+
assert_eq!(
21+
::std::mem::align_of::<A>(),
22+
1usize,
23+
concat!("Alignment of ", stringify!(A))
24+
);
25+
}
26+
extern "C" {
27+
#[link_name = "\u{1}_ZN1A17inline_definitionEv"]
28+
pub fn A_inline_definition(this: *mut A);
29+
}
30+
extern "C" {
31+
#[link_name = "\u{1}_ZN1A22out_of_line_definitionEv"]
32+
pub fn A_out_of_line_definition(this: *mut A);
33+
}
34+
impl A {
35+
#[inline]
36+
pub unsafe fn inline_definition(&mut self) {
37+
A_inline_definition(self)
38+
}
39+
#[inline]
40+
pub unsafe fn out_of_line_definition(&mut self) {
41+
A_out_of_line_definition(self)
42+
}
43+
}
44+
#[repr(C)]
45+
#[derive(Debug, Default, Copy, Clone)]
46+
pub struct B {
47+
pub _address: u8,
48+
}
49+
#[test]
50+
fn bindgen_test_layout_B() {
51+
assert_eq!(
52+
::std::mem::size_of::<B>(),
53+
1usize,
54+
concat!("Size of: ", stringify!(B))
55+
);
56+
assert_eq!(
57+
::std::mem::align_of::<B>(),
58+
1usize,
59+
concat!("Alignment of ", stringify!(B))
60+
);
61+
}
62+
#[repr(C)]
63+
#[derive(Debug, Default, Copy, Clone)]
64+
pub struct C {
65+
pub _address: u8,
66+
}
67+
#[test]
68+
fn bindgen_test_layout_C() {
69+
assert_eq!(
70+
::std::mem::size_of::<C>(),
71+
1usize,
72+
concat!("Size of: ", stringify!(C))
73+
);
74+
assert_eq!(
75+
::std::mem::align_of::<C>(),
76+
1usize,
77+
concat!("Alignment of ", stringify!(C))
78+
);
79+
}
80+
extern "C" {
81+
#[link_name = "\u{1}_ZN1CC1ERS_"]
82+
pub fn C_C(this: *mut C, arg1: *mut C);
83+
}
84+
impl C {
85+
#[inline]
86+
pub unsafe fn new(arg1: *mut C) -> Self {
87+
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
88+
C_C(__bindgen_tmp.as_mut_ptr(), arg1);
89+
__bindgen_tmp.assume_init()
90+
}
91+
}

tests/headers/deleted-function.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// bindgen-flags: --generate-inline-functions -- -std=c++11
2+
3+
class A {
4+
public:
5+
// Deleted function should not get a binding.
6+
void deleted() = delete;
7+
8+
// Inline functions should get bindings, whether they are defined inline
9+
// (in the class) or out of line.
10+
inline void inline_definition() {}
11+
inline void out_of_line_definition();
12+
13+
// TODO: This is an edge case that we get wrong: An inline function
14+
// without a definition in the same translation unit should still get a
15+
// binding. We currently can't distinguish this case from a deleted member
16+
// function because libclang doesn't provide a direct way to query for
17+
// deleted member functions. This seems acceptable, however, as an inline
18+
// function without a definition in the same translation unit is unlikely
19+
// to be useful in practice.
20+
inline void inline_without_definition();
21+
};
22+
23+
void A::out_of_line_definition() {}
24+
25+
class B {
26+
public:
27+
// Deleted copy constructor should not get a binding.
28+
B(B&) = delete;
29+
};
30+
31+
class C {
32+
public:
33+
// Defaulted copy constructor should get a binding.
34+
C(C&) = default;
35+
};

0 commit comments

Comments
 (0)