[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