summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-04-03 18:11:11 -0500
committerGitHub <noreply@github.com>2017-04-03 18:11:11 -0500
commit5e85271697255498603e852eaa0723da5f41f1bf (patch)
tree300e99521f0ff6baf2677363fb59696d283283e8
parentd4fce37939fbcebd04e7b7efec6930cfd717b13d (diff)
parent1f53966ee6b872b7443b335a84d9cf1b57394f13 (diff)
Auto merge of #608 - emilio:destructor-codegen, r=fitzgen
Destructor codegen Based on #542, and on top of #606, with a bunch more tests and fixes.
-rw-r--r--bindgen-integration/cpp/Test.cc11
-rw-r--r--bindgen-integration/cpp/Test.h8
-rwxr-xr-xbindgen-integration/src/lib.rs18
-rw-r--r--src/codegen/mod.rs26
-rw-r--r--src/ir/comp.rs28
-rw-r--r--src/ir/function.rs54
-rw-r--r--src/lib.rs4
-rw-r--r--src/options.rs6
-rw-r--r--tests/expectations/tests/bitfield-method-same-name.rs6
-rw-r--r--tests/expectations/tests/class.rs6
-rw-r--r--tests/expectations/tests/class_with_typedef.rs8
-rw-r--r--tests/expectations/tests/gen-constructors-neg.rs21
-rw-r--r--tests/expectations/tests/gen-constructors.rs33
-rw-r--r--tests/expectations/tests/gen-destructors-neg.rs23
-rw-r--r--tests/expectations/tests/gen-destructors.rs31
-rw-r--r--tests/expectations/tests/issue-410.rs2
-rw-r--r--tests/expectations/tests/method-mangling.rs4
-rw-r--r--tests/expectations/tests/namespace.rs2
-rw-r--r--tests/expectations/tests/public-dtor.rs8
-rw-r--r--tests/expectations/tests/union_dtor.rs10
-rw-r--r--tests/headers/gen-constructors-neg.hpp6
-rw-r--r--tests/headers/gen-constructors.hpp6
-rw-r--r--tests/headers/gen-destructors-neg.hpp9
-rw-r--r--tests/headers/gen-destructors.hpp7
24 files changed, 307 insertions, 30 deletions
diff --git a/bindgen-integration/cpp/Test.cc b/bindgen-integration/cpp/Test.cc
index 1d962406..7b0ec4ad 100644
--- a/bindgen-integration/cpp/Test.cc
+++ b/bindgen-integration/cpp/Test.cc
@@ -21,6 +21,15 @@ Test::Test(double foo)
, m_double(foo)
{}
+AutoRestoreBool::AutoRestoreBool(bool* ptr)
+ : m_ptr(ptr)
+ , m_value(*ptr)
+{}
+
+AutoRestoreBool::~AutoRestoreBool() {
+ *m_ptr = m_value;
+}
+
namespace bitfields {
bool
@@ -47,4 +56,4 @@ Third::assert(int first, bool second, ItemKind third)
kind == third;
}
-}
+} // namespace bitfields
diff --git a/bindgen-integration/cpp/Test.h b/bindgen-integration/cpp/Test.h
index 310478bb..01c7aea1 100644
--- a/bindgen-integration/cpp/Test.h
+++ b/bindgen-integration/cpp/Test.h
@@ -64,3 +64,11 @@ struct Third {
};
} // namespace bitfields
+
+struct AutoRestoreBool {
+ bool* m_ptr;
+ bool m_value;
+
+ AutoRestoreBool(bool*);
+ ~AutoRestoreBool();
+};
diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs
index 8d7eb753..be3c8451 100755
--- a/bindgen-integration/src/lib.rs
+++ b/bindgen-integration/src/lib.rs
@@ -101,3 +101,21 @@ fn test_bitfields_third() {
bindings::bitfields::ItemKind::ITEM_KIND_TRES)
});
}
+
+impl Drop for bindings::AutoRestoreBool {
+ fn drop(&mut self) {
+ unsafe { bindings::AutoRestoreBool::destruct(self) }
+ }
+}
+
+#[test]
+fn test_destructors() {
+ let mut v = true;
+
+ {
+ let auto_restore = unsafe { bindings::AutoRestoreBool::new(&mut v) };
+ v = false;
+ }
+
+ assert!(v, "Should've been restored when going out of scope");
+}
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index fb6c839d..5586c146 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -1597,6 +1597,24 @@ impl CodeGenerator for CompInfo {
self);
}
}
+
+ if ctx.options().codegen_config.destructors {
+ if let Some((is_virtual, destructor)) = self.destructor() {
+ let kind = if is_virtual {
+ MethodKind::VirtualDestructor
+ } else {
+ MethodKind::Destructor
+ };
+
+ Method::new(kind, destructor, false)
+ .codegen_method(ctx,
+ &mut methods,
+ &mut method_names,
+ result,
+ whitelisted_items,
+ self);
+ }
+ }
}
// NB: We can't use to_rust_ty here since for opaque types this tries to
@@ -1693,6 +1711,7 @@ impl MethodCodegen for Method {
if self.is_virtual() {
return; // FIXME
}
+
// First of all, output the actual function.
let function_item = ctx.resolve_item(self.signature());
function_item.codegen(ctx, result, whitelisted_items, &());
@@ -1701,6 +1720,7 @@ impl MethodCodegen for Method {
let signature_item = ctx.resolve_item(function.signature());
let mut name = match self.kind() {
MethodKind::Constructor => "new".into(),
+ MethodKind::Destructor => "destruct".into(),
_ => function.name().to_owned(),
};
@@ -1801,11 +1821,7 @@ impl MethodCodegen for Method {
exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp);
} else if !self.is_static() {
assert!(!exprs.is_empty());
- exprs[0] = if self.is_const() {
- quote_expr!(ctx.ext_cx(), &*self)
- } else {
- quote_expr!(ctx.ext_cx(), &mut *self)
- };
+ exprs[0] = quote_expr!(ctx.ext_cx(), self);
};
let call = aster::expr::ExprBuilder::new()
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index 9a6548a7..2c7b6de2 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -26,6 +26,10 @@ pub enum MethodKind {
/// A constructor. We represent it as method for convenience, to avoid code
/// duplication.
Constructor,
+ /// A destructor.
+ Destructor,
+ /// A virtual destructor.
+ VirtualDestructor,
/// A static method.
Static,
/// A normal method.
@@ -61,6 +65,12 @@ impl Method {
self.kind
}
+ /// Is this a destructor method?
+ pub fn is_destructor(&self) -> bool {
+ self.kind == MethodKind::Destructor ||
+ self.kind == MethodKind::VirtualDestructor
+ }
+
/// Is this a constructor?
pub fn is_constructor(&self) -> bool {
self.kind == MethodKind::Constructor
@@ -68,7 +78,8 @@ impl Method {
/// Is this a virtual method?
pub fn is_virtual(&self) -> bool {
- self.kind == MethodKind::Virtual
+ self.kind == MethodKind::Virtual ||
+ self.kind == MethodKind::VirtualDestructor
}
/// Is this a static method?
@@ -250,6 +261,10 @@ pub struct CompInfo {
/// The different constructors this struct or class contains.
constructors: Vec<ItemId>,
+ /// The destructor of this type. The bool represents whether this destructor
+ /// is virtual.
+ destructor: Option<(bool, ItemId)>,
+
/// Vector of classes this one inherits from.
base_members: Vec<Base>,
@@ -321,6 +336,7 @@ impl CompInfo {
template_params: vec![],
methods: vec![],
constructors: vec![],
+ destructor: None,
base_members: vec![],
inner_types: vec![],
inner_vars: vec![],
@@ -434,6 +450,11 @@ impl CompInfo {
&self.constructors
}
+ /// Get this type's destructor.
+ pub fn destructor(&self) -> Option<(bool, ItemId)> {
+ self.destructor
+ }
+
/// What kind of compound type is this?
pub fn kind(&self) -> CompKind {
self.kind
@@ -657,8 +678,9 @@ impl CompInfo {
CXCursor_Constructor => {
ci.constructors.push(signature);
}
- // TODO(emilio): Bind the destructor?
- CXCursor_Destructor => {}
+ CXCursor_Destructor => {
+ ci.destructor = Some((is_virtual, signature));
+ }
CXCursor_CXXMethod => {
let is_const = cur.method_is_const();
let method_kind = if is_static {
diff --git a/src/ir/function.rs b/src/ir/function.rs
index fd88b657..0809b3c2 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -114,6 +114,7 @@ fn get_abi(cc: CXCallingConv) -> Option<abi::Abi> {
pub fn cursor_mangling(ctx: &BindgenContext,
cursor: &clang::Cursor)
-> Option<String> {
+ use clang_sys;
if !ctx.options().enable_mangling {
return None;
}
@@ -131,10 +132,40 @@ pub fn cursor_mangling(ctx: &BindgenContext,
}
// Try to undo backend linkage munging (prepended _, generally)
+ //
+ // TODO(emilio): This is wrong when the target system is not the host
+ // system. See https://github.com/servo/rust-bindgen/issues/593
if cfg!(target_os = "macos") {
mangling.remove(0);
}
+ if cursor.kind() == clang_sys::CXCursor_Destructor {
+ // With old (3.8-) libclang versions, and the Itanium ABI, clang returns
+ // the "destructor group 0" symbol, which means that it'll try to free
+ // memory, which definitely isn't what we want.
+ //
+ // Explicitly force the destructor group 1 symbol.
+ //
+ // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special
+ // for the reference, and http://stackoverflow.com/a/6614369/1091587 for
+ // a more friendly explanation.
+ //
+ // We don't need to do this for constructors since clang seems to always
+ // have returned the C1 constructor.
+ //
+ // FIXME(emilio): Can a legit symbol in other ABIs end with this string?
+ // I don't think so, but if it can this would become a linker error
+ // anyway, not an invalid free at runtime.
+ //
+ // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with
+ // time.
+ if mangling.ends_with("D0Ev") {
+ let new_len = mangling.len() - 4;
+ mangling.truncate(new_len);
+ mangling.push_str("D1Ev");
+ }
+ }
+
Some(mangling)
}
@@ -220,13 +251,14 @@ impl FunctionSig {
let is_method = cursor.kind() == CXCursor_CXXMethod;
let is_constructor = cursor.kind() == CXCursor_Constructor;
- if (is_constructor || is_method) &&
+ let is_destructor = cursor.kind() == CXCursor_Destructor;
+ if (is_constructor || is_destructor || is_method) &&
cursor.lexical_parent() != cursor.semantic_parent() {
// Only parse constructors once.
return Err(ParseError::Continue);
}
- if is_method || is_constructor {
+ if is_method || is_constructor || is_destructor {
let is_const = is_method && cursor.method_is_const();
let is_virtual = is_method && cursor.method_is_virtual();
let is_static = is_method && cursor.method_is_static();
@@ -292,9 +324,9 @@ impl ClangSubItemParser for Function {
-> Result<ParseResult<Self>, ParseError> {
use clang_sys::*;
match cursor.kind() {
- // FIXME(emilio): Generate destructors properly.
CXCursor_FunctionDecl |
CXCursor_Constructor |
+ CXCursor_Destructor |
CXCursor_CXXMethod => {}
_ => return Err(ParseError::Continue),
};
@@ -325,9 +357,23 @@ impl ClangSubItemParser for Function {
let sig =
try!(Item::from_ty(&cursor.cur_type(), cursor, None, context));
- let name = cursor.spelling();
+ let mut name = cursor.spelling();
assert!(!name.is_empty(), "Empty function name?");
+ if cursor.kind() == CXCursor_Destructor {
+ // Remove the leading `~`. The alternative to this is special-casing
+ // code-generation for destructor functions, which seems less than
+ // ideal.
+ if name.starts_with('~') {
+ name.remove(0);
+ }
+
+ // Add a suffix to avoid colliding with constructors. This would be
+ // technically fine (since we handle duplicated functions/methods),
+ // but seems easy enough to handle it here.
+ name.push_str("_destructor");
+ }
+
let mut mangled_name = cursor_mangling(context, &cursor);
if mangled_name.as_ref() == Some(&name) {
mangled_name = None;
diff --git a/src/lib.rs b/src/lib.rs
index eccf80e3..e6a66dfc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -109,6 +109,8 @@ pub struct CodegenConfig {
pub methods: bool,
/// Whether to generate constructors.
pub constructors: bool,
+ /// Whether to generate destructors.
+ pub destructors: bool,
}
impl CodegenConfig {
@@ -120,6 +122,7 @@ impl CodegenConfig {
vars: true,
methods: true,
constructors: true,
+ destructors: true,
}
}
@@ -131,6 +134,7 @@ impl CodegenConfig {
vars: false,
methods: false,
constructors: false,
+ destructors: false,
}
}
}
diff --git a/src/options.rs b/src/options.rs
index f1c8479a..6d06ad3b 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -111,8 +111,8 @@ pub fn builder_from_flags<I>
Arg::with_name("generate")
.long("generate")
.help("Generate a given kind of items, split by commas. \
- Valid values are \"functions\",\"types\", \"vars\" and \
- \"methods\".")
+ Valid values are \"functions\",\"types\", \"vars\", \
+ \"methods\", \"constructors\" and \"destructors\".")
.takes_value(true),
Arg::with_name("ignore-methods")
.long("ignore-methods")
@@ -271,6 +271,8 @@ pub fn builder_from_flags<I>
"types" => config.types = true,
"vars" => config.vars = true,
"methods" => config.methods = true,
+ "constructors" => config.constructors = true,
+ "destructors" => config.destructors = true,
_ => {
return Err(Error::new(ErrorKind::Other,
"Unknown generate item"));
diff --git a/tests/expectations/tests/bitfield-method-same-name.rs b/tests/expectations/tests/bitfield-method-same-name.rs
index 9222f74d..e180153b 100644
--- a/tests/expectations/tests/bitfield-method-same-name.rs
+++ b/tests/expectations/tests/bitfield-method-same-name.rs
@@ -54,14 +54,14 @@ impl Foo {
}
#[inline]
pub unsafe fn type_(&mut self) -> ::std::os::raw::c_schar {
- Foo_type(&mut *self)
+ Foo_type(self)
}
#[inline]
pub unsafe fn set_type_(&mut self, c: ::std::os::raw::c_schar) {
- Foo_set_type_(&mut *self, c)
+ Foo_set_type_(self, c)
}
#[inline]
pub unsafe fn set_type(&mut self, c: ::std::os::raw::c_schar) {
- Foo_set_type(&mut *self, c)
+ Foo_set_type(self, c)
}
}
diff --git a/tests/expectations/tests/class.rs b/tests/expectations/tests/class.rs
index 3ed5edd2..edb2697b 100644
--- a/tests/expectations/tests/class.rs
+++ b/tests/expectations/tests/class.rs
@@ -283,14 +283,14 @@ impl Clone for RealAbstractionWithTonsOfMethods {
}
impl RealAbstractionWithTonsOfMethods {
#[inline]
- pub unsafe fn bar(&self) { RealAbstractionWithTonsOfMethods_bar(&*self) }
+ pub unsafe fn bar(&self) { RealAbstractionWithTonsOfMethods_bar(self) }
#[inline]
pub unsafe fn bar1(&mut self) {
- RealAbstractionWithTonsOfMethods_bar1(&mut *self)
+ RealAbstractionWithTonsOfMethods_bar1(self)
}
#[inline]
pub unsafe fn bar2(&mut self, foo: ::std::os::raw::c_int) {
- RealAbstractionWithTonsOfMethods_bar2(&mut *self, foo)
+ RealAbstractionWithTonsOfMethods_bar2(self, foo)
}
#[inline]
pub unsafe fn sta() { RealAbstractionWithTonsOfMethods_sta() }
diff --git a/tests/expectations/tests/class_with_typedef.rs b/tests/expectations/tests/class_with_typedef.rs
index 03822233..e962992d 100644
--- a/tests/expectations/tests/class_with_typedef.rs
+++ b/tests/expectations/tests/class_with_typedef.rs
@@ -70,18 +70,18 @@ impl Default for C {
}
impl C {
#[inline]
- pub unsafe fn method(&mut self, c: C_MyInt) { C_method(&mut *self, c) }
+ pub unsafe fn method(&mut self, c: C_MyInt) { C_method(self, c) }
#[inline]
pub unsafe fn methodRef(&mut self, c: *mut C_MyInt) {
- C_methodRef(&mut *self, c)
+ C_methodRef(self, c)
}
#[inline]
pub unsafe fn complexMethodRef(&mut self, c: *mut C_Lookup) {
- C_complexMethodRef(&mut *self, c)
+ C_complexMethodRef(self, c)
}
#[inline]
pub unsafe fn anotherMethod(&mut self, c: AnotherInt) {
- C_anotherMethod(&mut *self, c)
+ C_anotherMethod(self, c)
}
}
#[repr(C)]
diff --git a/tests/expectations/tests/gen-constructors-neg.rs b/tests/expectations/tests/gen-constructors-neg.rs
new file mode 100644
index 00000000..fbeb3d5e
--- /dev/null
+++ b/tests/expectations/tests/gen-constructors-neg.rs
@@ -0,0 +1,21 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+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 ) ));
+}
+impl Clone for Foo {
+ fn clone(&self) -> Self { *self }
+}
diff --git a/tests/expectations/tests/gen-constructors.rs b/tests/expectations/tests/gen-constructors.rs
new file mode 100644
index 00000000..72c2fc53
--- /dev/null
+++ b/tests/expectations/tests/gen-constructors.rs
@@ -0,0 +1,33 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+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 = "_ZN3FooC1Ei"]
+ pub fn Foo_Foo(this: *mut Foo, a: ::std::os::raw::c_int);
+}
+impl Clone for Foo {
+ fn clone(&self) -> Self { *self }
+}
+impl Foo {
+ #[inline]
+ pub unsafe fn new(a: ::std::os::raw::c_int) -> Self {
+ let mut __bindgen_tmp = ::std::mem::uninitialized();
+ Foo_Foo(&mut __bindgen_tmp, a);
+ __bindgen_tmp
+ }
+}
diff --git a/tests/expectations/tests/gen-destructors-neg.rs b/tests/expectations/tests/gen-destructors-neg.rs
new file mode 100644
index 00000000..4aaec83a
--- /dev/null
+++ b/tests/expectations/tests/gen-destructors-neg.rs
@@ -0,0 +1,23 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct Foo {
+ pub bar: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_Foo() {
+ assert_eq!(::std::mem::size_of::<Foo>() , 4usize , concat ! (
+ "Size of: " , stringify ! ( Foo ) ));
+ assert_eq! (::std::mem::align_of::<Foo>() , 4usize , concat ! (
+ "Alignment of " , stringify ! ( Foo ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Foo ) ) . bar as * const _ as usize } ,
+ 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( Foo ) , "::" ,
+ stringify ! ( bar ) ));
+}
diff --git a/tests/expectations/tests/gen-destructors.rs b/tests/expectations/tests/gen-destructors.rs
new file mode 100644
index 00000000..7ec13b03
--- /dev/null
+++ b/tests/expectations/tests/gen-destructors.rs
@@ -0,0 +1,31 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct Foo {
+ pub bar: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_Foo() {
+ assert_eq!(::std::mem::size_of::<Foo>() , 4usize , concat ! (
+ "Size of: " , stringify ! ( Foo ) ));
+ assert_eq! (::std::mem::align_of::<Foo>() , 4usize , concat ! (
+ "Alignment of " , stringify ! ( Foo ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Foo ) ) . bar as * const _ as usize } ,
+ 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( Foo ) , "::" ,
+ stringify ! ( bar ) ));
+}
+extern "C" {
+ #[link_name = "_ZN3FooD1Ev"]
+ pub fn Foo_Foo_destructor(this: *mut Foo);
+}
+impl Foo {
+ #[inline]
+ pub unsafe fn destruct(&mut self) { Foo_Foo_destructor(self) }
+}
diff --git a/tests/expectations/tests/issue-410.rs b/tests/expectations/tests/issue-410.rs
index 1f624fec..8833ef4e 100644
--- a/tests/expectations/tests/issue-410.rs
+++ b/tests/expectations/tests/issue-410.rs
@@ -34,7 +34,7 @@ pub mod root {
impl Value {
#[inline]
pub unsafe fn a(&mut self, arg1: root::JSWhyMagic) {
- Value_a(&mut *self, arg1)
+ Value_a(self, arg1)
}
}
}
diff --git a/tests/expectations/tests/method-mangling.rs b/tests/expectations/tests/method-mangling.rs
index 23f12280..360f0ea7 100644
--- a/tests/expectations/tests/method-mangling.rs
+++ b/tests/expectations/tests/method-mangling.rs
@@ -25,7 +25,5 @@ impl Clone for Foo {
}
impl Foo {
#[inline]
- pub unsafe fn type_(&mut self) -> ::std::os::raw::c_int {
- Foo_type(&mut *self)
- }
+ pub unsafe fn type_(&mut self) -> ::std::os::raw::c_int { Foo_type(self) }
}
diff --git a/tests/expectations/tests/namespace.rs b/tests/expectations/tests/namespace.rs
index 21b5a58b..8e64fa22 100644
--- a/tests/expectations/tests/namespace.rs
+++ b/tests/expectations/tests/namespace.rs
@@ -58,7 +58,7 @@ pub mod root {
#[inline]
pub unsafe fn lets_hope_this_works(&mut self)
-> ::std::os::raw::c_int {
- A_lets_hope_this_works(&mut *self)
+ A_lets_hope_this_works(self)
}
}
}
diff --git a/tests/expectations/tests/public-dtor.rs b/tests/expectations/tests/public-dtor.rs
index 1accf49c..d24e863e 100644
--- a/tests/expectations/tests/public-dtor.rs
+++ b/tests/expectations/tests/public-dtor.rs
@@ -16,3 +16,11 @@ fn bindgen_test_layout_cv_String() {
assert_eq! (::std::mem::align_of::<cv_String>() , 1usize , concat ! (
"Alignment of " , stringify ! ( cv_String ) ));
}
+extern "C" {
+ #[link_name = "_ZN2cv6StringD1Ev"]
+ pub fn cv_String_String_destructor(this: *mut cv_String);
+}
+impl cv_String {
+ #[inline]
+ pub unsafe fn destruct(&mut self) { cv_String_String_destructor(self) }
+}
diff --git a/tests/expectations/tests/union_dtor.rs b/tests/expectations/tests/union_dtor.rs
index bfd573e0..61fb0380 100644
--- a/tests/expectations/tests/union_dtor.rs
+++ b/tests/expectations/tests/union_dtor.rs
@@ -52,3 +52,13 @@ fn bindgen_test_layout_UnionWithDtor() {
"Alignment of field: " , stringify ! ( UnionWithDtor ) , "::"
, stringify ! ( mBar ) ));
}
+extern "C" {
+ #[link_name = "_ZN13UnionWithDtorD1Ev"]
+ pub fn UnionWithDtor_UnionWithDtor_destructor(this: *mut UnionWithDtor);
+}
+impl UnionWithDtor {
+ #[inline]
+ pub unsafe fn destruct(&mut self) {
+ UnionWithDtor_UnionWithDtor_destructor(self)
+ }
+}
diff --git a/tests/headers/gen-constructors-neg.hpp b/tests/headers/gen-constructors-neg.hpp
new file mode 100644
index 00000000..2dd491c4
--- /dev/null
+++ b/tests/headers/gen-constructors-neg.hpp
@@ -0,0 +1,6 @@
+// bindgen-flags: --generate types,functions
+
+class Foo {
+ public:
+ Foo(int a);
+};
diff --git a/tests/headers/gen-constructors.hpp b/tests/headers/gen-constructors.hpp
new file mode 100644
index 00000000..809d6ef9
--- /dev/null
+++ b/tests/headers/gen-constructors.hpp
@@ -0,0 +1,6 @@
+// bindgen-flags: --generate types,constructors,functions
+
+class Foo {
+ public:
+ Foo(int a);
+};
diff --git a/tests/headers/gen-destructors-neg.hpp b/tests/headers/gen-destructors-neg.hpp
new file mode 100644
index 00000000..5ede3ba3
--- /dev/null
+++ b/tests/headers/gen-destructors-neg.hpp
@@ -0,0 +1,9 @@
+// bindgen-flags: --generate types,functions
+//
+// NB: This is intended to _not_ generate destructors.
+
+class Foo {
+ int bar;
+ public:
+ ~Foo();
+};
diff --git a/tests/headers/gen-destructors.hpp b/tests/headers/gen-destructors.hpp
new file mode 100644
index 00000000..719eb248
--- /dev/null
+++ b/tests/headers/gen-destructors.hpp
@@ -0,0 +1,7 @@
+// bindgen-flags: --generate types,destructors,functions
+
+class Foo {
+ int bar;
+ public:
+ ~Foo();
+};