Skip to content

Commit f4d2d6a

Browse files
committed
Don't generate symbols for pure virtual functions.
Fixes rust-lang#1197.
1 parent 3dffd1c commit f4d2d6a

File tree

9 files changed

+125
-35
lines changed

9 files changed

+125
-35
lines changed

bindgen-integration/cpp/Test.h

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class Test {
1515
static const int* countdown();
1616
};
1717

18+
class ITest {
19+
virtual void foo() = 0;
20+
};
21+
1822
namespace testing {
1923

2024
typedef Test TypeAlias;

src/clang.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -606,11 +606,16 @@ impl Cursor {
606606
unsafe { clang_CXXMethod_isConst(self.x) != 0 }
607607
}
608608

609-
/// Is this cursor's referent a member function that is declared `const`?
609+
/// Is this cursor's referent a member function that is virtual?
610610
pub fn method_is_virtual(&self) -> bool {
611611
unsafe { clang_CXXMethod_isVirtual(self.x) != 0 }
612612
}
613613

614+
/// Is this cursor's referent a member function that is pure virtual?
615+
pub fn method_is_pure_virtual(&self) -> bool {
616+
unsafe { clang_CXXMethod_isPureVirtual(self.x) != 0 }
617+
}
618+
614619
/// Is this cursor's referent a struct or class with virtual members?
615620
pub fn is_virtual_base(&self) -> bool {
616621
unsafe { clang_isVirtualBase(self.x) != 0 }

src/codegen/mod.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault,
2626
CanDerivePartialEq, CanDeriveEq, CanDerive};
2727
use ir::dot;
2828
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
29-
use ir::function::{Abi, Function, FunctionSig, Linkage};
29+
use ir::function::{Abi, Function, FunctionKind, FunctionSig, Linkage};
3030
use ir::int::IntKind;
3131
use ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
3232
use ir::item_kind::ItemKind;
@@ -1878,13 +1878,8 @@ impl CodeGenerator for CompInfo {
18781878
}
18791879

18801880
if ctx.options().codegen_config.destructors {
1881-
if let Some((is_virtual, destructor)) = self.destructor() {
1882-
let kind = if is_virtual {
1883-
MethodKind::VirtualDestructor
1884-
} else {
1885-
MethodKind::Destructor
1886-
};
1887-
1881+
if let Some((kind, destructor)) = self.destructor() {
1882+
debug_assert!(kind.is_destructor());
18881883
Method::new(kind, destructor, false).codegen_method(
18891884
ctx,
18901885
&mut methods,
@@ -1990,9 +1985,9 @@ impl MethodCodegen for Method {
19901985
match self.kind() {
19911986
MethodKind::Constructor => cc.constructors,
19921987
MethodKind::Destructor => cc.destructors,
1993-
MethodKind::VirtualDestructor => cc.destructors,
1988+
MethodKind::VirtualDestructor { .. } => cc.destructors,
19941989
MethodKind::Static | MethodKind::Normal |
1995-
MethodKind::Virtual => cc.methods,
1990+
MethodKind::Virtual { .. } => cc.methods,
19961991
}
19971992
});
19981993

@@ -3174,6 +3169,15 @@ impl CodeGenerator for Function {
31743169
Linkage::External => {}
31753170
}
31763171

3172+
// Pure virtual methods have no actual symbol, so we can't generate
3173+
// something meaningful for them.
3174+
match self.kind() {
3175+
FunctionKind::Method(ref method_kind) if method_kind.is_pure_virtual() => {
3176+
return;
3177+
}
3178+
_ => {},
3179+
}
3180+
31773181
// Similar to static member variables in a class template, we can't
31783182
// generate bindings to template functions, because the set of
31793183
// instantiations is open ended and we have no way of knowing which

src/ir/comp.rs

+52-19
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,40 @@ pub enum MethodKind {
3737
/// A destructor.
3838
Destructor,
3939
/// A virtual destructor.
40-
VirtualDestructor,
40+
VirtualDestructor {
41+
/// Whether it's pure virtual.
42+
pure_virtual: bool,
43+
},
4144
/// A static method.
4245
Static,
4346
/// A normal method.
4447
Normal,
4548
/// A virtual method.
46-
Virtual,
49+
Virtual {
50+
/// Whether it's pure virtual.
51+
pure_virtual: bool,
52+
},
53+
}
54+
55+
56+
impl MethodKind {
57+
/// Is this a destructor method?
58+
pub fn is_destructor(&self) -> bool {
59+
match *self {
60+
MethodKind::Destructor |
61+
MethodKind::VirtualDestructor { .. } => true,
62+
_ => false,
63+
}
64+
}
65+
66+
/// Is this a pure virtual method?
67+
pub fn is_pure_virtual(&self) -> bool {
68+
match *self {
69+
MethodKind::Virtual { pure_virtual } |
70+
MethodKind::VirtualDestructor { pure_virtual } => pure_virtual,
71+
_ => false,
72+
}
73+
}
4774
}
4875

4976
/// A struct representing a C++ method, either static, normal, or virtual.
@@ -73,21 +100,18 @@ impl Method {
73100
self.kind
74101
}
75102

76-
/// Is this a destructor method?
77-
pub fn is_destructor(&self) -> bool {
78-
self.kind == MethodKind::Destructor ||
79-
self.kind == MethodKind::VirtualDestructor
80-
}
81-
82103
/// Is this a constructor?
83104
pub fn is_constructor(&self) -> bool {
84105
self.kind == MethodKind::Constructor
85106
}
86107

87108
/// Is this a virtual method?
88109
pub fn is_virtual(&self) -> bool {
89-
self.kind == MethodKind::Virtual ||
90-
self.kind == MethodKind::VirtualDestructor
110+
match self.kind {
111+
MethodKind::Virtual { .. } |
112+
MethodKind::VirtualDestructor { .. } => true,
113+
_ => false,
114+
}
91115
}
92116

93117
/// Is this a static method?
@@ -960,7 +984,7 @@ pub struct CompInfo {
960984

961985
/// The destructor of this type. The bool represents whether this destructor
962986
/// is virtual.
963-
destructor: Option<(bool, FunctionId)>,
987+
destructor: Option<(MethodKind, FunctionId)>,
964988

965989
/// Vector of classes this one inherits from.
966990
base_members: Vec<Base>,
@@ -1104,7 +1128,7 @@ impl CompInfo {
11041128
}
11051129

11061130
/// Get this type's destructor.
1107-
pub fn destructor(&self) -> Option<(bool, FunctionId)> {
1131+
pub fn destructor(&self) -> Option<(MethodKind, FunctionId)> {
11081132
self.destructor
11091133
}
11101134

@@ -1355,14 +1379,23 @@ impl CompInfo {
13551379
ci.constructors.push(signature);
13561380
}
13571381
CXCursor_Destructor => {
1358-
ci.destructor = Some((is_virtual, signature));
1382+
let kind = if is_virtual {
1383+
MethodKind::VirtualDestructor {
1384+
pure_virtual: cur.method_is_pure_virtual(),
1385+
}
1386+
} else {
1387+
MethodKind::Destructor
1388+
};
1389+
ci.destructor = Some((kind, signature));
13591390
}
13601391
CXCursor_CXXMethod => {
13611392
let is_const = cur.method_is_const();
13621393
let method_kind = if is_static {
13631394
MethodKind::Static
13641395
} else if is_virtual {
1365-
MethodKind::Virtual
1396+
MethodKind::Virtual {
1397+
pure_virtual: cur.method_is_pure_virtual(),
1398+
}
13661399
} else {
13671400
MethodKind::Normal
13681401
};
@@ -1658,11 +1691,11 @@ impl Trace for CompInfo {
16581691
}
16591692

16601693
for method in self.methods() {
1661-
if method.is_destructor() {
1662-
tracer.visit_kind(method.signature.into(), EdgeKind::Destructor);
1663-
} else {
1664-
tracer.visit_kind(method.signature.into(), EdgeKind::Method);
1665-
}
1694+
tracer.visit_kind(method.signature.into(), EdgeKind::Method);
1695+
}
1696+
1697+
if let Some((_kind, signature)) = self.destructor() {
1698+
tracer.visit_kind(signature.into(), EdgeKind::Destructor);
16661699
}
16671700

16681701
for ctor in self.constructors() {

src/ir/function.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,26 @@ pub enum FunctionKind {
2727

2828
impl FunctionKind {
2929
fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> {
30+
// FIXME(emilio): Deduplicate logic with `ir::comp`.
3031
Some(match cursor.kind() {
3132
clang_sys::CXCursor_FunctionDecl => FunctionKind::Function,
3233
clang_sys::CXCursor_Constructor => FunctionKind::Method(
3334
MethodKind::Constructor,
3435
),
3536
clang_sys::CXCursor_Destructor => FunctionKind::Method(
36-
MethodKind::Destructor,
37+
if cursor.method_is_virtual() {
38+
MethodKind::VirtualDestructor {
39+
pure_virtual: cursor.method_is_pure_virtual(),
40+
}
41+
} else {
42+
MethodKind::Destructor
43+
}
3744
),
3845
clang_sys::CXCursor_CXXMethod => {
3946
if cursor.method_is_virtual() {
40-
FunctionKind::Method(MethodKind::Virtual)
47+
FunctionKind::Method(MethodKind::Virtual {
48+
pure_virtual: cursor.method_is_pure_virtual(),
49+
})
4150
} else if cursor.method_is_static() {
4251
FunctionKind::Method(MethodKind::Static)
4352
} else {

src/ir/item.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -944,12 +944,12 @@ impl Item {
944944
cc.constructors
945945
}
946946
FunctionKind::Method(MethodKind::Destructor) |
947-
FunctionKind::Method(MethodKind::VirtualDestructor) => {
947+
FunctionKind::Method(MethodKind::VirtualDestructor { .. }) => {
948948
cc.destructors
949949
}
950950
FunctionKind::Method(MethodKind::Static) |
951951
FunctionKind::Method(MethodKind::Normal) |
952-
FunctionKind::Method(MethodKind::Virtual) => cc.methods,
952+
FunctionKind::Method(MethodKind::Virtual { .. }) => cc.methods,
953953
}
954954
}
955955
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
4+
5+
#[repr(C)]
6+
pub struct Foo__bindgen_vtable(::std::os::raw::c_void);
7+
#[repr(C)]
8+
#[derive(Debug)]
9+
pub struct Foo {
10+
pub vtable_: *const Foo__bindgen_vtable,
11+
}
12+
#[test]
13+
fn bindgen_test_layout_Foo() {
14+
assert_eq!(
15+
::std::mem::size_of::<Foo>(),
16+
8usize,
17+
concat!("Size of: ", stringify!(Foo))
18+
);
19+
assert_eq!(
20+
::std::mem::align_of::<Foo>(),
21+
8usize,
22+
concat!("Alignment of ", stringify!(Foo))
23+
);
24+
}
25+
impl Default for Foo {
26+
fn default() -> Self {
27+
unsafe { ::std::mem::zeroed() }
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class Foo
2+
{
3+
public:
4+
virtual void Bar() = 0;
5+
virtual ~Foo() = 0;
6+
};

tests/headers/ref_argument_array.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
#define NSID_LENGTH 10
33
class nsID {
44
public:
5-
virtual void ToProvidedString(char (&aDest)[NSID_LENGTH]) = 0;
5+
virtual void ToProvidedString(char (&aDest)[NSID_LENGTH]);
66
};

0 commit comments

Comments
 (0)