diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 120acefad3..b6161e4cb3 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1456,6 +1456,20 @@ impl CodeGenerator for CompInfo { self); } } + + if ctx.options().codegen_config.destructor { + if let Some(destructor) = *self.destructor() { + Method::new(MethodKind::Destructor, + 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 @@ -1560,6 +1574,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 => "__bindgen_destructor__".into(), _ => function.name().to_owned(), }; diff --git a/src/ir/comp.rs b/src/ir/comp.rs index b97879f710..0d3ffde58d 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -26,6 +26,8 @@ pub enum MethodKind { /// A constructor. We represent it as method for convenience, to avoid code /// duplication. Constructor, + /// A destructor method + Destructor, /// A static method. Static, /// A normal method. @@ -61,6 +63,11 @@ impl Method { self.kind } + /// Is this a destructor method? + pub fn is_destructor(&self) -> bool { + self.kind == MethodKind::Destructor + } + /// Is this a constructor? pub fn is_constructor(&self) -> bool { self.kind == MethodKind::Constructor @@ -249,6 +256,9 @@ pub struct CompInfo { /// The different constructors this struct or class contains. constructors: Vec, + /// The destructor of this type + destructor: Option, + /// Vector of classes this one inherits from. base_members: Vec, @@ -323,6 +333,7 @@ impl CompInfo { template_args: vec![], methods: vec![], constructors: vec![], + destructor: None, base_members: vec![], ref_template: None, inner_types: vec![], @@ -468,6 +479,11 @@ impl CompInfo { &self.constructors } + /// Get this type's destructor. + pub fn destructor(&self) -> &Option { + &self.destructor + } + /// What kind of compound type is this? pub fn kind(&self) -> CompKind { self.kind @@ -729,8 +745,9 @@ impl CompInfo { CXCursor_Constructor => { ci.constructors.push(signature); } - // TODO(emilio): Bind the destructor? - CXCursor_Destructor => {} + CXCursor_Destructor => { + ci.destructor = Some(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 ad336c4ba3..ca6c0a7488 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -217,13 +217,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(); @@ -288,9 +289,9 @@ impl ClangSubItemParser for Function { -> Result, ParseError> { use clang_sys::*; match cursor.kind() { - // FIXME(emilio): Generate destructors properly. CXCursor_FunctionDecl | CXCursor_Constructor | + CXCursor_Destructor | CXCursor_CXXMethod => {} _ => return Err(ParseError::Continue), }; @@ -322,7 +323,16 @@ impl ClangSubItemParser for Function { None, context)); - let name = cursor.spelling(); + let name = match cursor.kind() { + CXCursor_Destructor => { + let mut name_ = cursor.spelling(); + // remove the `~` + name_.remove(0); + name_ + "_destructor" + }, + _ => cursor.spelling(), + }; + assert!(!name.is_empty(), "Empty function name?"); let mut mangled_name = cursor_mangling(context, &cursor); diff --git a/src/lib.rs b/src/lib.rs index 5e14d81eed..277660f274 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 a destructor. + pub destructor: bool, } impl CodegenConfig { @@ -120,6 +122,7 @@ impl CodegenConfig { vars: true, methods: true, constructors: true, + destructor: true, } } @@ -131,6 +134,7 @@ impl CodegenConfig { vars: false, methods: false, constructors: false, + destructor: false, } } } diff --git a/tests/expectations/tests/public-dtor.rs b/tests/expectations/tests/public-dtor.rs index 1accf49cb5..0412b9f4b7 100644 --- a/tests/expectations/tests/public-dtor.rs +++ b/tests/expectations/tests/public-dtor.rs @@ -16,3 +16,13 @@ fn bindgen_test_layout_cv_String() { assert_eq! (::std::mem::align_of::() , 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 __bindgen_destructor__(&mut self) { + cv_String_String_destructor(&mut *self) + } +} diff --git a/tests/expectations/tests/union_dtor.rs b/tests/expectations/tests/union_dtor.rs index bfd573e021..1bcb45b672 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 __bindgen_destructor__(&mut self) { + UnionWithDtor_UnionWithDtor_destructor(&mut *self) + } +} diff --git a/tests/expectations/tests/virtual_dtor.rs b/tests/expectations/tests/virtual_dtor.rs index 0c4109776d..2a594ab5a3 100644 --- a/tests/expectations/tests/virtual_dtor.rs +++ b/tests/expectations/tests/virtual_dtor.rs @@ -20,6 +20,16 @@ fn bindgen_test_layout_nsSlots() { assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( "Alignment of " , stringify ! ( nsSlots ) )); } +extern "C" { + #[link_name = "_ZN7nsSlotsD1Ev"] + pub fn nsSlots_nsSlots_destructor(this: *mut nsSlots); +} impl Default for nsSlots { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } +impl nsSlots { + #[inline] + pub unsafe fn __bindgen_destructor__(&mut self) { + nsSlots_nsSlots_destructor(&mut *self) + } +}