In c++11 char16_t is a built-in fundamental type, but in c11 it is a typedef from <uchar.h>
Signed-off-by: Kevin Puetz PuetzKevinA@JohnDeere.com --- include/sqltypes.h | 3 +++ include/tchar.h | 3 +++ include/winnt.h | 3 +++ 3 files changed, 9 insertions(+)
diff --git a/include/sqltypes.h b/include/sqltypes.h index 0923f6b362..8d406df562 100644 --- a/include/sqltypes.h +++ b/include/sqltypes.h @@ -31,6 +31,9 @@ typedef unsigned char SQLCHAR; #if defined(WINE_UNICODE_NATIVE) typedef wchar_t SQLWCHAR; #elif defined(WINE_UNICODE_CHAR16) +# if !defined(__cplusplus) && !defined(RC_INVOKED) +# include <uchar.h> /* Bring in char16_t and char32_t for C */ +# endif typedef char16_t SQLWCHAR; #else typedef unsigned short SQLWCHAR; diff --git a/include/tchar.h b/include/tchar.h index 9fc4c72099..56f876bf84 100644 --- a/include/tchar.h +++ b/include/tchar.h @@ -241,6 +241,9 @@ typedef unsigned short wctype_t; #if defined(WINE_UNICODE_NATIVE) typedef wchar_t _TCHAR; #elif defined(WINE_UNICODE_CHAR16) +# if !defined(__cplusplus) && !defined(RC_INVOKED) +# include <uchar.h> /* Bring in char16_t and char32_t for C */ +# endif typedef char16_t _TCHAR; #else typedef unsigned short _TCHAR; diff --git a/include/winnt.h b/include/winnt.h index e1cf78420a..126135eca2 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -463,6 +463,9 @@ typedef int LONG, *PLONG; #if defined(WINE_UNICODE_NATIVE) typedef wchar_t WCHAR; #elif defined(WINE_UNICODE_CHAR16) +# if !defined(__cplusplus) && !defined(RC_INVOKED) +# include <uchar.h> /* Bring in char16_t and char32_t for C */ +# endif typedef char16_t WCHAR; #else typedef unsigned short WCHAR;
Hi Kevin,
On 17.07.2020 03:09, Puetz Kevin A wrote:
In c++11 char16_t is a built-in fundamental type, but in c11 it is a typedef from <uchar.h>
I was assuming that WINE_UNICODE_CHAR16 is mostly for C++, it doesn't seem very useful in C. Is there a reason it's needed?
If the concern is that things break when it's defined, maybe we could change checks to make it no-op in C:
#if defined(WINE_UNICODE_CHAR16) && defined(__cplusplus)
We'd then typedef WCHAR to unsigned short, like we usually do. uchar.h uses unsigned short as well, so the result should be the same without introducing an additional includes.
Thanks,
Jacek
In c++11 char16_t is a built-in fundamental type, but in c11 it is a typedef from <uchar.h>
I was assuming that WINE_UNICODE_CHAR16 is mostly for C++, it doesn't seem very useful in C. Is there a reason it's needed?
I don't know if I'd go as far as *needed*, but C11 does have both char16_t and u"", so WINE_UNICODE_CHAR16 is at least useful in C too. It allows you to use -DUNICODE and have TEXT("...") macros that match the Foo-> FooW functions just like in MSVC, without requiring -fshort-wchar (which beaks ABI for libc and other libraries)
If the concern is that things break when it's defined, maybe we could change checks to make it no-op in C:
#if defined(WINE_UNICODE_CHAR16) && defined(__cplusplus)
Yes, that was my main concern. Usually one sets the same #defines for C and C++, so if you're setting it for C++ the headers end up not working in C by breaking include-what-you-use and referencing an undefined type.
We'd then typedef WCHAR to unsigned short, like we usually do. uchar.h uses unsigned short as well, so the result should be the same without introducing an additional includes.
That could work too, especially since in C char16_t is no* a distinct type (and there's no function-overload mangling). Once you have <uchar.h>, char16_t is "the same type as uint16_t", which is almost certainly unsigned short anyway. So it's just a different route to the same result. And, since u"" *is* a built-in, one could even still offer TEXT macros for C11 in the final #else.
e.g. a shape like the following
#if defined(WINE_UNICODE_NATIVE) typedef wchar_t WCHAR #define TEXT(x) L ## x #elif defined(WINE_UNICODE_CHAR16) && defined(__cplusplus) typedef char16_t WCHAR #define TEXT(x) u ## x #else typedef unsigned short WCHAR #if __STDC_UTF_16__ /* C11 */ #define TEXT(x) u ## x #endif #endif
It's a little less more complex (since you need to know how char16_t Is defined to argue that u"" matches this WCHAR), but I think it would work for any compiler that actually has a 16-bit unsigned integral type, and anything so exotic it doesn't can't really plausibly support wine.
We'd then typedef WCHAR to unsigned short, like we usually do. uchar.h uses unsigned short as well, so the result should be the same without introducing an additional includes.
That could work too, especially since in C char16_t is not a distinct type (and there's no function-overload mangling). Once you have <uchar.h>, char16_t is "the same type as uint16_t", which is almost certainly unsigned short anyway. So it's just a different route to the same result. And, since u"" *is* a built-in, one could even still offer TEXT macros for C11 in the final #else.
e.g. a shape like the following
#if defined(WINE_UNICODE_NATIVE) typedef wchar_t WCHAR #define TEXT(x) L ## x #elif defined(WINE_UNICODE_CHAR16) && defined(__cplusplus) typedef char16_t WCHAR #define TEXT(x) u ## x #else typedef unsigned short WCHAR #if __STDC_UTF_16__ /* C11 */ #define TEXT(x) u ## x #endif #endif
It's a little less more complex (since you need to know how char16_t Is defined to argue that u"" matches this WCHAR), but I think it would work for any compiler that actually has a 16-bit unsigned integral type, and anything so exotic it doesn't can't really plausibly support wine.
Would you prefer that I redo this patch in the above shape? I think it would work, but I personally prefer it as it currently stands (consistently using char16_t in both C and C++). And I think there is sufficient opt-in; if you're on a pre-C11 platform lacking <uchar.h>, or you don’t want any extra utf16 symbols in scope, just don't define WINE_UNICODE_CHAR16.
Another option would be using __CHAR16_TYPE__, though that's gcc-specific. I originally had a version of "include: Fix conflicting definitions of wchar_t..." that used __WCHAR_TYPE__ in this fashion, before I settled on using <stddef.h> as a more portable solution and a path to also fixing my other ODR issue with NULL (e.g. windef.h's 0 is 32-bit, gcc <stddef.h> uses __null, which can be a 64-bit type).
On 21.07.2020 16:17, Puetz Kevin A wrote:
We'd then typedef WCHAR to unsigned short, like we usually do. uchar.h uses unsigned short as well, so the result should be the same without introducing an additional includes.
That could work too, especially since in C char16_t is not a distinct type (and there's no function-overload mangling). Once you have <uchar.h>, char16_t is "the same type as uint16_t", which is almost certainly unsigned short anyway. So it's just a different route to the same result. And, since u"" *is* a built-in, one could even still offer TEXT macros for C11 in the final #else.
e.g. a shape like the following
#if defined(WINE_UNICODE_NATIVE) typedef wchar_t WCHAR #define TEXT(x) L ## x #elif defined(WINE_UNICODE_CHAR16) && defined(__cplusplus) typedef char16_t WCHAR #define TEXT(x) u ## x #else typedef unsigned short WCHAR #if __STDC_UTF_16__ /* C11 */ #define TEXT(x) u ## x #endif #endif
It's a little less more complex (since you need to know how char16_t Is defined to argue that u"" matches this WCHAR), but I think it would work for any compiler that actually has a 16-bit unsigned integral type, and anything so exotic it doesn't can't really plausibly support wine.
Would you prefer that I redo this patch in the above shape? I think it would work, but I personally prefer it as it currently stands (consistently using char16_t in both C and C++). And I think there is sufficient opt-in; if you're on a pre-C11 platform lacking <uchar.h>, or you don’t want any extra utf16 symbols in scope, just don't define WINE_UNICODE_CHAR16.
Another option would be using __CHAR16_TYPE__, though that's gcc-specific. I originally had a version of "include: Fix conflicting definitions of wchar_t..." that used __WCHAR_TYPE__ in this fashion, before I settled on using <stddef.h> as a more portable solution and a path to also fixing my other ODR issue with NULL (e.g. windef.h's 0 is 32-bit, gcc <stddef.h> uses __null, which can be a 64-bit type).
I would prefer to make WINE_UNICODE_CHAR16 a no-op here, yes. I think that ideally we would keep it as simple as possible and try to avoid having differences between WINE_UNICODE_CHAR16 and non-WINE_UNICODE_CHAR16 to minimum. Those few typedefs are all places in Wine that need to be aware of char16_t, all other places may just use WCHAR. A new include with a new type that's not really needed for Wine headers has bigger impact on compiled code than we need. I'd prefer to avoid it.
I'm not sure why you mention a problem with TEXT macro. Current solution from winnt.rh uses u"" always when WINE_UNICODE_NATIVE is not used, so it's used in WINE_UNICODE_CHAR16 case as well. While it could be possible to try harder to make sure that it's supported by compiler, where is not much we can do about it. I don't see any fallback we could use in such case, so we may as well just let compiler fail to parse code that uses it in such case.
Thanks,
Jacek
Another option would be using __CHAR16_TYPE__, though that's gcc-
specific.
I originally had a version of "include: Fix conflicting definitions of wchar_t..." that used __WCHAR_TYPE__ in this fashion, before I settled on using <stddef.h> as a more portable solution and a path to also fixing my other ODR issue with NULL (e.g. windef.h's 0 is 32-bit, gcc <stddef.h> uses
__null, which can be a 64-bit type).
I would prefer to make WINE_UNICODE_CHAR16 a no-op here, yes. I think that ideally we would keep it as simple as possible and try to avoid having differences between WINE_UNICODE_CHAR16 and non-WINE_UNICODE_CHAR16 to minimum. Those few typedefs are all places in Wine that need to be aware of char16_t, all other places may just use WCHAR. A new include with a new type that's not really needed for Wine headers has bigger impact on compiled code than we need. I'd prefer to avoid it.
Ok, it's messier, but I can live with that. I just figured wine itself never set WINE_UNICODE_CHAR16, and anyone's project that did would be unsurprised to now get the definitions of <uchar.h>, so it was the "obviously correct" path instead of the "reverse engineer libc and match it".
I'm not sure why you mention a problem with TEXT macro. Current solution from winnt.rh uses u"" always when WINE_UNICODE_NATIVE is not used, so it's used in WINE_UNICODE_CHAR16 case as well. While it could be possible to try harder to make sure that it's supported by compiler, where is not much we can do about it. I don't see any fallback we could use in such case, so we may as well just let compiler fail to parse code that uses it in such case.
My issue was that I could easily have a compiler which does support u"", but a project that did not set WINE_UNICODE_CHAR16. In which TEXT() compiles, but has type char16_t[], not WCHAR[]. With overloading, templates, or auto, the eventual mismatch error can be quite distant from the offending TEXT().
This isn't such an issue for C, since char16_t=unsigned short anyway so it will probably work out.
I would also be perfectly happy to make this even simpler and just make char16_t consistent, e.g. WINE_UNICODE_NATIVE -> wchar_t and L"", else char16_t and u"". for C and pre-C++11 where it isn't already a fundamental type, Wine would follow GCC's __CHAR16_TYPE__ (thus matching <uchar.h>) or just use unsigned short (which is in practice what __CHAR16_TYPE__ will be anyway).
#ifdef WINE_UNICODE_NATIVE typdef wchar_t WCHAR; #define TEXT(x) L ## x #else #ifndef __cpp_unicode_characters #ifdef __CHAR16_TYPE__ typedef __CHAR16_TYPE__ char16_t; #else typedef unsigned short char16_t; #endif typedef char16_t WCHAR; #define TEXT(x) u ## x #endif
That could be an ABI breaking change for C++11 winelib programs since WCHAR in functions that aren't extern "C" would now name-mangle char16_t. But it doesn't change anything for C (or for C++03). I don't know to what extent wine makes winelib ABI promises, and I guess in any case wine 5->6 will be a major version. Maybe it's OK? It's certainly tidier... only 2 choices, and just controlled by -f(no-)short-wchar.
Thanks,
Jacek