-
-
Notifications
You must be signed in to change notification settings - Fork 702
Fix issue 18716: type const(char)[] can not be mapped to C++
#8120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| Added support for D arrays in C++ functions | ||
|
|
||
| D arrays don't have any corresponding type in C++. This change adds support for | ||
| mangling a D array as a templated struct with the special name: `__dslice`. | ||
| Under the hood, a D array is represented as a struct, containing the length of | ||
| the array and a pointer to the data: | ||
|
|
||
| --- | ||
| struct DArray(T) | ||
| { | ||
| size_t length; | ||
| T* ptr; | ||
| } | ||
| --- | ||
|
|
||
| Any D array in the form of, `T[]`, when used in a C++ function, will be mangled | ||
| as the following struct: | ||
|
|
||
| --- | ||
| struct __dslice(T); | ||
| --- | ||
|
|
||
| For example, an array of ints, `int[]`, will be mangled as `__dslice!int` when | ||
| used in a C++ function. This allows to declare C++ functions that accepts D | ||
| arrays and can be accessed to C++ if the right struct declaration is present | ||
| on the C++ side. | ||
|
|
||
| On the D side: | ||
|
|
||
| --- | ||
| extern(C++) void foo(const(char)[] str); | ||
|
|
||
| void main() | ||
| { | ||
| foo("bar"); | ||
| } | ||
| --- | ||
|
|
||
| On the C++ side: | ||
|
|
||
| $(CPPCODE | ||
| #include <stdio.h> | ||
|
|
||
| template<typename T> struct __dslice | ||
| { | ||
| size_t length; | ||
| T* ptr; | ||
| }; | ||
|
|
||
| void foo(__dslice<const char> array) | ||
| { | ||
| printf("%.*s\n", (int) array.length, array.ptr); | ||
| } | ||
| ) | ||
|
|
||
| Since the `__dslice` struct is ABI compatible with D arrays, it works perfectly | ||
| fine to pass a D array to a C++ function taking a `__dslice`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -206,3 +206,15 @@ struct Array | |
| } | ||
| }; | ||
|
|
||
| // This is the type that the D compiler will mangle D slices as when mangling | ||
| // for C++. This type is ABI compatible with native D slices. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is ABI compatibility actually tested somewhere? I seriously doubt it is on Win64 for example. LDC on Win64 returns and passes slices (and delegates IIRC) as pairs (in 2 registers if available), whereas a 128-bit struct is passed/returned indirectly by value (hidden ref), and there is no way for a struct to emulate that behaviour. [Btw, the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The C++
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apparently the same for DMD. DMD 2.081.0, const(char)[] getNativeSlice() { return "lala"[0..3]; }
struct Slice(T)
{
size_t length;
T* ptr;
}
extern(C++) Slice!(const(char)) getSlice() { return Slice!(const(char))(3, "lala".ptr); }=> ; native slice returned in RAX and RDX
_D5slice14getNativeSliceFZAxa:
0000000000000000: 55 push rbp
0000000000000001: 48 8B EC mov rbp,rsp
0000000000000004: 48 8D 15 00 00 00 lea rdx,[__a3_6c616c]
00
000000000000000B: B8 03 00 00 00 mov eax,3
0000000000000010: 5D pop rbp
0000000000000011: C3 ret
; pointer to pre-allocated return value passed in RCX
?getSlice@@YA?AU?$Slice@D@@XZ (struct Slice<char> __cdecl getSlice(void)):
0000000000000000: 55 push rbp
0000000000000001: 48 8B EC mov rbp,rsp
0000000000000004: 48 C7 01 03 00 00 mov qword ptr [rcx],3
00
000000000000000B: 48 8D 05 00 00 00 lea rax,[_TMP0]
00
0000000000000012: 48 89 41 08 mov qword ptr [rcx+8],rax
0000000000000016: 48 89 C8 mov rax,rcx
0000000000000019: 5D pop rbp
000000000000001A: C3 ret
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No.
That's unfortunate. |
||
| template <typename T> struct __dslice | ||
| { | ||
| d_size_t length; | ||
| T* ptr; | ||
|
|
||
| __dslice() : length(0), ptr(NULL) {} | ||
| __dslice(size_t length, T* ptr) : length(length), ptr(ptr) {} | ||
| }; | ||
|
|
||
| #define DSlice __dslice | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1105,6 +1105,40 @@ else version(Posix) | |
| static assert(test19278_var.mangleof == "_ZN5hello5world13test19278_varE"); | ||
| } | ||
|
|
||
| /*****************************************/ | ||
| // https://issues.dlang.org/show_bug.cgi?id=18716 | ||
| // D slices as parameters in extern(C++) functions | ||
|
|
||
| struct Test18716 {} | ||
| struct __dslice(T) {} | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tests needs to be in runnable
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The ABI doesn't match, so there's no point, at least not yet.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The point is exactly that the ABI does not match.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not following. This whole PR is moot as long as the ABI problem exists.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I was just saying that it's not obvious, since there are tests, and the PR is green.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. It should, but Walter hasn't responded to the reasoning why his concerns are unfounded.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’m not going to spend time on moving the tests if/until I fix the ABI issue.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Walter did already vetoed it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But not sensibly.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #11073 contains a |
||
|
|
||
| extern(C++) void test18716a(char[]); | ||
| extern(C++) void test18716b(__dslice!char); | ||
| extern(C++) void test18716c(const(char)[]); | ||
| extern(C++) void test18716d(Test18716[]); | ||
|
|
||
| void test18716() | ||
| { | ||
| test18716a("foo".dup); | ||
| test18716c("foo"); | ||
| test18716d([Test18716()]); | ||
|
thewilsonator marked this conversation as resolved.
|
||
| } | ||
|
|
||
| version (Posix) | ||
| { | ||
| static assert(test18716a.mangleof == "_Z10test18716a8__dsliceIcE"); | ||
| static assert(test18716b.mangleof == "_Z10test18716b8__dsliceIcE"); | ||
| static assert(test18716c.mangleof == "_Z10test18716c8__dsliceIKcE"); | ||
| static assert(test18716d.mangleof == "_Z10test18716d8__dsliceI9Test18716E"); | ||
| } | ||
|
|
||
| else version (Windows) | ||
| { | ||
| static assert(test18716a.mangleof == "?test18716a@@YAXU?$__dslice@D@@@Z"); | ||
| static assert(test18716b.mangleof == "?test18716b@@YAXU?$__dslice@D@@@Z"); | ||
| static assert(test18716c.mangleof == "?test18716c@@YAXU?$__dslice@$$CBD@@@Z"); | ||
| static assert(test18716d.mangleof == "?test18716d@@YAXU?$__dslice@UTest18716@@@@@Z"); | ||
| } | ||
| /**************************************/ | ||
| // https://issues.dlang.org/show_bug.cgi?id=18958 | ||
| // Issue 18958 - extern(C++) wchar, dchar mangling not correct | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.