[libcxx-commits] [libcxx] [libc++] Use std::to_chars to format thread::id and canonicalize the representation across platforms (PR #181624)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Mar 16 04:13:57 PDT 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/181624
>From 1a234983a62c98fd50cc522ff4010a06a1eb8297 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 16 Feb 2026 11:40:25 +0100
Subject: [PATCH] [libc++] Use std::to_string to format thread::id
---
libcxx/docs/ReleaseNotes/23.rst | 3 +
libcxx/include/__thread/formatter.h | 9 +-
libcxx/include/__thread/thread.h | 28 +++---
libcxx/include/future | 5 +
libcxx/include/module.modulemap.in | 5 +-
libcxx/include/thread | 5 +
.../format.functions.pass.cpp | 94 +++++++++++++++++++
.../test/libcxx/transitive_includes/cxx26.csv | 13 ---
.../format.functions.format.pass.cpp | 57 -----------
.../thread.thread.id/format.functions.tests.h | 83 ----------------
.../format.functions.vformat.pass.cpp | 48 +++++++---
.../thread.thread.id/format.pass.cpp | 16 ++--
.../thread.thread.id/stream.pass.cpp | 3 +-
13 files changed, 175 insertions(+), 194 deletions(-)
create mode 100644 libcxx/test/libcxx/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.pass.cpp
delete mode 100644 libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.format.pass.cpp
delete mode 100644 libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.tests.h
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index 4441a8aed198c..5abb20d1fd78d 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -61,6 +61,9 @@ Deprecations and Removals
Potentially breaking changes
----------------------------
+- The output of ``ostream << std::thread::id`` and ``std::format("...", std::thread:id)`` changes on some platforms from
+ hexadecimal to decimal. This is done to have consistent formatting across all platforms libc++ supports.
+
Announcements About Future Releases
-----------------------------------
diff --git a/libcxx/include/__thread/formatter.h b/libcxx/include/__thread/formatter.h
index 826607d47b469..9682798e1df41 100644
--- a/libcxx/include/__thread/formatter.h
+++ b/libcxx/include/__thread/formatter.h
@@ -51,20 +51,13 @@ struct formatter<__thread_id, _CharT> {
// On Linux systems pthread_t is an unsigned long long.
// On Apple systems pthread_t is a pointer type.
//
- // Note the output should match what the stream operator does. Since
- // the ostream operator has been shipped years before this formatter
- // was added to the Standard, this formatter does what the stream
- // operator does. This may require platform specific changes.
+ // Note the output should match what the stream operator does.
using _Tp = decltype(__get_underlying_id(__id));
using _Cp = conditional_t<integral<_Tp>, _Tp, conditional_t<is_pointer_v<_Tp>, uintptr_t, void>>;
static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
__format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
- if constexpr (is_pointer_v<_Tp>) {
- __specs.__std_.__alternate_form_ = true;
- __specs.__std_.__type_ = __format_spec::__type::__hexadecimal_lower_case;
- }
return __formatter::__format_integer(reinterpret_cast<_Cp>(__get_underlying_id(__id)), __ctx, __specs);
}
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index b2f51aa816c10..516b4833fb925 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -11,12 +11,13 @@
#define _LIBCPP___THREAD_THREAD_H
#include <__assert>
+#include <__charconv/to_chars_integral.h>
#include <__condition_variable/condition_variable.h>
#include <__config>
#include <__exception/terminate.h>
#include <__functional/hash.h>
#include <__functional/unary_function.h>
-#include <__locale>
+#include <__fwd/ostream.h>
#include <__memory/addressof.h>
#include <__memory/unique_ptr.h>
#include <__mutex/mutex.h>
@@ -27,15 +28,14 @@
#include <__type_traits/enable_if.h>
#include <__type_traits/invoke.h>
#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_pointer.h>
#include <__type_traits/is_same.h>
#include <__type_traits/remove_cvref.h>
#include <__utility/forward.h>
+#include <cstdint>
+#include <limits>
#include <tuple>
-#if _LIBCPP_HAS_LOCALIZATION
-# include <sstream>
-#endif
-
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
@@ -144,13 +144,19 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) {
//
// Since various flags in the output stream can affect how the
// thread id is represented (e.g. numpunct or showbase), we
- // use a temporary stream instead and just output the thread
- // id representation as a string.
+ // use `to_chars` directly and output the id as a string.
+
+ static_assert(is_pointer<__libcpp_thread_id>::value || is_integral<__libcpp_thread_id>::value);
+
+ using __int_type = __conditional_t<is_pointer<__libcpp_thread_id>::value, uintptr_t, __libcpp_thread_id>;
- basic_ostringstream<_CharT, _Traits> __sstr;
- __sstr.imbue(locale::classic());
- __sstr << __id.__id_;
- return __os << __sstr.str();
+ static const size_t __buffer_size = numeric_limits<__int_type>::digits10 + 2;
+ char __buffer[__buffer_size];
+ auto __ret =
+ std::__to_chars_integral(__buffer, __buffer + __buffer_size - 1, reinterpret_cast<__int_type>(__id.__id_), 10);
+ _LIBCPP_ASSERT_INTERNAL(__ret.__ec == std::errc(), "to_chars failed!");
+ *__ret.__ptr = '\0';
+ return __os << __buffer;
}
# endif // _LIBCPP_HAS_LOCALIZATION
diff --git a/libcxx/include/future b/libcxx/include/future
index 6bd836afa04e8..17e84096fe160 100644
--- a/libcxx/include/future
+++ b/libcxx/include/future
@@ -2075,6 +2075,11 @@ _LIBCPP_POP_MACROS
# include <system_error>
# include <thread>
# endif
+
+# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23
+# include <sstream>
+# endif
+
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
#endif // _LIBCPP_FUTURE
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index d6e8289b7c8b0..1548121556ec9 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -948,7 +948,10 @@ module std [system] {
header "__charconv/to_chars_integral.h"
export std.charconv.to_chars_result
}
- module to_chars_result { header "__charconv/to_chars_result.h" }
+ module to_chars_result {
+ header "__charconv/to_chars_result.h"
+ export std.system_error.errc
+ }
module traits { header "__charconv/traits.h" }
header "charconv"
diff --git a/libcxx/include/thread b/libcxx/include/thread
index 029ed418e2070..e14e47d02788b 100644
--- a/libcxx/include/thread
+++ b/libcxx/include/thread
@@ -128,6 +128,11 @@ void sleep_for(const chrono::duration<Rep, Period>& rel_time);
# include <system_error>
# include <type_traits>
# endif
+
+# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23
+# include <sstream>
+# endif
+
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
#endif // _LIBCPP_THREAD
diff --git a/libcxx/test/libcxx/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.pass.cpp b/libcxx/test/libcxx/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.pass.cpp
new file mode 100644
index 0000000000000..6719ec6b783e6
--- /dev/null
+++ b/libcxx/test/libcxx/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.pass.cpp
@@ -0,0 +1,94 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: no-threads
+
+// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+
+// TODO FMT This test should not require std::to_chars(floating-point)
+// XFAIL: availability-fp_to_chars-missing
+
+// <thread>
+
+// template<class charT>
+// struct formatter<thread::id, charT>;
+
+// template<class... Args>
+// string format(format_string<Args...> fmt, Args&&... args);
+// template<class... Args>
+// wstring format(wformat_string<Args...> fmt, Args&&... args);
+
+#include <cassert>
+#include <format>
+#include <thread>
+
+#include "assert_macros.h"
+#include "concat_macros.h"
+#include "format.functions.common.h"
+#include "test_format_string.h"
+#include "test_macros.h"
+
+template <class CharT, class TestFunction>
+void format_tests(TestFunction check) {
+ // Note the output of std::thread::id is unspecified. The output text is the
+ // same as the stream operator. Since that format is already released this
+ // test follows the practice on existing systems.
+ std::thread::id input{};
+
+ /***** Test the type specific part *****/
+ check(SV("0"), SV("{}"), input);
+ check(SV("0^42"), SV("{}^42"), input);
+ check(SV("0^42"), SV("{:}^42"), input);
+
+ // *** align-fill & width ***
+ check(SV(" 0"), SV("{:5}"), input);
+ check(SV("0****"), SV("{:*<5}"), input);
+ check(SV("__0__"), SV("{:_^5}"), input);
+ check(SV("::::0"), SV("{::>5}"), input); // This is not a range, so : is allowed as fill character.
+
+ check(SV(" 0"), SV("{:{}}"), input, 5);
+ check(SV("0****"), SV("{:*<{}}"), input, 5);
+ check(SV("__0__"), SV("{:_^{}}"), input, 5);
+ check(SV("####0"), SV("{:#>{}}"), input, 5);
+}
+
+auto test = []<class CharT, class... Args>(
+ std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
+ {
+ std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
+ TEST_REQUIRE(out == expected,
+ TEST_WRITE_CONCATENATED(
+ "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
+ }
+ {
+ std::basic_string<CharT> out = std::vformat(fmt.get(), std::make_format_args<context_t<CharT>>(args...));
+ TEST_REQUIRE(out == expected,
+ TEST_WRITE_CONCATENATED(
+ "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
+ }
+};
+
+int main(int, char**) {
+ format_tests<char>(test);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ format_tests<wchar_t>(test);
+#endif
+
+ { // Check that we print the ID correctly (i.e. library-internal round-tripping works)
+ auto thread_id = std::this_thread::get_id();
+ auto result = std::format("{}", thread_id);
+ auto num = std::stoull(result);
+ using int_t =
+ std::conditional_t<std::is_pointer<std::__libcpp_thread_id>::value, uintptr_t, std::__libcpp_thread_id>;
+ assert(reinterpret_cast<int_t>(__get_underlying_id(std::this_thread::get_id())) == static_cast<int_t>(num));
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 253cf64703076..d130d6daa89f9 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -424,29 +424,21 @@ functional tuple
functional typeinfo
functional unordered_map
functional version
-future bitset
future cctype
future cerrno
future climits
-future clocale
future compare
-future cstddef
future cstdint
future cstdio
-future cstdlib
future cstring
future ctime
future cwchar
future cwctype
future initializer_list
-future ios
future iosfwd
-future istream
future limits
future ratio
-future sstream
future stdexcept
-future streambuf
future string
future string_view
future tuple
@@ -1037,7 +1029,6 @@ system_error tuple
system_error version
thread array
thread atomic
-thread bitset
thread cctype
thread cerrno
thread climits
@@ -1052,14 +1043,10 @@ thread ctime
thread cwchar
thread cwctype
thread initializer_list
-thread ios
thread iosfwd
-thread istream
thread limits
thread ratio
-thread sstream
thread stdexcept
-thread streambuf
thread string
thread string_view
thread tuple
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.format.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.format.pass.cpp
deleted file mode 100644
index 5618836d89e80..0000000000000
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.format.pass.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// UNSUPPORTED: no-threads
-
-// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
-
-// TODO FMT This test should not require std::to_chars(floating-point)
-// XFAIL: availability-fp_to_chars-missing
-
-// <thread>
-
-// template<class charT>
-// struct formatter<thread::id, charT>;
-
-// template<class... Args>
-// string format(format_string<Args...> fmt, Args&&... args);
-// template<class... Args>
-// wstring format(wformat_string<Args...> fmt, Args&&... args);
-
-#include <format>
-#include <cassert>
-
-#include "assert_macros.h"
-#include "concat_macros.h"
-#include "format.functions.tests.h"
-#include "test_format_string.h"
-#include "test_macros.h"
-
-auto test = []<class CharT, class... Args>(
- std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
- std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
- TEST_REQUIRE(out == expected,
- TEST_WRITE_CONCATENATED(
- "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
-};
-
-auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, Args&&...) {
- // After P2216 most exceptions thrown by std::format become ill-formed.
- // Therefore this tests does nothing.
-};
-
-int main(int, char**) {
- format_tests<char>(test, test_exception);
-
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- format_tests<wchar_t>(test, test_exception);
-#endif
-
- return 0;
-}
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.tests.h b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.tests.h
deleted file mode 100644
index f55f0e2af8cb2..0000000000000
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.tests.h
+++ /dev/null
@@ -1,83 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef TEST_STD_THREAD_THREAD_THREADS_THREAD_THREAD_CLASS_THREAD_THREAD_ID_FORMAT_FUNCTIONS_TESTS_H
-#define TEST_STD_THREAD_THREAD_THREADS_THREAD_THREAD_CLASS_THREAD_THREAD_ID_FORMAT_FUNCTIONS_TESTS_H
-
-#include <thread>
-
-#include "format.functions.common.h"
-#include "test_macros.h"
-
-template <class CharT, class TestFunction, class ExceptionTest>
-void format_tests(TestFunction check, ExceptionTest check_exception) {
- // Note the output of std::thread::id is unspecified. The output text is the
- // same as the stream operator. Since that format is already released this
- // test follows the practice on existing systems.
- std::thread::id input{};
-
- /***** Test the type specific part *****/
-#if !defined(__APPLE__) && !defined(__FreeBSD__)
- check(SV("0"), SV("{}"), input);
- check(SV("0^42"), SV("{}^42"), input);
- check(SV("0^42"), SV("{:}^42"), input);
-
- // *** align-fill & width ***
- check(SV(" 0"), SV("{:5}"), input);
- check(SV("0****"), SV("{:*<5}"), input);
- check(SV("__0__"), SV("{:_^5}"), input);
- check(SV("::::0"), SV("{::>5}"), input); // This is not a range, so : is allowed as fill character.
-
- check(SV(" 0"), SV("{:{}}"), input, 5);
- check(SV("0****"), SV("{:*<{}}"), input, 5);
- check(SV("__0__"), SV("{:_^{}}"), input, 5);
- check(SV("####0"), SV("{:#>{}}"), input, 5);
-#else // !defined(__APPLE__) && !defined(__FreeBSD__)
- check(SV("0x0"), SV("{}"), input);
- check(SV("0x0^42"), SV("{}^42"), input);
- check(SV("0x0^42"), SV("{:}^42"), input);
-
- // *** align-fill & width ***
- check(SV(" 0x0"), SV("{:7}"), input);
- check(SV("0x0****"), SV("{:*<7}"), input);
- check(SV("__0x0__"), SV("{:_^7}"), input);
- check(SV("::::0x0"), SV("{::>7}"), input); // This is not a range, so : is allowed as fill character.
-
- check(SV(" 0x0"), SV("{:{}}"), input, 7);
- check(SV("0x0****"), SV("{:*<{}}"), input, 7);
- check(SV("__0x0__"), SV("{:_^{}}"), input, 7);
- check(SV("####0x0"), SV("{:#>{}}"), input, 7);
-#endif // !defined(__APPLE__) && !defined(__FreeBSD__)
-
- /***** Test the type generic part *****/
- check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
- check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
-
- // *** sign ***
- check_exception("The replacement field misses a terminating '}'", SV("{:-}"), input);
- check_exception("The replacement field misses a terminating '}'", SV("{:+}"), input);
- check_exception("The replacement field misses a terminating '}'", SV("{: }"), input);
-
- // *** alternate form ***
- check_exception("The replacement field misses a terminating '}'", SV("{:#}"), input);
-
- // *** zero-padding ***
- check_exception("The width option should not have a leading zero", SV("{:0}"), input);
-
- // *** precision ***
- check_exception("The replacement field misses a terminating '}'", SV("{:.}"), input);
-
- // *** locale-specific form ***
- check_exception("The replacement field misses a terminating '}'", SV("{:L}"), input);
-
- // *** type ***
- for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>(""))
- check_exception("The replacement field misses a terminating '}'", fmt, input);
-}
-
-#endif // TEST_STD_THREAD_THREAD_THREADS_THREAD_THREAD_CLASS_THREAD_THREAD_ID_FORMAT_FUNCTIONS_TESTS_H
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.vformat.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.vformat.pass.cpp
index 8555ebd742616..ffe1330fa9c7a 100644
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.vformat.pass.cpp
+++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.vformat.pass.cpp
@@ -22,21 +22,47 @@
// string vformat(string_view fmt, format_args args);
// wstring vformat(wstring_view fmt, wformat_args args);
-#include <format>
#include <cassert>
+#include <format>
+#include <thread>
#include "assert_macros.h"
#include "concat_macros.h"
-#include "format.functions.tests.h"
+#include "format.functions.common.h"
#include "test_macros.h"
-auto test = []<class CharT, class... Args>(
- std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) {
- std::basic_string<CharT> out = std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...));
- TEST_REQUIRE(out == expected,
- TEST_WRITE_CONCATENATED(
- "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
-};
+template <class CharT, class ExceptionTest>
+void format_tests(ExceptionTest check_exception) {
+ // Note the output of std::thread::id is unspecified. The output text is the
+ // same as the stream operator. Since that format is already released this
+ // test follows the practice on existing systems.
+ std::thread::id input{};
+
+ /***** Test the type generic part *****/
+ check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
+ check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
+
+ // *** sign ***
+ check_exception("The replacement field misses a terminating '}'", SV("{:-}"), input);
+ check_exception("The replacement field misses a terminating '}'", SV("{:+}"), input);
+ check_exception("The replacement field misses a terminating '}'", SV("{: }"), input);
+
+ // *** alternate form ***
+ check_exception("The replacement field misses a terminating '}'", SV("{:#}"), input);
+
+ // *** zero-padding ***
+ check_exception("The width option should not have a leading zero", SV("{:0}"), input);
+
+ // *** precision ***
+ check_exception("The replacement field misses a terminating '}'", SV("{:.}"), input);
+
+ // *** locale-specific form ***
+ check_exception("The replacement field misses a terminating '}'", SV("{:L}"), input);
+
+ // *** type ***
+ for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>(""))
+ check_exception("The replacement field misses a terminating '}'", fmt, input);
+}
auto test_exception =
[]<class CharT, class... Args>(
@@ -55,10 +81,10 @@ auto test_exception =
};
int main(int, char**) {
- format_tests<char>(test, test_exception);
+ format_tests<char>(test_exception);
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- format_tests<wchar_t>(test, test_exception);
+ format_tests<wchar_t>(test_exception);
#endif
return 0;
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp
index 39a257592809d..d3fc6e4b016d6 100644
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp
+++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp
@@ -34,9 +34,8 @@
#define SV(S) MAKE_STRING_VIEW(CharT, S)
-template <class StringViewT>
-void test_format(StringViewT expected, std::thread::id arg) {
- using CharT = typename StringViewT::value_type;
+template <class CharT>
+std::basic_string<CharT> test_format(std::thread::id arg) {
using String = std::basic_string<CharT>;
using OutIt = std::back_insert_iterator<String>;
using FormatCtxT = std::basic_format_context<OutIt, CharT>;
@@ -47,16 +46,15 @@ void test_format(StringViewT expected, std::thread::id arg) {
OutIt out = std::back_inserter(result);
FormatCtxT format_ctx = test_format_context_create<OutIt, CharT>(out, std::make_format_args<FormatCtxT>(arg));
formatter.format(arg, format_ctx);
- assert(result == expected);
+ assert(!result.empty());
+ return result;
}
template <class CharT>
void test_fmt() {
-#if !defined(__APPLE__) && !defined(__FreeBSD__)
- test_format(SV("0"), std::thread::id());
-#else
- test_format(SV("0x0"), std::thread::id());
-#endif
+ auto def = test_format<CharT>(std::thread::id());
+ auto self = test_format<CharT>(std::this_thread::get_id());
+ assert(def != self);
}
void test() {
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/stream.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/stream.pass.cpp
index 97e797f9a8fbb..3d4087918be63 100644
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/stream.pass.cpp
+++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/stream.pass.cpp
@@ -10,7 +10,7 @@
// UNSUPPORTED: no-localization
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
-// REQUIRES: locale.fr_FR.UTF-8
+// REQUIRES-: locale.fr_FR.UTF-8
// TODO FMT This test should not require std::to_chars(floating-point)
// XFAIL: availability-fp_to_chars-missing
@@ -27,6 +27,7 @@
#include <format>
#include <locale>
#include <sstream>
+#include <string>
#include <thread>
#include "make_string.h"
More information about the libcxx-commits
mailing list