Rollback: Improve detection for wchar_t and wstring support.

Add a configurable `GTEST_HAS_WCHAR` option to control whether to provide `wchar_t*` overloads for `PrintTo`. Check implementation-specific standard library defines to determine proper defaults for  `GTEST_HAS_WCHAR` and `GTEST_HAS_STD_WSTRING` and to produce compile errors if the users pick a configuration that depends on unavailable standard library features.

PiperOrigin-RevId: 958668507
Change-Id: Ic9b78d83fb455dff7d993303d54a0bde749a8cd8
This commit is contained in:
Abseil Team
2026-08-03 17:36:46 -07:00
committed by Copybara-Service
parent 92f71eddb0
commit 51725d1111
4 changed files with 29 additions and 84 deletions
+7 -2
View File
@@ -676,13 +676,18 @@ inline void PrintTo(char32_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const char32_t*>(s), os); PrintTo(ImplicitCast_<const char32_t*>(s), os);
} }
#if GTEST_HAS_WCHAR // MSVC can be configured to define wchar_t as a typedef of unsigned
// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
// type. When wchar_t is a typedef, defining an overload for const
// wchar_t* would cause unsigned short* be printed as a wide string,
// possibly causing invalid memory accesses.
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
// Overloads for wide C strings // Overloads for wide C strings
GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
inline void PrintTo(wchar_t* s, ::std::ostream* os) { inline void PrintTo(wchar_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const wchar_t*>(s), os); PrintTo(ImplicitCast_<const wchar_t*>(s), os);
} }
#endif // GTEST_HAS_WCHAR #endif
// Overload for C arrays. Multi-dimensional arrays are printed // Overload for C arrays. Multi-dimensional arrays are printed
// properly. // properly.
+6 -78
View File
@@ -80,11 +80,6 @@
// is/isn't available. // is/isn't available.
// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't // GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't
// enabled. // enabled.
// GTEST_HAS_WCHAR - Define it to 1/0 to indicate that wide
// characters are/aren't supported. (Google Test
// can be used where std::char_traits<wchar_t> and
// libc wchar_t functions (putwc, getwc, etc.) are
// unavailable.)
// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that
// std::wstring does/doesn't work (Google Test can // std::wstring does/doesn't work (Google Test can
// be used where std::wstring is unavailable). // be used where std::wstring is unavailable).
@@ -504,89 +499,22 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
#endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // defined(_MSC_VER) || defined(__BORLANDC__)
#endif // GTEST_HAS_EXCEPTIONS #endif // GTEST_HAS_EXCEPTIONS
// 1. Calculate default GTEST_HAS_WCHAR and GTEST_HAS_STD_WSTRING values based #ifndef GTEST_HAS_STD_WSTRING
// on compiler / STL capabilities. // The user didn't tell us whether ::std::wstring is available, so we need
#if defined(_MSC_VER) // to figure it out.
// MSVC always supports ::std::wstring.
#define GTEST_HAS_STD_WSTRING_DEFAULT 1
// MSVC either defines wchar_t as a typedef of unsigned short, or as a native
// type (in which case, it defines _NATIVE_WCHAR_T_DEFINED). When wchar_t is a
// typedef, defining an overload for const wchar_t* would cause unsigned short*
// be printed as a wide string, possibly causing invalid memory accesses, so we
// omit wchar_t overloads in that case.
#if defined(_NATIVE_WCHAR_T_DEFINED)
#define GTEST_HAS_WCHAR_DEFAULT 1
#else
#define GTEST_HAS_WCHAR_DEFAULT 0
#endif
#elif defined(_LIBCPP_VERSION)
#if _LIBCPP_HAS_WIDE_CHARACTERS
#define GTEST_HAS_WCHAR_DEFAULT 1
#define GTEST_HAS_STD_WSTRING_DEFAULT 1
#else
#define GTEST_HAS_WCHAR_DEFAULT 0
#define GTEST_HAS_STD_WSTRING_DEFAULT 0
#endif
#elif defined(__GLIBCXX__)
#if _GLIBCXX_USE_WCHAR_T
#define GTEST_HAS_WCHAR_DEFAULT 1
#define GTEST_HAS_STD_WSTRING_DEFAULT 1
#else
#define GTEST_HAS_WCHAR_DEFAULT 0
#define GTEST_HAS_STD_WSTRING_DEFAULT 0
#endif
#else
// Unknown standard library implementation; fall back to a list of OSes known to
// not support wide characters.
//
// Cygwin 1.7 and below doesn't support ::std::wstring. // Cygwin 1.7 and below doesn't support ::std::wstring.
// Solaris' libc++ doesn't support it either. Android has // Solaris' libc++ doesn't support it either. Android has
// no support for it at least as recent as Froyo (2.2). // no support for it at least as recent as Froyo (2.2).
//
// Always let the user override the defaults in this case; they might have more
// information about what's supported than we do.
#if (!(defined(GTEST_OS_LINUX_ANDROID) || defined(GTEST_OS_CYGWIN) || \ #if (!(defined(GTEST_OS_LINUX_ANDROID) || defined(GTEST_OS_CYGWIN) || \
defined(GTEST_OS_SOLARIS) || defined(GTEST_OS_HAIKU) || \ defined(GTEST_OS_SOLARIS) || defined(GTEST_OS_HAIKU) || \
defined(GTEST_OS_ESP32) || defined(GTEST_OS_ESP8266) || \ defined(GTEST_OS_ESP32) || defined(GTEST_OS_ESP8266) || \
defined(GTEST_OS_XTENSA) || defined(GTEST_OS_QURT) || \ defined(GTEST_OS_XTENSA) || defined(GTEST_OS_QURT) || \
defined(GTEST_OS_NXP_QN9090) || defined(GTEST_OS_NRF52))) defined(GTEST_OS_NXP_QN9090) || defined(GTEST_OS_NRF52)))
#define GTEST_HAS_WCHAR_DEFAULT 1 #define GTEST_HAS_STD_WSTRING 1
#define GTEST_HAS_STD_WSTRING_DEFAULT 1
#else #else
#define GTEST_HAS_WCHAR_DEFAULT 0 #define GTEST_HAS_STD_WSTRING 0
#define GTEST_HAS_STD_WSTRING_DEFAULT 0
#endif
#endif
// 2. Validate explicit user overrides (if user passed -DGTEST_HAS_*=1)
#if defined(GTEST_HAS_WCHAR) && GTEST_HAS_WCHAR
#if defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED)
#error Cannot explicitly enable GTEST_HAS_WCHAR when wchar_t is a typedef.
#elif defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_WIDE_CHARACTERS
#error Cannot explicitly enable GTEST_HAS_WCHAR without libc++ wide character support.
#elif defined(__GLIBCXX__) && !_GLIBCXX_USE_WCHAR_T
#error Cannot explicitly enable GTEST_HAS_WCHAR without libstdc++ wide character support.
#endif
#endif
#if defined(GTEST_HAS_STD_WSTRING) && GTEST_HAS_STD_WSTRING
#if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_WIDE_CHARACTERS
#error Cannot explicitly enable GTEST_HAS_STD_WSTRING without libc++ wide character support.
#elif defined(__GLIBCXX__) && !_GLIBCXX_USE_WCHAR_T
#error Cannot explicitly enable GTEST_HAS_STD_WSTRING without libstdc++ wide character support.
#endif
#endif
// 3. Set final values if not explicitly overridden by user
#if !defined(GTEST_HAS_WCHAR)
#define GTEST_HAS_WCHAR GTEST_HAS_WCHAR_DEFAULT
#endif
#if !defined(GTEST_HAS_STD_WSTRING)
#define GTEST_HAS_STD_WSTRING GTEST_HAS_STD_WSTRING_DEFAULT
#endif #endif
#endif // GTEST_HAS_STD_WSTRING
#ifndef GTEST_HAS_FILE_SYSTEM #ifndef GTEST_HAS_FILE_SYSTEM
// Most platforms support a file system. // Most platforms support a file system.
+8 -2
View File
@@ -445,10 +445,16 @@ void PrintTo(const char16_t* s, ostream* os) { PrintCStringTo(s, os); }
void PrintTo(const char32_t* s, ostream* os) { PrintCStringTo(s, os); } void PrintTo(const char32_t* s, ostream* os) { PrintCStringTo(s, os); }
#if GTEST_HAS_WCHAR // MSVC compiler can be configured to define whar_t as a typedef
// of unsigned short. Defining an overload for const wchar_t* in that case
// would cause pointers to unsigned shorts be printed as wide strings,
// possibly accessing more memory than intended and causing invalid
// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
// wchar_t is implemented as a native type.
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
// Prints the given wide C string to the ostream. // Prints the given wide C string to the ostream.
void PrintTo(const wchar_t* s, ostream* os) { PrintCStringTo(s, os); } void PrintTo(const wchar_t* s, ostream* os) { PrintCStringTo(s, os); }
#endif // GTEST_HAS_WCHAR #endif // wchar_t is native
namespace { namespace {
+8 -2
View File
@@ -648,7 +648,13 @@ TEST(PrintU32StringTest, EscapesProperly) {
Print(p)); Print(p));
} }
#if GTEST_HAS_WCHAR // MSVC compiler can be configured to define whar_t as a typedef
// of unsigned short. Defining an overload for const wchar_t* in that case
// would cause pointers to unsigned shorts be printed as wide strings,
// possibly accessing more memory than intended and causing invalid
// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
// wchar_t is implemented as a native type.
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
// const wchar_t*. // const wchar_t*.
TEST(PrintWideCStringTest, Const) { TEST(PrintWideCStringTest, Const) {
@@ -679,7 +685,7 @@ TEST(PrintWideCStringTest, EscapesProperly) {
"\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"", "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"",
Print(static_cast<const wchar_t*>(s))); Print(static_cast<const wchar_t*>(s)));
} }
#endif // GTEST_HAS_WCHAR #endif // native wchar_t
// Tests printing pointers to other char types. // Tests printing pointers to other char types.