diff --git a/compiler/test/compilable/importc_wchar_t.d b/compiler/test/compilable/importc_wchar_t.d new file mode 100644 index 000000000000..c07e27d5fcd8 --- /dev/null +++ b/compiler/test/compilable/importc_wchar_t.d @@ -0,0 +1,67 @@ +// EXTRA_SOURCES: imports/importc_wchar_t_c.c + +import importc_wchar_t_c; + +version (Windows) +{ + /+ On Windows, we expect C's `wchar_t` to be D's `wchar`. +/ + + static assert(is(typeof(wchar_t_aggregate.w) == wchar)); + + alias Func = extern(C) void function(const(wchar)* str); + + Func wcharT() + { + wchar c = 0; + wchar_t_aggregate w = wchar_t_aggregate('W'); + w.p = &c; + + accept_wchar_t_string("Hello, World!"); + accept_wchar_t_string("Hello, World!"w.ptr); + accept_wchar_t_string(&w.w); + accept_wchar_t_string(w.p); + + static if (__traits(hasMember, importc_wchar_t_c, "accept_msvc___wchar_t_string")) + { + accept_msvc___wchar_t_string("Hello, World!"); + accept_msvc___wchar_t_string("Hello, World!"w.ptr); + accept_msvc___wchar_t_string(&w.w); + } + + return &accept_wchar_t_string; + } +} +else +{ + /+ On non-Windows platforms, we expect C's `wchar_t` to be whatever `` defined it as. +/ + + alias WCharT = typeof(wchar_t_aggregate.w); + static assert(__traits(isScalar, WCharT)); + + alias Func = extern(C) void function(const(WCharT)* str); + + Func wcharT() + { + WCharT c = 0; + wchar_t_aggregate w = wchar_t_aggregate('W'); + w.p = &c; + + accept_wchar_t_string(&w.w); + accept_wchar_t_string(w.p); + + static if (WCharT.sizeof == 4) + { + accept_wchar_t_string(cast(const(WCharT)*) "Hello, World!"d.ptr); + } + else static if (WCharT.sizeof == 2) + { + accept_wchar_t_string(cast(const(WCharT)*) "Hello, World!"w.ptr); + } + else static if (WCharT.sizeof == 1) + { + accept_wchar_t_string(cast(const(WCharT)*) "Hello, World!".ptr); + } + + return &accept_wchar_t_string; + } +} diff --git a/compiler/test/compilable/imports/importc_wchar_t_c.c b/compiler/test/compilable/imports/importc_wchar_t_c.c new file mode 100644 index 000000000000..9ce8e6bb71dc --- /dev/null +++ b/compiler/test/compilable/imports/importc_wchar_t_c.c @@ -0,0 +1,20 @@ + +#include + +_Static_assert(sizeof(__importc_char) == 1, "sizeof(__importc_char) == 1"); +_Static_assert(sizeof(__importc_wchar) == 2, "sizeof(__importc_wchar) == 2"); +_Static_assert(sizeof(__importc_dchar) == 4, "sizeof(__importc_dchar) == 4"); + +typedef struct +{ + wchar_t w; + wchar_t *p; +} wchar_t_aggregate; + +void accept_wchar_t_string(const wchar_t *str) +{} + +#ifdef _MSC_VER + void accept_msvc___wchar_t_string(const __wchar_t *str) + {} +#endif diff --git a/druntime/src/__importc_builtins.di b/druntime/src/__importc_builtins.di index 03bb22a74021..0256553af5da 100644 --- a/druntime/src/__importc_builtins.di +++ b/druntime/src/__importc_builtins.di @@ -49,6 +49,12 @@ version (CRuntime_Microsoft) alias __int64 = long; } +/* Make D's character types available in ImportC. + */ +alias __importc_char = char; +alias __importc_wchar = wchar; +alias __importc_dchar = dchar; + /*********** floating point *************/ /* https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html diff --git a/druntime/src/importc.h b/druntime/src/importc.h index 66d45ea920c4..c6b7d469112d 100644 --- a/druntime/src/importc.h +++ b/druntime/src/importc.h @@ -75,6 +75,21 @@ typedef unsigned short __uint16_t; typedef unsigned int __uint32_t; typedef unsigned long long __uint64_t; +/* wchar_t */ +#if defined(_WIN32) +#ifndef _WCHAR_T_DEFINED +// On Windows, wchar_t is defined as an unsigned 16-bit integer: the same as D's wchar. +typedef __importc_wchar wchar_t; +#define _WCHAR_T_DEFINED 1 +#define _NATIVE_WCHAR_T_DEFINED 1 + +#ifdef _MSC_VER +// Microsoft go a step further and have a proper built-in type. +typedef __importc_wchar __wchar_t; +#endif +#endif +#endif + /********************* * Obsolete detritus */ diff --git a/spec/importc.dd b/spec/importc.dd index 66a97c45164f..859b725638e7 100644 --- a/spec/importc.dd +++ b/spec/importc.dd @@ -487,6 +487,12 @@ $(H2 $(LNAME2 implementation, Implementation)) C compiler) on the target platform. ) + $(H3 $(LNAME2 wchar_t, `wchar_t`)) + + $(P When targeting Windows, `wchar_t` is a `typedef` for $(RELATIVE_LINK2 d-character-types, `__importc_wchar`). + When targeting platforms other than Windows, `wchar_t` receives no special treatment + and thus is defined by the `` header, as usual.) + $(H3 $(LNAME2 implicit-function-declaration, Implicit Function Declarations)) $(P Implicit function declarations:) @@ -731,6 +737,11 @@ _Static_assert(sizeof(A) == 1, "A should be size 1"); ) + $(H3 $(LNAME2 d-character-types, D Character Types)) + + $(P D's character types are available in ImportC via the + `__importc_char`, `__importc_wchar`, and `__importc_dchar` aliases.) + $(H3 $(LNAME2 register, Register Storage Class)) $(P Objects with `register` storage class are treated as `auto` declarations.)