DMD is incorrectly mangling the copy constructor of an `extern (C++) struct`.
Please see the details below
c.d
```
module c;
extern (C++) struct A
{
int x;
this(int x) { this.x = x; }
this(const ref A rhs) { this.x = rhs.x; }
~this() { }
}
```
c.h
```
struct A
{
_d_int x;
A(_d_int x);
A(const A& rhs);
~A();
};
```
tc.cpp
```
#include "c.h"
int main(int argc, char *argv[])
{
A x = A(42);
A y = x;
return 0;
}
```
I'm running on Ubuntu 18.04.1 LTS
Compiling `.d` with DMD64 D Compiler v2.086.0-1241-g08360654e
custdmd2 -c -betterC c.d
Compiling `.cpp` with g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
g++ -c tc.cpp
Linking the two objects together
`g++ tc.o c.o` results in the linker error
tc.o: In function `main':
tc.cpp:(.text+0x3f): undefined reference to `A::A(A const&)'
collect2: error: ld returned 1 exit status
Results of `nm` on objects
nm c.o
[...]
0000000000000000 W _ZN1AC2ERKS_
nm tc.o
[...]
U _ZN1AC1ERKS_
Compiling the `.d` module with LDC - the LLVM D compiler (1.14.0) based on DMD v2.084.1 and LLVM 7.0.1
ldc2 -betterC -c c.d
The resulted `c.o` object correctly links with the g++ generated one.
The output of `nm c.o` on the ldc2 generated object is
[...]
0000000000000000 T _ZN1AC1ERKS_
Comment #1 by edi33416 — 2019-09-12T12:19:01Z
Forgot to mention.
I also tested with gdc-9 and everything works as expected (same result as with ldc).
Comment #2 by razvan.nitu1305 — 2019-09-12T12:47:09Z
We probably have to emit extern(C++) copy ctors as 2 symbols for non-Windows, both the C1 ('complete object ctor') and the C2 ('base object constructor') variant. There's even a third one, C3 ('complete object allocating constructor'). A similar mess as for the C++ dtors.
The testcase in https://github.com/dlang/dmd/pull/9806 needed the C2 one, so I assumed it would suffice, but it clearly doesn't: https://godbolt.org/z/qD5Tta
Comment #4 by snarwin+bugzilla — 2023-08-20T20:40:30Z
Someone just ran into this in the community Discord. I was able to reproduce using both DMD 2.104.0 and LDC 1.33.0 as the D compiler, with the following example program:
--- test.d
extern(C++)
struct Test
{
this(const ref Test other) {}
}
--- main.cpp
struct Test
{
Test() = default;
Test(const Test &other);
};
int main()
{
Test a;
Test b = a;
return 0;
}
---
Comment #5 by robert.schadek — 2024-12-13T19:05:33Z