Open
Description
This is done on Windows 10. Linux appears to work as expected.
bindgen: 0.53.1
LLVM: 9.0.0
from installer
Correct mangling shown on godbolt. clang-cl isn't shown, but outputs the same, as is expected.
Input C/C++ Header
struct B{
B();
~B();
};
// Bindgen incorrectly demangles this as ??_DB@@QEAAXXZ
// real: ??1B@@QEAA@XZ
B::~B() {}
class C{
public:
C();
~C();
};
// Bindgen incorrectly demangles this as ??_DC@@QEAAXXZ (same as struct)
// symbol: ??1C@@AEAA@XZ (note the A in AEAA)
C::~C() {}
Bindgen Invocation
$ bindgen file.hpp
Actual Results
Verbose Output
These look pretty important 😛
cargo:warning=couldn't execute `llvm-config --prefix` (error: The system cannot find the file specified. (os error 2))
cargo:warning=set the LLVM_CONFIG_PATH environment variable to a valid `llvm-config` executable
[2020-02-11T06:08:18Z ERROR bindgen::ir::item] Unhandled cursor kind 25: Cursor(~B kind: CXXDestructor, loc: .\file.hpp:8:4, usr: Some("c:@S@B@F@~B#"))
[2020-02-11T06:08:18Z ERROR bindgen::ir::item] Unhandled cursor kind 25: Cursor(~C kind: CXXDestructor, loc: .\file.hpp:18:4, usr: Some("c:@S@C@F@~C#"))
Bindgen Output
Comments my own.
/* automatically generated by rust-bindgen */
#[repr(C)]
#[derive(Debug)]
pub struct B {
pub _address: u8,
}
#[test]
fn bindgen_test_layout_B() {
assert_eq!(
::std::mem::size_of::<B>(),
1usize,
concat!("Size of: ", stringify!(B))
);
assert_eq!(
::std::mem::align_of::<B>(),
1usize,
concat!("Alignment of ", stringify!(B))
);
}
extern "C" {
#[link_name = "\u{1}??0B@@QEAA@XZ"]
pub fn B_B(this: *mut B);
}
extern "C" {
// incorrect, should be: ??1B@@QEAA@XZ
#[link_name = "\u{1}??_DB@@QEAAXXZ"]
pub fn B_B_destructor(this: *mut B);
}
impl B {
#[inline]
pub unsafe fn new() -> Self {
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
B_B(__bindgen_tmp.as_mut_ptr());
__bindgen_tmp.assume_init()
}
#[inline]
pub unsafe fn destruct(&mut self) {
B_B_destructor(self)
}
}
#[repr(C)]
#[derive(Debug)]
pub struct C {
pub _address: u8,
}
#[test]
fn bindgen_test_layout_C() {
assert_eq!(
::std::mem::size_of::<C>(),
1usize,
concat!("Size of: ", stringify!(C))
);
assert_eq!(
::std::mem::align_of::<C>(),
1usize,
concat!("Alignment of ", stringify!(C))
);
}
extern "C" {
#[link_name = "\u{1}??0C@@QEAA@XZ"]
pub fn C_C(this: *mut C);
}
extern "C" {
// incorrect, should be ??1C@@AEAA@XZ
#[link_name = "\u{1}??_DC@@QEAAXXZ"]
pub fn C_C_destructor(this: *mut C);
}
impl C {
#[inline]
pub unsafe fn new() -> Self {
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
C_C(__bindgen_tmp.as_mut_ptr());
__bindgen_tmp.assume_init()
}
#[inline]
pub unsafe fn destruct(&mut self) {
C_C_destructor(self)
}
}
Expected Results
As mentioned above, the destructors are getting mangled incorrectly on the MSVC abi. Specifically:
??1C@@AEAA@XZ
gets mangled as ??_DC@@QEAAXXZ
and
??1B@@QEAA@XZ
gets mangled as ??_DB@@QEAAXXZ
.
This gives a linker error that is quite confusing talking about a missing reference to a vbase destructor
on a class with no parents nor virtuality.
Workaround
For those affected by the issue, if you post process the bindings with a regex, you can automatically filter these:
\?\?_D(.*?)XXZ
-> ??1${1}@XZ