[libcxx-commits] [libcxx] 08a0faf - [libc++] Keep char_traits<T> for arbitrary T around until LLVM 18

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Nov 24 05:22:55 PST 2022


Author: Louis Dionne
Date: 2022-11-24T08:22:39-05:00
New Revision: 08a0faf4cd32bce6c51027ea9b5ec351747995b4

URL: https://github.com/llvm/llvm-project/commit/08a0faf4cd32bce6c51027ea9b5ec351747995b4
DIFF: https://github.com/llvm/llvm-project/commit/08a0faf4cd32bce6c51027ea9b5ec351747995b4.diff

LOG: [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

Added: 
    libcxx/test/libcxx/strings/char.traits/char.traits.specializations/arbitrary_char_type.deprecated.verify.cpp
    libcxx/test/libcxx/strings/char.traits/char.traits.specializations/arbitrary_char_type.pass.cpp

Modified: 
    libcxx/docs/ReleaseNotes.rst
    libcxx/include/__string/char_traits.h
    libcxx/test/std/input.output/iostream.forward/iosfwd.pass.cpp
    libcxx/test/std/strings/basic.string.hash/enabled_hashes.pass.cpp
    libcxx/test/std/strings/string.view/string.view.hash/enabled_hashes.pass.cpp
    libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp

Removed: 
    libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.deprecated.verify.cpp
    libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.pass.cpp


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index bbee24334ac93..63d6f29171449 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -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
 -----------

diff  --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index f6ca48d6033d8..617c6c156e961 100644
--- a/libcxx/include/__string/char_traits.h
+++ b/libcxx/include/__string/char_traits.h
@@ -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

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/arbitrary_char_type.deprecated.verify.cpp
similarity index 53%
rename from libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.deprecated.verify.cpp
rename to libcxx/test/libcxx/strings/char.traits/char.traits.specializations/arbitrary_char_type.deprecated.verify.cpp
index a201f6e8cf347..ec6f34ef5462e 100644
--- 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/arbitrary_char_type.deprecated.verify.cpp
@@ -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}}
 }

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/arbitrary_char_type.pass.cpp
similarity index 97%
rename from libcxx/test/libcxx/strings/char.traits/char.traits.specializations/signed_unsigned_char.pass.cpp
rename to libcxx/test/libcxx/strings/char.traits/char.traits.specializations/arbitrary_char_type.pass.cpp
index d67fb9c175333..c2de29d22b2fe 100644
--- 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/arbitrary_char_type.pass.cpp
@@ -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;

diff  --git a/libcxx/test/std/input.output/iostream.forward/iosfwd.pass.cpp b/libcxx/test/std/input.output/iostream.forward/iosfwd.pass.cpp
index b6ef60d967b4e..1a28a5985a011 100644
--- a/libcxx/test/std/input.output/iostream.forward/iosfwd.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.forward/iosfwd.pass.cpp
@@ -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

diff  --git a/libcxx/test/std/strings/basic.string.hash/enabled_hashes.pass.cpp b/libcxx/test/std/strings/basic.string.hash/enabled_hashes.pass.cpp
index f82735862ecd2..f79b0d9162eba 100644
--- a/libcxx/test/std/strings/basic.string.hash/enabled_hashes.pass.cpp
+++ b/libcxx/test/std/strings/basic.string.hash/enabled_hashes.pass.cpp
@@ -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();
   {

diff  --git a/libcxx/test/std/strings/string.view/string.view.hash/enabled_hashes.pass.cpp b/libcxx/test/std/strings/string.view/string.view.hash/enabled_hashes.pass.cpp
index c214ac1363bc0..407823ba43258 100644
--- a/libcxx/test/std/strings/string.view/string.view.hash/enabled_hashes.pass.cpp
+++ b/libcxx/test/std/strings/string.view/string.view.hash/enabled_hashes.pass.cpp
@@ -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();
   {

diff  --git a/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp
index 8f83ad6f771b9..56b6692ac34bb 100644
--- a/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp
@@ -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>();
 


        


More information about the libcxx-commits mailing list