[libc++] Add an option to disable wide character support in libc++

Some embedded platforms do not wish to support the C library functionality
for handling wchar_t because they have no use for it. It makes sense for
libc++ to work properly on those platforms, so this commit adds a carve-out
of functionality for wchar_t.

Unfortunately, unlike some other carve-outs (e.g. random device), this
patch touches several parts of the library. However, despite the wide
impact of this patch, I still think it is important to support this
configuration since it makes it much simpler to port libc++ to some
embedded platforms.

Differential Revision: https://reviews.llvm.org/D111265
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index 012b2ea..c8dae34 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -9,13 +9,16 @@
 #include "string"
 #include "charconv"
 #include "cstdlib"
-#include "cwchar"
 #include "cerrno"
 #include "limits"
 #include "stdexcept"
 #include <stdio.h>
 #include "__debug"
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+#   include "cwchar"
+#endif
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 void __basic_string_common<true>::__throw_length_error() const {
@@ -28,11 +31,15 @@
 
 #define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template __VA_ARGS__;
 #ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
-_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
-_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
+    _LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
+#   ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+        _LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
+#   endif
 #else
-_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
-_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
+    _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
+#   ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+        _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
+#   endif
 #endif
 #undef _LIBCPP_EXTERN_TEMPLATE_DEFINE
 
@@ -137,6 +144,7 @@
     return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 // wstring
 template<>
 inline
@@ -181,6 +189,7 @@
 {
     return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
 }
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
 
 // as_float
 
@@ -232,6 +241,7 @@
     return as_float_helper<long double>( func, s, idx, strtold );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template<>
 inline
 float
@@ -255,6 +265,7 @@
 {
     return as_float_helper<long double>( func, s, idx, wcstold );
 }
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
 
 }  // unnamed namespace
 
@@ -264,11 +275,13 @@
     return as_integer<int>( "stoi", str, idx, base );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 int
 stoi(const wstring& str, size_t* idx, int base)
 {
     return as_integer<int>( "stoi", str, idx, base );
 }
+#endif
 
 long
 stol(const string& str, size_t* idx, int base)
@@ -276,11 +289,13 @@
     return as_integer<long>( "stol", str, idx, base );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 long
 stol(const wstring& str, size_t* idx, int base)
 {
     return as_integer<long>( "stol", str, idx, base );
 }
+#endif
 
 unsigned long
 stoul(const string& str, size_t* idx, int base)
@@ -288,11 +303,13 @@
     return as_integer<unsigned long>( "stoul", str, idx, base );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 unsigned long
 stoul(const wstring& str, size_t* idx, int base)
 {
     return as_integer<unsigned long>( "stoul", str, idx, base );
 }
+#endif
 
 long long
 stoll(const string& str, size_t* idx, int base)
@@ -300,11 +317,13 @@
     return as_integer<long long>( "stoll", str, idx, base );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 long long
 stoll(const wstring& str, size_t* idx, int base)
 {
     return as_integer<long long>( "stoll", str, idx, base );
 }
+#endif
 
 unsigned long long
 stoull(const string& str, size_t* idx, int base)
@@ -312,11 +331,13 @@
     return as_integer<unsigned long long>( "stoull", str, idx, base );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 unsigned long long
 stoull(const wstring& str, size_t* idx, int base)
 {
     return as_integer<unsigned long long>( "stoull", str, idx, base );
 }
+#endif
 
 float
 stof(const string& str, size_t* idx)
@@ -324,11 +345,13 @@
     return as_float<float>( "stof", str, idx );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 float
 stof(const wstring& str, size_t* idx)
 {
     return as_float<float>( "stof", str, idx );
 }
+#endif
 
 double
 stod(const string& str, size_t* idx)
@@ -336,11 +359,13 @@
     return as_float<double>( "stod", str, idx );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 double
 stod(const wstring& str, size_t* idx)
 {
     return as_float<double>( "stod", str, idx );
 }
+#endif
 
 long double
 stold(const string& str, size_t* idx)
@@ -348,11 +373,13 @@
     return as_float<long double>( "stold", str, idx );
 }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 long double
 stold(const wstring& str, size_t* idx)
 {
     return as_float<long double>( "stold", str, idx );
 }
+#endif
 
 // to_string
 
@@ -403,6 +430,7 @@
     }
 };
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <>
 struct initial_string<wstring>
 {
@@ -427,6 +455,7 @@
     return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
 #endif
 }
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
 
 template <typename S, typename V>
 S i_to_string(V v)
@@ -450,20 +479,23 @@
 string  to_string (unsigned long val)      { return i_to_string< string>(val); }
 string  to_string (unsigned long long val) { return i_to_string< string>(val); }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 wstring to_wstring(int val)                { return i_to_string<wstring>(val); }
 wstring to_wstring(long val)               { return i_to_string<wstring>(val); }
 wstring to_wstring(long long val)          { return i_to_string<wstring>(val); }
 wstring to_wstring(unsigned val)           { return i_to_string<wstring>(val); }
 wstring to_wstring(unsigned long val)      { return i_to_string<wstring>(val); }
 wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
-
+#endif
 
 string  to_string (float val)       { return as_string(snprintf,       initial_string< string>()(),   "%f", val); }
 string  to_string (double val)      { return as_string(snprintf,       initial_string< string>()(),   "%f", val); }
 string  to_string (long double val) { return as_string(snprintf,       initial_string< string>()(),  "%Lf", val); }
 
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 wstring to_wstring(float val)       { return as_string(get_swprintf(), initial_string<wstring>()(),  L"%f", val); }
 wstring to_wstring(double val)      { return as_string(get_swprintf(), initial_string<wstring>()(),  L"%f", val); }
 wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
+#endif
 
 _LIBCPP_END_NAMESPACE_STD