[PATCH v2 1/4] include: Fix undefined char16_t in C11.

Jacek Caban jacek at codeweavers.com
Thu Sep 24 06:55:11 CDT 2020


On 23.09.2020 19:43, Puetz Kevin A wrote:
>
>> -----Original Message-----
>> From: Jacek Caban <jacek at codeweavers.com>
>> Sent: Wednesday, September 23, 2020 9:44 AM
>>> In c++11 char16_t is a distinct fundamental type,
>>> but in c11 it is merely a typedef in <uchar.h>.
>>>
>>> Explicitly mention char16_t only in c++11 (where it is built-in),
>>> otherwise define WCHAR to match u"...", without naming char16_t.
>>>
>>> Remove WINE_UNICODE_CHAR16; it is now the default when supported.
>> I like the part that uses __cpp_unicode_literals, it would make our
>> headers much more C++ friendly by default.
>>
>> I'm less sure if we want __CHAR16_TYPE__. In practice, it will only
>> affect C, which is much less strict about types anyway. We assume in
>> Wine code base that WCHAR is 16-bit unsigned integer. If __CHAR16_TYPE__
>> is something else, we shouldn't use it. If it's the same, then there is
>> little point in using it. I think that the original problem is fixed by
>> __cpp_unicode_literals change alone, so how about doing just that?
> __CHAR16_TYPE__ (per C11 standard) is always the same type as uint_least16_t.
> Which, in turn, is always a typedef for one of the ordinary integer types.
> So it is just a 16-bit unsigned integer, unless one doesn't exist at all ,
> in which case it's the smallest unsigned integer that can hold 0...65535.
> It's never a distinct type like char16_t is for c++11/__cpp_unicode_literals.
>
> What isn't guaranteed is that the only suitable type is `unsigned short`,
> it could legally be `unsigned int` (if that was also 16-bit).
>
> I don't quite agree that ignoring this is preferable because C
> "is much less strict about types anyway."
> 1. The __CHAR16_TYPE__ path applies to C++98 and C++03,
>     which lack __cpp_unicode_literals but might have a C-ish char16_t.
>     So its behavior shouldn't completely ignore c++.


It's not clear to me that we want to change the default in this case 
(and even if we do, it could be C++ only change).


> 2. C has mostly the same strict-aliasing rules as C++, which would
>     not permit `const unsigned short *` pointing to `unsigned int[]`,
>     even if they are the same size.
>     So when LPCTSTR = TEXT("...") becomes const WCHAR * = u"...",
>     if WCHAR is `short` but __CHAR16_TYPE__ is e.g. `int`,
>     there is a strict-aliasing violation (and undefined behavior) in C too.
>
> Now, in practice wine probably doesn't support any platform with 16-bit `int`,
> So __CHAR16_TYPE__ is just going to be `unsigned short` anyway.
> This way is pedantically more portable (to various architectures,
> if they are using gcc or clang which provide __CHAR16_TYPE__)
> But in practice they will preprocess to the same thing, which makes
> both the arguments in favor and the arguments against moot.
>
> So I'll drop it (after this last attempt to justify it) if that's what you want;
> I care about char16_t mostly in C++11, but was just trying to fix the C path
> to be portable too on general principle. Not a hill I need to die on :-)


I can see your point, but by changing C path, you put compatibility of 
Wine itself into the consideration. WCHAR is an important core type for 
Wine and we have a simple declaration that worked for years. If we were 
writing it from scratch, the consideration could be different. I think 
we agree the existing declaration works equally good in practice (esp. 
once WINE_UNICODE_CHAR16 handling is fixed in C), so I would prefer to 
avoid the additional complication. If we'd have 16-bit int, we would 
have much more problems than WCHAR declaration.


Thanks,

Jacek




More information about the wine-devel mailing list