Bug 19841 – Wrong ABI for C++ functions taking a struct by value
Status
RESOLVED
Resolution
WORKSFORME
Severity
blocker
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2019-05-02T12:11:58Z
Last change time
2020-09-07T22:41:48Z
Keywords
backend, C++, wrong-code
Assigned to
No Owner
Creator
Atila Neves
Comments
Comment #0 by atila.neves — 2019-05-02T12:11:58Z
Code:
------------------------
extern(C++) {
struct Foo {
void[32] _;
}
struct Bar {
this(Foo foo);
}
}
void oops() {
auto foo = Foo();
auto bar = Bar(foo);
}
--------------------------
The assembly for oops doesn't even mention the RSI register where the address of `foo` should be passed in (RDI contains the address of where to construct `bar`). It tries to pass `foo` to the `Bar` constructor on the stack.
The equivalent C++ code passes `foo` as an address in RSI. Calling the C++ implementation results in segfault.
The bug is weirdly present in ldc and gdc as well.
Comment #1 by kinke — 2019-05-02T12:55:46Z
(In reply to Atila Neves from comment #0)
> The equivalent C++ code passes `foo` as an address in RSI.
No it doesn't: https://godbolt.org/z/hyzdMY
(In reply to Atila Neves from comment #2)
> Ah. In that case it's the copy ctor that causes this to happen:
Yes, as it's no POD in C++-terms anymore, affecting the ABI. So in D, you can define a dummy postblit to make it a non-POD.
IIRC, Microsoft is a lot stricter, and the mere existence of at least one ctor makes it a non-POD.
Comment #5 by atila.neves — 2019-05-02T17:20:49Z
A dummy postblit wouldn't work - it wouldn't actually fix up the value. Duplicating the functionality of the C++ copy constructor is undesireable, and using the copy constructor with the latest release candidate of dmd 2.086.0 doesn't work either.