@@ -114,6 +114,7 @@ fn get_abi(cc: CXCallingConv) -> Option<abi::Abi> {
114
114
pub fn cursor_mangling ( ctx : & BindgenContext ,
115
115
cursor : & clang:: Cursor )
116
116
-> Option < String > {
117
+ use clang_sys;
117
118
if !ctx. options ( ) . enable_mangling {
118
119
return None ;
119
120
}
@@ -131,10 +132,40 @@ pub fn cursor_mangling(ctx: &BindgenContext,
131
132
}
132
133
133
134
// Try to undo backend linkage munging (prepended _, generally)
135
+ //
136
+ // TODO(emilio): This is wrong when the target system is not the host
137
+ // system. See https://github.com/servo/rust-bindgen/issues/593
134
138
if cfg ! ( target_os = "macos" ) {
135
139
mangling. remove ( 0 ) ;
136
140
}
137
141
142
+ if cursor. kind ( ) == clang_sys:: CXCursor_Destructor {
143
+ // With old (3.8-) libclang versions, and the Itanium ABI, clang returns
144
+ // the "destructor group 0" symbol, which means that it'll try to free
145
+ // memory, which definitely isn't what we want.
146
+ //
147
+ // Explicitly force the destructor group 1 symbol.
148
+ //
149
+ // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special
150
+ // for the reference, and http://stackoverflow.com/a/6614369/1091587 for
151
+ // a more friendly explanation.
152
+ //
153
+ // We don't need to do this for constructors since clang seems to always
154
+ // have returned the C1 constructor.
155
+ //
156
+ // FIXME(emilio): Can a legit symbol in other ABIs end with this string?
157
+ // I don't think so, but if it can this would become a linker error
158
+ // anyway, not an invalid free at runtime.
159
+ //
160
+ // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with
161
+ // time.
162
+ if mangling. ends_with ( "D0Ev" ) {
163
+ let new_len = mangling. len ( ) - 4 ;
164
+ mangling. truncate ( new_len) ;
165
+ mangling. push_str ( "D1Ev" ) ;
166
+ }
167
+ }
168
+
138
169
Some ( mangling)
139
170
}
140
171
@@ -220,13 +251,14 @@ impl FunctionSig {
220
251
221
252
let is_method = cursor. kind ( ) == CXCursor_CXXMethod ;
222
253
let is_constructor = cursor. kind ( ) == CXCursor_Constructor ;
223
- if ( is_constructor || is_method) &&
254
+ let is_destructor = cursor. kind ( ) == CXCursor_Destructor ;
255
+ if ( is_constructor || is_destructor || is_method) &&
224
256
cursor. lexical_parent ( ) != cursor. semantic_parent ( ) {
225
257
// Only parse constructors once.
226
258
return Err ( ParseError :: Continue ) ;
227
259
}
228
260
229
- if is_method || is_constructor {
261
+ if is_method || is_constructor || is_destructor {
230
262
let is_const = is_method && cursor. method_is_const ( ) ;
231
263
let is_virtual = is_method && cursor. method_is_virtual ( ) ;
232
264
let is_static = is_method && cursor. method_is_static ( ) ;
@@ -292,9 +324,9 @@ impl ClangSubItemParser for Function {
292
324
-> Result < ParseResult < Self > , ParseError > {
293
325
use clang_sys:: * ;
294
326
match cursor. kind ( ) {
295
- // FIXME(emilio): Generate destructors properly.
296
327
CXCursor_FunctionDecl |
297
328
CXCursor_Constructor |
329
+ CXCursor_Destructor |
298
330
CXCursor_CXXMethod => { }
299
331
_ => return Err ( ParseError :: Continue ) ,
300
332
} ;
@@ -325,9 +357,23 @@ impl ClangSubItemParser for Function {
325
357
let sig =
326
358
try!( Item :: from_ty ( & cursor. cur_type ( ) , cursor, None , context) ) ;
327
359
328
- let name = cursor. spelling ( ) ;
360
+ let mut name = cursor. spelling ( ) ;
329
361
assert ! ( !name. is_empty( ) , "Empty function name?" ) ;
330
362
363
+ if cursor. kind ( ) == CXCursor_Destructor {
364
+ // Remove the leading `~`. The alternative to this is special-casing
365
+ // code-generation for destructor functions, which seems less than
366
+ // ideal.
367
+ if name. starts_with ( '~' ) {
368
+ name. remove ( 0 ) ;
369
+ }
370
+
371
+ // Add a suffix to avoid colliding with constructors. This would be
372
+ // technically fine (since we handle duplicated functions/methods),
373
+ // but seems easy enough to handle it here.
374
+ name. push_str ( "_destructor" ) ;
375
+ }
376
+
331
377
let mut mangled_name = cursor_mangling ( context, & cursor) ;
332
378
if mangled_name. as_ref ( ) == Some ( & name) {
333
379
mangled_name = None ;
0 commit comments