diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -100,6 +100,12 @@ - The ``_LIBCPP_DEBUG`` macro is not honored anymore, and it is an error to try to use it. Please migrate to ``_LIBCPP_ENABLE_DEBUG_MODE`` instead. +- A base template for ``std::char_traits`` is not provided anymore. The Standard mandates that the library + provides specializations for several types like ``char`` and ``wchar_t``, which libc++ does. However, we + also additionally provided a default implementation for ``std::char_traits`` for arbitrary ``T``. Not + only does the Standard not mandate that one is provided, but such an implementation is bound to be incorrect + for some types. + Upcoming Deprecations and Removals ---------------------------------- diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h --- a/libcxx/include/__string/char_traits.h +++ b/libcxx/include/__string/char_traits.h @@ -39,132 +39,37 @@ _LIBCPP_BEGIN_NAMESPACE_STD template -struct _LIBCPP_TEMPLATE_VIS char_traits +struct _LIBCPP_TEMPLATE_VIS char_traits; +/* +The Standard does not define the base template for char_traits because it is impossible to provide +a correct definition for arbitrary character types. Instead, it requires implementations to provide +specializations for predefined character types like `char`, `wchar_t` and others. We provide this as +exposition-only to document what members a char_traits specialization should provide: { using char_type = _CharT; - using int_type = int; - using off_type = streamoff; - using pos_type = streampos; - using state_type = mbstate_t; - - static inline void _LIBCPP_CONSTEXPR_SINCE_CXX17 - assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;} - static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT - {return __c1 == __c2;} - static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT - {return __c1 < __c2;} - - static _LIBCPP_CONSTEXPR_SINCE_CXX17 - int compare(const char_type* __s1, const char_type* __s2, size_t __n); - _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17 - size_t length(const char_type* __s); - _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17 - const char_type* find(const char_type* __s, size_t __n, const char_type& __a); - static _LIBCPP_CONSTEXPR_SINCE_CXX20 - char_type* move(char_type* __s1, const char_type* __s2, size_t __n); - _LIBCPP_INLINE_VISIBILITY - static _LIBCPP_CONSTEXPR_SINCE_CXX20 - char_type* copy(char_type* __s1, const char_type* __s2, size_t __n); - _LIBCPP_INLINE_VISIBILITY - static _LIBCPP_CONSTEXPR_SINCE_CXX20 - char_type* assign(char_type* __s, size_t __n, char_type __a); - - static inline _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT - {return eq_int_type(__c, eof()) ? ~eof() : __c;} - static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT - {return char_type(__c);} - static inline _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT - {return int_type(__c);} - static inline _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT - {return __c1 == __c2;} - static inline _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT - {return int_type(EOF);} + using int_type = ...; + using off_type = ...; + using pos_type = ...; + using state_type = ...; + + static _LIBCPP_CONSTEXPR_SINCE_CXX17 void assign(char_type&, const char_type&) _NOEXCEPT; + static _LIBCPP_CONSTEXPR bool eq(char_type, char_type) _NOEXCEPT; + static _LIBCPP_CONSTEXPR bool lt(char_type, char_type) _NOEXCEPT; + + static _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type*, const char_type*, size_t); + static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type*); + static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* find(const char_type*, size_t, const char_type&); + static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* move(char_type*, const char_type*, size_t); + static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* copy(char_type*, const char_type* __s2, size_t); + static _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* assign(char_type*, size_t, char_type); + + static _LIBCPP_CONSTEXPR int_type not_eof(int_type) _NOEXCEPT; + static _LIBCPP_CONSTEXPR char_type to_char_type(int_type) _NOEXCEPT; + static _LIBCPP_CONSTEXPR int_type to_int_type(char_type) _NOEXCEPT; + static _LIBCPP_CONSTEXPR bool eq_int_type(int_type, int_type) _NOEXCEPT; + static _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT; }; - -template -_LIBCPP_CONSTEXPR_SINCE_CXX17 int -char_traits<_CharT>::compare(const char_type* __s1, const char_type* __s2, size_t __n) -{ - for (; __n; --__n, ++__s1, ++__s2) - { - if (lt(*__s1, *__s2)) - return -1; - if (lt(*__s2, *__s1)) - return 1; - } - return 0; -} - -template -inline -_LIBCPP_CONSTEXPR_SINCE_CXX17 size_t -char_traits<_CharT>::length(const char_type* __s) -{ - size_t __len = 0; - for (; !eq(*__s, char_type(0)); ++__s) - ++__len; - return __len; -} - -template -inline -_LIBCPP_CONSTEXPR_SINCE_CXX17 const _CharT* -char_traits<_CharT>::find(const char_type* __s, size_t __n, const char_type& __a) -{ - for (; __n; --__n) - { - if (eq(*__s, __a)) - return __s; - ++__s; - } - return nullptr; -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 _CharT* -char_traits<_CharT>::move(char_type* __s1, const char_type* __s2, size_t __n) -{ - if (__n == 0) return __s1; - char_type* __r = __s1; - if (__s1 < __s2) - { - for (; __n; --__n, ++__s1, ++__s2) - assign(*__s1, *__s2); - } - else if (__s2 < __s1) - { - __s1 += __n; - __s2 += __n; - for (; __n; --__n) - assign(*--__s1, *--__s2); - } - return __r; -} - -template -inline _LIBCPP_CONSTEXPR_SINCE_CXX20 -_CharT* -char_traits<_CharT>::copy(char_type* __s1, const char_type* __s2, size_t __n) -{ - if (!__libcpp_is_constant_evaluated()) { - _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range"); - } - char_type* __r = __s1; - for (; __n; --__n, ++__s1, ++__s2) - assign(*__s1, *__s2); - return __r; -} - -template -inline _LIBCPP_CONSTEXPR_SINCE_CXX20 -_CharT* -char_traits<_CharT>::assign(char_type* __s, size_t __n, char_type __a) -{ - char_type* __r = __s; - for (; __n; --__n, ++__s) - assign(*__s, __a); - return __r; -} +*/ template _LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX20 diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/assign2.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/assign2.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/assign2.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/assign2.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/assign3.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/assign3.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/assign3.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/assign3.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/compare.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/compare.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/compare.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/compare.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/copy.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/copy.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/copy.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/copy.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/eof.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/eof.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/eof.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/eof.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/eq.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/eq.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/eq.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/eq.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/eq_int_type.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/eq_int_type.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/eq_int_type.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/eq_int_type.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/find.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/find.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/find.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/find.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/length.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/length.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/length.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/length.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/lt.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/lt.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/lt.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/lt.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/move.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/move.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/move.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/move.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/not_eof.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/not_eof.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/not_eof.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/not_eof.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/to_char_type.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/to_char_type.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/to_char_type.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/to_char_type.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/to_int_type.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/to_int_type.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/to_int_type.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/to_int_type.pass.cpp diff --git a/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/types.compile.pass.cpp b/libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/types.compile.pass.cpp rename from libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/types.compile.pass.cpp rename to libcxx/test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar_t/types.compile.pass.cpp