rust-bindgen: Wrong ABI used for small C++ classes on Linux.
Input C/C++ Header
#include <cstdint>
struct Foo {
size_t data;
};
struct Bar {
size_t data;
~Bar() { data = 0; }
};
Foo MakeFoo(); // { return Foo(); }
Bar MakeBar(); // { return Bar(); }
Bindgen Invocation
bindgen::Builder::default()
.clang_args(&["-x","c++", "-std=c++11"])
.header("input.h")
.generate()
.unwrap()
Actual Results
#[repr(C)]
#[derive(Debug, Copy)]
pub struct Foo {
pub data: usize,
}
impl Clone for Foo {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug)]
pub struct Bar {
pub data: usize,
}
extern "C" {
#[link_name = "_ZN3BarD1Ev"]
pub fn Bar_Bar_destructor(this: *mut Bar);
}
impl Bar {
#[inline]
pub unsafe fn destruct(&mut self) { Bar_Bar_destructor(self) }
}
extern "C" {
#[link_name = "_Z7MakeFoov"]
pub fn MakeFoo() -> Foo;
}
extern "C" {
#[link_name = "_Z7MakeBarv"]
pub fn MakeBar() -> Bar;
}
Expected Results
Not sure…
Discussion
MakeFoo and MakeBar look very similar, however in C++ they use different ABIs, at least on Linux.
Here’s a quote from System V AMD64 ABI spec (page 20):
If a C++ object has either a non-trivial copy constructor or a non-trivial destructor 11, it is passed by invisible reference (the object is replaced in the parameter list by a pointer that has class POINTER) 12
This means that while Foo get returned by-value in the rax register, Bar must be returned by-pointer to a caller allocated memory. To Rust compiler, however, these look identical, so it expects both to be returned in rax.
About this issue
- Original URL
- State: open
- Created 7 years ago
- Comments: 32 (14 by maintainers)
Commits related to this issue
- Replace confusing note in cpp.md on "RVO" The original commit adding this note referenced #778, but then went on to talk about how the problem was RVO and that the problem is not possible to solve in... — committed to barcharcraz/rust-bindgen by barcharcraz 2 years ago
- Replace confusing note in cpp.md on "RVO" The original commit adding this note referenced #778, but then went on to talk about how the problem was RVO and that the problem is not possible to solve in... — committed to rust-lang/rust-bindgen by barcharcraz 2 years ago
- Replace confusing note in cpp.md on "RVO" The original commit adding this note referenced #778, but then went on to talk about how the problem was RVO and that the problem is not possible to solve in... — committed to LoganBarnett/rust-bindgen by barcharcraz 2 years ago
Intel website moved the System V AMD64 ABI pdf so the link in the issue is broken – here is an updated link: https://software.intel.com/content/dam/develop/external/us/en/documents/mpx-linux64-abi.pdf
Since we already link to clang, another solution arises: generate C++ code and have clang emit LLVM IR for it. Since
rustccurrently generates LLVM IR too, we can perform cross-language link-time optimization to remove all of the overhead.