diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst index aac5d500e5036..c731eab01dbca 100644 --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -100,8 +100,19 @@ Deprecations and Removals - 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, libc++ + used to additionally provide 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, so it has been removed. As an exception, ``std::char_traits`` and + ``std::char_traits`` are kept for a limited period of time and marked as deprecated to let people + move off of those, since we know there were some users of those. They will be removed in LLVM 18. + Upcoming Deprecations and Removals ---------------------------------- +- The specializations of ``std::char_traits`` for ``unsigned char`` and ``signed char`` are provided until + LLVM 18. Those non-standard specializations are provided for a transition period and marked as deprecated + but will be removed in the future. API Changes ----------- diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h index 3d9eb1fc05d13..f6ca48d6033d8 100644 --- a/libcxx/include/__string/char_traits.h +++ b/libcxx/include/__string/char_traits.h @@ -39,132 +39,37 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD template -struct _LIBCPP_TEMPLATE_VIS char_traits +struct 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 void assign(char_type&, const char_type&); + static bool eq(char_type, char_type); + static bool lt(char_type, char_type); + + static int compare(const char_type*, const char_type*, size_t); + static size_t length(const char_type*); + static const char_type* find(const char_type*, size_t, const char_type&); + static char_type* move(char_type*, const char_type*, size_t); + static char_type* copy(char_type*, const char_type* __s2, size_t); + static char_type* assign(char_type*, size_t, char_type); + + static int_type not_eof(int_type); + static char_type to_char_type(int_type); + static int_type to_int_type(char_type); + static bool eq_int_type(int_type, int_type); + static int_type eof(); }; - -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 @@ -300,7 +205,6 @@ char_traits::find(const char_type* __s, size_t __n, const char_type& __a) #endif } - // char_traits #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS @@ -713,6 +617,202 @@ char_traits::find(const char_type* __s, size_t __n, const char_type& _ return nullptr; } +// +// Temporary extensions for std::char_traits and std::char_traits. +// TODO: Remove those in LLVM 18. +// +template <> +struct _LIBCPP_TEMPLATE_VIS + _LIBCPP_DEPRECATED_("char_traits is non-standard and is provided for a temporary period. It will be removed in LLVM 18, so please migrate off of it.") + char_traits +{ + using char_type = unsigned char; + 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) { + for (; __n; --__n, ++__s1, ++__s2) + { + if (lt(*__s1, *__s2)) + return -1; + if (lt(*__s2, *__s1)) + return 1; + } + return 0; + } + _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17 + size_t length(const char_type* __s) { + size_t __len = 0; + for (; !eq(*__s, char_type(0)); ++__s) + ++__len; + return __len; + } + _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17 + const char_type* find(const char_type* __s, size_t __n, const char_type& __a) { + for (; __n; --__n) + { + if (eq(*__s, __a)) + return __s; + ++__s; + } + return nullptr; + } + static _LIBCPP_CONSTEXPR_SINCE_CXX20 + char_type* 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; + } + _LIBCPP_INLINE_VISIBILITY + static _LIBCPP_CONSTEXPR_SINCE_CXX20 + char_type* 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; + } + _LIBCPP_INLINE_VISIBILITY + static _LIBCPP_CONSTEXPR_SINCE_CXX20 + char_type* assign(char_type* __s, size_t __n, char_type __a) { + char_type* __r = __s; + for (; __n; --__n, ++__s) + assign(*__s, __a); + return __r; + } + + 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);} +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS + _LIBCPP_DEPRECATED_("char_traits is non-standard and is provided for a temporary period. It will be removed in LLVM 18, so please migrate off of it.") + char_traits +{ + using char_type = signed char; + 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) { + for (; __n; --__n, ++__s1, ++__s2) + { + if (lt(*__s1, *__s2)) + return -1; + if (lt(*__s2, *__s1)) + return 1; + } + return 0; + } + _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17 + size_t length(const char_type* __s) { + size_t __len = 0; + for (; !eq(*__s, char_type(0)); ++__s) + ++__len; + return __len; + } + _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17 + const char_type* find(const char_type* __s, size_t __n, const char_type& __a) { + for (; __n; --__n) + { + if (eq(*__s, __a)) + return __s; + ++__s; + } + return nullptr; + } + static _LIBCPP_CONSTEXPR_SINCE_CXX20 + char_type* 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; + } + _LIBCPP_INLINE_VISIBILITY + static _LIBCPP_CONSTEXPR_SINCE_CXX20 + char_type* 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; + } + _LIBCPP_INLINE_VISIBILITY + static _LIBCPP_CONSTEXPR_SINCE_CXX20 + char_type* assign(char_type* __s, size_t __n, char_type __a) { + char_type* __r = __s; + for (; __n; --__n, ++__s) + assign(*__s, __a); + return __r; + } + + 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);} +}; + // helper fns for basic_string and string_view // __str_find diff --git a/libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.deprecated.verify.cpp b/libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.deprecated.verify.cpp new file mode 100644 index 0000000000000..a201f6e8cf347 --- /dev/null +++ b/libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.deprecated.verify.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template<> struct char_traits +// template<> struct char_traits + +// Make sure we issue deprecation warnings. + +#include + +void f() { + std::char_traits uc; // expected-warning{{'char_traits' is deprecated}} + std::char_traits sc; // expected-warning{{'char_traits' is deprecated}} + + (void)uc; + (void)sc; +} diff --git a/libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.pass.cpp b/libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.pass.cpp new file mode 100644 index 0000000000000..d67fb9c175333 --- /dev/null +++ b/libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.pass.cpp @@ -0,0 +1,145 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template<> struct char_traits +// template<> struct char_traits + +// Non-standard but provided temporarily for users to migrate. + +// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated + +#include +#include +#include + +#include "test_macros.h" + +template +TEST_CONSTEXPR_CXX20 bool test() { + static_assert(std::is_same::char_type, Char>::value, ""); + static_assert(std::is_same::int_type, int>::value, ""); + static_assert(std::is_same::off_type, std::streamoff>::value, ""); + static_assert(std::is_same::pos_type, std::streampos>::value, ""); + static_assert(std::is_same::state_type, std::mbstate_t>::value, ""); + + assert(std::char_traits::to_int_type(Char('a')) == Char('a')); + assert(std::char_traits::to_int_type(Char('A')) == Char('A')); + assert(std::char_traits::to_int_type(0) == 0); + + assert(std::char_traits::to_char_type(Char('a')) == Char('a')); + assert(std::char_traits::to_char_type(Char('A')) == Char('A')); + assert(std::char_traits::to_char_type(0) == 0); + + assert(std::char_traits::eof() == EOF); + + assert(std::char_traits::not_eof(Char('a')) == Char('a')); + assert(std::char_traits::not_eof(Char('A')) == Char('A')); + assert(std::char_traits::not_eof(0) == 0); + assert(std::char_traits::not_eof(std::char_traits::eof()) != + std::char_traits::eof()); + + assert(std::char_traits::lt(Char('\0'), Char('A')) == (Char('\0') < Char('A'))); + assert(std::char_traits::lt(Char('A'), Char('\0')) == (Char('A') < Char('\0'))); + assert(std::char_traits::lt(Char('a'), Char('a')) == (Char('a') < Char('a'))); + assert(std::char_traits::lt(Char('A'), Char('a')) == (Char('A') < Char('a'))); + assert(std::char_traits::lt(Char('a'), Char('A')) == (Char('a') < Char('A'))); + + assert( std::char_traits::eq(Char('a'), Char('a'))); + assert(!std::char_traits::eq(Char('a'), Char('A'))); + + assert( std::char_traits::eq_int_type(Char('a'), Char('a'))); + assert(!std::char_traits::eq_int_type(Char('a'), Char('A'))); + assert(!std::char_traits::eq_int_type(std::char_traits::eof(), Char('A'))); + assert( std::char_traits::eq_int_type(std::char_traits::eof(), std::char_traits::eof())); + + { + Char s1[] = {1, 2, 3, 0}; + Char s2[] = {0}; + assert(std::char_traits::length(s1) == 3); + assert(std::char_traits::length(s2) == 0); + } + + { + Char s1[] = {1, 2, 3}; + assert(std::char_traits::find(s1, 3, Char(1)) == s1); + assert(std::char_traits::find(s1, 3, Char(2)) == s1+1); + assert(std::char_traits::find(s1, 3, Char(3)) == s1+2); + assert(std::char_traits::find(s1, 3, Char(4)) == 0); + assert(std::char_traits::find(s1, 3, Char(0)) == 0); + assert(std::char_traits::find(NULL, 0, Char(0)) == 0); + } + + { + Char s1[] = {1, 2, 3}; + Char s2[3] = {0}; + assert(std::char_traits::copy(s2, s1, 3) == s2); + assert(s2[0] == Char(1)); + assert(s2[1] == Char(2)); + assert(s2[2] == Char(3)); + assert(std::char_traits::copy(NULL, s1, 0) == NULL); + assert(std::char_traits::copy(s1, NULL, 0) == s1); + } + + { + Char s1[] = {1, 2, 3}; + assert(std::char_traits::move(s1, s1+1, 2) == s1); + assert(s1[0] == Char(2)); + assert(s1[1] == Char(3)); + assert(s1[2] == Char(3)); + s1[2] = Char(0); + assert(std::char_traits::move(s1+1, s1, 2) == s1+1); + assert(s1[0] == Char(2)); + assert(s1[1] == Char(2)); + assert(s1[2] == Char(3)); + assert(std::char_traits::move(NULL, s1, 0) == NULL); + assert(std::char_traits::move(s1, NULL, 0) == s1); + } + + { + Char s1[] = {0}; + assert(std::char_traits::compare(s1, s1, 0) == 0); + assert(std::char_traits::compare(NULL, NULL, 0) == 0); + + Char s2[] = {1, 0}; + Char s3[] = {2, 0}; + assert(std::char_traits::compare(s2, s2, 1) == 0); + assert(std::char_traits::compare(s2, s3, 1) < 0); + assert(std::char_traits::compare(s3, s2, 1) > 0); + } + + { + Char s2[3] = {0}; + assert(std::char_traits::assign(s2, 3, Char(5)) == s2); + assert(s2[0] == Char(5)); + assert(s2[1] == Char(5)); + assert(s2[2] == Char(5)); + assert(std::char_traits::assign(NULL, 0, Char(5)) == NULL); + } + + { + Char c = Char('\0'); + std::char_traits::assign(c, Char('a')); + assert(c == Char('a')); + } + + return true; +} + +int main(int, char**) { + test(); + test(); + +#if TEST_STD_VER > 17 + static_assert(test()); + static_assert(test()); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/general.pass.cpp index 0da59ca4e1fdd..421453245ef8d 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/general.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/general.pass.cpp @@ -19,27 +19,36 @@ #include #include #include +#include #include -#include #include +#include #include #include #include "types.h" -// A constexpr-friendly lightweight string, primarily useful for comparisons. -// Unlike `std::string_view`, it copies the given string into an -// internal buffer and can work with non-contiguous inputs. +// Basic utility to convert a range to a string-like type. This handles ranges +// that do not contain character types and can work with non-contiguous inputs. template class BasicSmallString { - std::basic_string buffer_{}; + std::vector buffer_{}; public: - constexpr BasicSmallString(std::basic_string_view v) : buffer_(v) {} + constexpr BasicSmallString(std::basic_string_view v) + requires (std::same_as || +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::same_as || +#endif + std::same_as || + std::same_as || + std::same_as) + : buffer_(v.begin(), v.end()) + {} template constexpr BasicSmallString(I b, const S& e) { for (; b != e; ++b) { - buffer_ += *b; + buffer_.push_back(*b); } } diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp index 8a8c8ff6049ea..7d9cf9aecd900 100644 --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp @@ -11,17 +11,51 @@ // void push_back(charT c) // constexpr since C++20 #include +#include #include #include "test_macros.h" #include "min_allocator.h" -struct veryLarge -{ +struct VeryLarge { long long a; char b; }; +namespace std { + template <> + struct char_traits { + using char_type = VeryLarge; + using int_type = int; + using off_type = streamoff; + using pos_type = streampos; + using state_type = mbstate_t; + + static TEST_CONSTEXPR_CXX20 void assign(char_type& c1, const char_type& c2) { c1 = c2; } + static bool eq(char_type c1, char_type c2); + static bool lt(char_type c1, char_type c2); + + static int compare(const char_type* s1, const char_type* s2, size_t n); + static size_t length(const char_type* s); + static const char_type* find(const char_type* s, size_t n, const char_type& a); + static char_type* move(char_type* s1, const char_type* s2, size_t n); + static TEST_CONSTEXPR_CXX20 char_type* copy(char_type* s1, const char_type* s2, size_t n) { + std::copy_n(s2, n, s1); + return s1; + } + static TEST_CONSTEXPR_CXX20 char_type* assign(char_type* s, size_t n, char_type a) { + std::fill_n(s, n, a); + return s; + } + + static int_type not_eof(int_type c); + static char_type to_char_type(int_type c); + static int_type to_int_type(char_type c); + static bool eq_int_type(int_type c1, int_type c2); + static int_type eof(); + }; +} // end namespace std + template TEST_CONSTEXPR_CXX20 void test(S s, typename S::value_type c, S expected) @@ -48,9 +82,9 @@ TEST_CONSTEXPR_CXX20 bool test() { #endif { -// https://llvm.org/PR31454 - std::basic_string s; - veryLarge vl = {}; + // https://llvm.org/PR31454 + std::basic_string s; + VeryLarge vl = {}; s.push_back(vl); s.push_back(vl); s.push_back(vl);