mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-10-07 19:03:57 +00:00
[libc++] Keep char_traits<T> for arbitrary T around until LLVM 18
This is in response to failures seen after landing D138307. Differential Revision: https://reviews.llvm.org/D138596
This commit is contained in:
parent
e647b4f519
commit
08a0faf4cd
@ -100,19 +100,14 @@ 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<T>`` 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<unsigned char>`` and
|
||||
``std::char_traits<signed char>`` 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.
|
||||
- The base template for ``std::char_traits`` has been marked as deprecated and will be removed in LLVM 18. If
|
||||
you are using ``std::char_traits`` with types other than ``char``, ``wchar_t``, ``char8_t``, ``char16_t``,
|
||||
``char32_t`` or a custom character type for which you specialized ``std::char_traits``, your code will stop
|
||||
working when we remove the base template. The Standard does not mandate that a base template is provided,
|
||||
and such a base template is bound to be incorrect for some types, which could currently cause unexpected
|
||||
behavior while going undetected.
|
||||
|
||||
API Changes
|
||||
-----------
|
||||
|
@ -60,7 +60,7 @@ exposition-only to document what members a char_traits specialization should pro
|
||||
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* copy(char_type*, const char_type*, size_t);
|
||||
static char_type* assign(char_type*, size_t, char_type);
|
||||
|
||||
static int_type not_eof(int_type);
|
||||
@ -71,6 +71,105 @@ exposition-only to document what members a char_traits specialization should pro
|
||||
};
|
||||
*/
|
||||
|
||||
//
|
||||
// Temporary extension to provide a base template for std::char_traits.
|
||||
// TODO: Remove in LLVM 18.
|
||||
//
|
||||
template <class _CharT>
|
||||
struct _LIBCPP_DEPRECATED_("char_traits<T> for T not equal to char, wchar_t, char8_t, char16_t or char32_t 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 = _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) {
|
||||
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 <class _CharT>
|
||||
_LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
|
||||
_CharT* __char_traits_move(_CharT* __dest, const _CharT* __source, size_t __n) _NOEXCEPT
|
||||
@ -617,202 +716,6 @@ char_traits<char32_t>::find(const char_type* __s, size_t __n, const char_type& _
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
// Temporary extensions for std::char_traits<unsigned char> and std::char_traits<signed char>.
|
||||
// TODO: Remove those in LLVM 18.
|
||||
//
|
||||
template <>
|
||||
struct _LIBCPP_TEMPLATE_VIS
|
||||
_LIBCPP_DEPRECATED_("char_traits<unsigned char> 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<unsigned char>
|
||||
{
|
||||
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<signed char> 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<signed char>
|
||||
{
|
||||
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
|
||||
|
@ -8,17 +8,14 @@
|
||||
|
||||
// <string>
|
||||
|
||||
// template<> struct char_traits<unsigned char>
|
||||
// template<> struct char_traits<signed char>
|
||||
// template<> struct char_traits<T> for arbitrary T
|
||||
|
||||
// Make sure we issue deprecation warnings.
|
||||
|
||||
#include <string>
|
||||
|
||||
void f() {
|
||||
std::char_traits<unsigned char> uc; // expected-warning{{'char_traits<unsigned char>' is deprecated}}
|
||||
std::char_traits<signed char> sc; // expected-warning{{'char_traits<signed char>' is deprecated}}
|
||||
|
||||
(void)uc;
|
||||
(void)sc;
|
||||
std::char_traits<unsigned char> t1; (void)t1; // expected-warning{{'char_traits<unsigned char>' is deprecated}}
|
||||
std::char_traits<signed char> t2; (void)t2; // expected-warning{{'char_traits<signed char>' is deprecated}}
|
||||
std::char_traits<unsigned long> t3; (void)t3; // expected-warning{{'char_traits<unsigned long>' is deprecated}}
|
||||
}
|
@ -8,8 +8,7 @@
|
||||
|
||||
// <string>
|
||||
|
||||
// template<> struct char_traits<unsigned char>
|
||||
// template<> struct char_traits<signed char>
|
||||
// template<> struct char_traits<T> for arbitrary T
|
||||
|
||||
// Non-standard but provided temporarily for users to migrate.
|
||||
|
||||
@ -135,10 +134,12 @@ TEST_CONSTEXPR_CXX20 bool test() {
|
||||
int main(int, char**) {
|
||||
test<unsigned char>();
|
||||
test<signed char>();
|
||||
test<unsigned long>();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test<unsigned char>());
|
||||
static_assert(test<signed char>());
|
||||
static_assert(test<unsigned long>());
|
||||
#endif
|
||||
|
||||
return 0;
|
@ -28,7 +28,6 @@ int main(int, char**)
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test<std::char_traits<wchar_t>* >();
|
||||
#endif
|
||||
test<std::char_traits<unsigned short>*>();
|
||||
|
||||
test<std::basic_ios<char>* >();
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
|
@ -24,6 +24,32 @@ struct MyChar {
|
||||
char c;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::char_traits<MyChar> {
|
||||
using char_type = MyChar;
|
||||
using int_type = std::char_traits<char>::int_type;
|
||||
using off_type = std::char_traits<char>::off_type;
|
||||
using pos_type = std::char_traits<char>::pos_type;
|
||||
using state_type = std::char_traits<char>::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*, 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();
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
test_library_hash_specializations_available();
|
||||
{
|
||||
|
@ -24,6 +24,32 @@ struct MyChar {
|
||||
char c;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::char_traits<MyChar> {
|
||||
using char_type = MyChar;
|
||||
using int_type = std::char_traits<char>::int_type;
|
||||
using off_type = std::char_traits<char>::off_type;
|
||||
using pos_type = std::char_traits<char>::pos_type;
|
||||
using state_type = std::char_traits<char>::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*, 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();
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
test_library_hash_specializations_available();
|
||||
{
|
||||
|
@ -81,8 +81,10 @@ void test_P0645() {
|
||||
assert_is_formattable<CharT*, CharT>();
|
||||
assert_is_formattable<const CharT*, CharT>();
|
||||
assert_is_formattable<CharT[42], CharT>();
|
||||
assert_is_formattable<std::basic_string<CharT>, CharT>();
|
||||
assert_is_formattable<std::basic_string_view<CharT>, CharT>();
|
||||
if constexpr (!std::same_as<CharT, int>) { // string and string_view only work with proper character types
|
||||
assert_is_formattable<std::basic_string<CharT>, CharT>();
|
||||
assert_is_formattable<std::basic_string_view<CharT>, CharT>();
|
||||
}
|
||||
|
||||
assert_is_formattable<bool, CharT>();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user