Skip to content

STL: When wchar_t is a real type, users shouldn't see unsigned short machinery #216

@StephanTLavavej

Description

@StephanTLavavej

Because the STL grudgingly supports /Zc:wchar_t- (see #212), we occasionally need to detect _NATIVE_WCHAR_T_DEFINED.

For a correct (although weird) example, the STL always defines numeric_limits<wchar_t>:

STL/stl/inc/limits

Lines 460 to 461 in 6b0238d

template <>
class numeric_limits<wchar_t> : public _Num_int_base {

Then if wchar_t is a real type, it additionally defines numeric_limits<unsigned short>:

STL/stl/inc/limits

Lines 685 to 688 in 6b0238d

#ifdef _NATIVE_WCHAR_T_DEFINED
// CLASS numeric_limits<unsigned short>
template <>
class numeric_limits<unsigned short> : public _Num_int_base {

This is backwards, but it works. Users with real wchar_t get both specializations, while users with fake wchar_t get only one.

However, the STL appears to have incorrect logic elsewhere. It follows the numeric_limits pattern for char_traits:

STL/stl/inc/xstring

Lines 265 to 275 in 6b0238d

// STRUCT char_traits<wchar_t>
template <>
struct char_traits<wchar_t> : _WChar_traits<wchar_t> {}; // properties of a string or stream wchar_t element
#ifdef _NATIVE_WCHAR_T_DEFINED
// STRUCT char_traits<unsigned short>
template <>
struct char_traits<unsigned short> : _WChar_traits<unsigned short> {
// properties of a string or stream unsigned short element
};
#endif // _NATIVE_WCHAR_T_DEFINED

But when wchar_t is a real type, char_traits<unsigned short> doesn't make any sense!

<fstream> has many similar examples. basic_ifstream is always constructible from const wchar_t*:

STL/stl/inc/fstream

Lines 823 to 824 in 6b0238d

explicit basic_ifstream(
const wchar_t* _Filename, ios_base::openmode _Mode = ios_base::in, int _Prot = ios_base::_Default_open_prot)

And when wchar_t is real, it's also constructible from const unsigned short*:

STL/stl/inc/fstream

Lines 850 to 852 in 6b0238d

#ifdef _NATIVE_WCHAR_T_DEFINED
explicit basic_ifstream(const unsigned short* _Filename, ios_base::openmode _Mode = ios_base::in,
int _Prot = ios_base::_Default_open_prot)

I believe that all of our _NATIVE_WCHAR_T_DEFINED logic needs to be audited. When we're separately compiling the STL, wchar_t is always a real type, and we additionally need to provide unsigned short counterparts (so we should detect whether we're building the STL). But when headers are being used to compile user code, users with real wchar_t should see only wchar_t for character-ish things, never unsigned short. (Users with fake wchar_t will see only wchar_t being a typedef for unsigned short, as they should.)

In theory, this should not affect ABI compatibility, although it may affect source compatibility (if users with real wchar_t somehow took a dependency on the unsigned short machinery).

Also tracked by Microsoft-internal VSO-387426 / AB#387426.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementSomething can be improvedfixedSomething works now, yay!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions