Mordante updated this revision to Diff 511705. Mordante marked 2 inline comments as done. Mordante added a comment.
Rebased, addresses review comment, and get a CI run. Herald added a comment. NOTE: Clang-Format Team Automated Review Comment It looks like your clang-format review does not contain any unit tests, please try to ensure all code changes have a unit test (unless this is an `NFC` or refactoring, adding documentation etc..) Add your unit tests in `clang/unittests/Format` and you can build with `ninja FormatTests`. We recommend using the `verifyFormat(xxx)` format of unit tests rather than `EXPECT_EQ` as this will ensure you change is tolerant to random whitespace changes (see FormatTest.cpp as an example) For situations where your change is altering the TokenAnnotator.cpp which can happen if you are trying to improve the annotation phase to ensure we are correctly identifying the type of a token, please add a token annotator test in `TokenAnnotatorTest.cpp` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144331/new/ https://reviews.llvm.org/D144331 Files: libcxx/docs/FeatureTestMacroTable.rst libcxx/docs/ReleaseNotes.rst libcxx/docs/Status/Cxx2b.rst libcxx/docs/Status/Cxx2bPapers.csv libcxx/docs/Status/FormatPaper.csv libcxx/include/__format/parser_std_format_spec.h libcxx/include/__threading_support libcxx/include/thread libcxx/include/version libcxx/test/libcxx/transitive_includes/cxx03.csv libcxx/test/libcxx/transitive_includes/cxx11.csv libcxx/test/libcxx/transitive_includes/cxx14.csv libcxx/test/libcxx/transitive_includes/cxx17.csv libcxx/test/libcxx/transitive_includes/cxx20.csv libcxx/test/libcxx/transitive_includes/cxx2b.csv libcxx/test/std/language.support/support.limits/support.limits.general/thread.version.compile.pass.cpp libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.format.pass.cpp libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.tests.h libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.vformat.pass.cpp libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/parse.pass.cpp libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/stream.pass.cpp libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp libcxx/utils/generate_feature_test_macro_components.py
Index: libcxx/utils/generate_feature_test_macro_components.py =================================================================== --- libcxx/utils/generate_feature_test_macro_components.py +++ libcxx/utils/generate_feature_test_macro_components.py @@ -327,6 +327,13 @@ "test_suite_guard": "!defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)", "libcxx_guard": "!defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)", "unimplemented": True, + }, { + "name": "__cpp_lib_formatters", + "values": { "c++2b": 202302 }, + "headers": ["stacktrace", "thread"], + "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)", + "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)", + "unimplemented": True, }, { "name": "__cpp_lib_forward_like", "values": { "c++2b": 202207 }, Index: libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp =================================================================== --- libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp +++ libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp @@ -175,7 +175,8 @@ // Tests for P1636 Formatters for library types // // The paper hasn't been voted in so currently all formatters are disabled. -// TODO validate whether the test is correct after the paper has been accepted. +// Note the paper has been abandoned, the types are kept since other papers may +// introduce these formatters. template <class CharT> void test_P1636() { assert_is_not_formattable<std::basic_streambuf<CharT>, CharT>(); @@ -191,7 +192,7 @@ assert_is_not_formattable<std::sub_match<CharT*>, CharT>(); #endif #ifndef TEST_HAS_NO_THREADS - assert_is_not_formattable<std::thread::id, CharT>(); + assert_is_formattable<std::thread::id, CharT>(); #endif assert_is_not_formattable<std::unique_ptr<int>, CharT>(); } Index: libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/stream.pass.cpp =================================================================== --- libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/stream.pass.cpp +++ libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/stream.pass.cpp @@ -18,16 +18,38 @@ // operator<<(basic_ostream<charT, traits>& out, thread::id id); #include <thread> +#include <format> #include <sstream> #include <cassert> +#include "make_string.h" #include "test_macros.h" -int main(int, char**) -{ - std::thread::id id0 = std::this_thread::get_id(); - std::ostringstream os; - os << id0; +template <class CharT> +static void test() { + std::thread::id id0 = std::this_thread::get_id(); + std::basic_ostringstream<CharT> os; + os << id0; + +#if TEST_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) + // C++23 added a formatter specialization for thread::id. + // This changed the requirement of ostream to have a + // [thread.thread.id]/2 + // The text representation for the character type charT of an object of + // type threadâ::âid is an unspecified sequence of charT ... + // This definition is used for both streaming and formatting. + // + // Test whether the output is identical. + std::basic_string<CharT> s = std::format(MAKE_STRING_VIEW(CharT, "{}"), id0); + assert(s == os.str()); +#endif +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif return 0; } Index: libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/parse.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/parse.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// 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: libcpp-has-no-incomplete-format + +// TODO FMT Fix this test using GCC, it currently times out. +// UNSUPPORTED: gcc-12 + +// <thread> + +// template<class charT> +// struct formatter<thread::id, charT>; + +// template<class ParseContext> +// constexpr typename ParseContext::iterator +// parse(ParseContext& ctx); + +// Note this tests the basics of this function. It's tested in more detail in +// the format functions test. + +#include <cassert> +#include <concepts> +#include <thread> + +#include "test_format_context.h" +#include "test_macros.h" +#include "make_string.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template <class StringViewT> +constexpr void test_parse(StringViewT fmt) { + using CharT = typename StringViewT::value_type; + auto parse_ctx = std::basic_format_parse_context<CharT>(fmt); + std::formatter<std::thread::id, CharT> formatter; + static_assert(std::semiregular<decltype(formatter)>); + + std::same_as<typename StringViewT::iterator> auto it = formatter.parse(parse_ctx); + assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}')); +} + +template <class CharT> +constexpr void test_fmt() { + test_parse(SV("")); + test_parse(SV("1")); + + test_parse(SV("}")); + test_parse(SV("1}")); +} + +constexpr bool test() { + test_fmt<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_fmt<wchar_t>(); +#endif + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} Index: libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// 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: libcpp-has-no-incomplete-format + +// TODO FMT Fix this test using GCC, it currently times out. +// UNSUPPORTED: gcc-12 + +// <thread> + +// template<class charT> +// struct formatter<thread::id, charT>; + +// template<class FormatContext> +// typename FormatContext::iterator +// format(const T& r, FormatContext& ctx) const; + +// Note this tests the basics of this function. It's tested in more detail in +// the format functions test. + +#include <cassert> +#include <concepts> +#include <thread> + +#include "test_format_context.h" +#include "test_macros.h" +#include "make_string.h" + +#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; + using String = std::basic_string<CharT>; + using OutIt = std::back_insert_iterator<String>; + using FormatCtxT = std::basic_format_context<OutIt, CharT>; + + const std::formatter<std::thread::id, CharT> formatter; + + String result; + 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); +} + +template <class CharT> +void test_fmt() { +#ifndef __APPLE__ + test_format(SV("0"), std::thread::id()); +#else + test_format(SV("0x0"), std::thread::id()); +#endif +} + +void test() { + test_fmt<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_fmt<wchar_t>(); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} Index: libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.vformat.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.vformat.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// 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: libcpp-has-no-incomplete-format + +// TODO FMT Fix this test using GCC, it currently times out. +// UNSUPPORTED: gcc-12 + +// <thread> + +// template<class charT> +// struct formatter<thread::id, charT>; + +// string vformat(string_view fmt, format_args args); +// wstring vformat(wstring_view fmt, wformat_args args); + +#include <format> +#include <cassert> + +#include "assert_macros.h" +#include "concat_macros.h" +#include "format.functions.tests.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')); +}; + +auto test_exception = + []<class CharT, class... Args>( + [[maybe_unused]] std::string_view what, + [[maybe_unused]] std::basic_string_view<CharT> fmt, + [[maybe_unused]] Args&&... args) { + TEST_VALIDATE_EXCEPTION( + std::format_error, + [&]([[maybe_unused]] const std::format_error& e) { + TEST_LIBCPP_REQUIRE( + e.what() == what, + TEST_WRITE_CONCATENATED( + "\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); + }, + TEST_IGNORE_NODISCARD std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...))); + }; + +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; +} Index: libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.tests.h =================================================================== --- /dev/null +++ libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.tests.h @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// 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 *****/ +#ifndef __APPLE__ + check(SV("0"), SV("{}"), 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 // __APPLE__ + check(SV("0x0"), SV("{}"), 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 // __APPLE__ + + /***** Test the type generic part *****/ + check_exception("The format-spec fill field contains an invalid character", SV("{:}<}"), input); + check_exception("The format-spec fill field contains an invalid character", 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("A format-spec width field shouldn't 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 Index: libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.format.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.format.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// 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: libcpp-has-no-incomplete-format + +// TODO FMT Fix this test using GCC, it currently times out. +// UNSUPPORTED: gcc-12 + +// <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; +} Index: libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp =================================================================== --- libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -79,6 +79,7 @@ __cpp_lib_expected 202202L [C++2b] __cpp_lib_filesystem 201703L [C++17] __cpp_lib_format 202106L [C++20] + __cpp_lib_formatters 202302L [C++2b] __cpp_lib_forward_like 202207L [C++2b] __cpp_lib_gcd_lcm 201606L [C++17] __cpp_lib_generic_associative_lookup 201304L [C++14] @@ -431,6 +432,10 @@ # error "__cpp_lib_format should not be defined before c++20" # endif +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined before c++2b" +# endif + # ifdef __cpp_lib_forward_like # error "__cpp_lib_forward_like should not be defined before c++2b" # endif @@ -1086,6 +1091,10 @@ # error "__cpp_lib_format should not be defined before c++20" # endif +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined before c++2b" +# endif + # ifdef __cpp_lib_forward_like # error "__cpp_lib_forward_like should not be defined before c++2b" # endif @@ -1855,6 +1864,10 @@ # error "__cpp_lib_format should not be defined before c++20" # endif +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined before c++2b" +# endif + # ifdef __cpp_lib_forward_like # error "__cpp_lib_forward_like should not be defined before c++2b" # endif @@ -2903,6 +2916,10 @@ # endif # endif +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined before c++2b" +# endif + # ifdef __cpp_lib_forward_like # error "__cpp_lib_forward_like should not be defined before c++2b" # endif @@ -4140,6 +4157,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_formatters +# error "__cpp_lib_formatters should be defined in c++2b" +# endif +# if __cpp_lib_formatters != 202302L +# error "__cpp_lib_formatters should have the value 202302L in c++2b" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_forward_like # error "__cpp_lib_forward_like should be defined in c++2b" # endif Index: libcxx/test/std/language.support/support.limits/support.limits.general/thread.version.compile.pass.cpp =================================================================== --- libcxx/test/std/language.support/support.limits/support.limits.general/thread.version.compile.pass.cpp +++ libcxx/test/std/language.support/support.limits/support.limits.general/thread.version.compile.pass.cpp @@ -17,8 +17,9 @@ // Test the feature test macros defined by <thread> -/* Constant Value - __cpp_lib_jthread 201911L [C++20] +/* Constant Value + __cpp_lib_formatters 202302L [C++2b] + __cpp_lib_jthread 201911L [C++20] */ #include <thread> @@ -26,24 +27,40 @@ #if TEST_STD_VER < 14 +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined before c++2b" +# endif + # ifdef __cpp_lib_jthread # error "__cpp_lib_jthread should not be defined before c++20" # endif #elif TEST_STD_VER == 14 +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined before c++2b" +# endif + # ifdef __cpp_lib_jthread # error "__cpp_lib_jthread should not be defined before c++20" # endif #elif TEST_STD_VER == 17 +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined before c++2b" +# endif + # ifdef __cpp_lib_jthread # error "__cpp_lib_jthread should not be defined before c++20" # endif #elif TEST_STD_VER == 20 +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined before c++2b" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_jthread # error "__cpp_lib_jthread should be defined in c++20" @@ -59,6 +76,19 @@ #elif TEST_STD_VER > 20 +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_formatters +# error "__cpp_lib_formatters should be defined in c++2b" +# endif +# if __cpp_lib_formatters != 202302L +# error "__cpp_lib_formatters should have the value 202302L in c++2b" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_formatters +# error "__cpp_lib_formatters should not be defined because it is unimplemented in libc++!" +# endif +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_jthread # error "__cpp_lib_jthread should be defined in c++2b" Index: libcxx/test/libcxx/transitive_includes/cxx2b.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx2b.csv +++ libcxx/test/libcxx/transitive_includes/cxx2b.csv @@ -584,14 +584,32 @@ system_error stdexcept system_error string system_error version +thread array +thread charconv thread compare thread cstddef +<<<<<<< HEAD thread ctime thread iosfwd thread limits thread ratio thread system_error thread tuple +======= +thread cstdint +thread cstdlib +thread initializer_list +thread iosfwd +thread limits +thread locale +thread stdexcept +thread string +thread string_view +thread system_error +thread tuple +thread type_traits +thread vector +>>>>>>> 824b22b7f148 ([libc++][format] Implements formatter thread::id.) thread version tuple compare tuple cstddef Index: libcxx/test/libcxx/transitive_includes/cxx20.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx20.csv +++ libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -838,19 +838,26 @@ system_error string system_error type_traits system_error version +thread array thread compare thread cstddef thread cstdint +thread cstdlib thread cstring thread ctime thread functional thread iosfwd thread limits +thread locale thread new thread ratio +thread stdexcept +thread string +thread string_view thread system_error thread tuple thread type_traits +thread vector thread version tuple compare tuple cstddef Index: libcxx/test/libcxx/transitive_includes/cxx17.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx17.csv +++ libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -832,6 +832,7 @@ system_error string system_error type_traits system_error version +thread array thread chrono thread compare thread cstddef @@ -841,11 +842,15 @@ thread functional thread iosfwd thread limits +thread locale thread new thread ratio +thread string +thread string_view thread system_error thread tuple thread type_traits +thread vector thread version tuple compare tuple cstddef Index: libcxx/test/libcxx/transitive_includes/cxx14.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx14.csv +++ libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -832,6 +832,7 @@ system_error string system_error type_traits system_error version +thread array thread chrono thread compare thread cstddef @@ -841,11 +842,15 @@ thread functional thread iosfwd thread limits +thread locale thread new thread ratio +thread string +thread string_view thread system_error thread tuple thread type_traits +thread vector thread version tuple compare tuple cstddef Index: libcxx/test/libcxx/transitive_includes/cxx11.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx11.csv +++ libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -830,6 +830,7 @@ system_error string system_error type_traits system_error version +thread array thread chrono thread compare thread cstddef @@ -839,11 +840,15 @@ thread functional thread iosfwd thread limits +thread locale thread new thread ratio +thread string +thread string_view thread system_error thread tuple thread type_traits +thread vector thread version tuple compare tuple cstddef Index: libcxx/test/libcxx/transitive_includes/cxx03.csv =================================================================== --- libcxx/test/libcxx/transitive_includes/cxx03.csv +++ libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -829,6 +829,7 @@ system_error string system_error type_traits system_error version +thread array thread chrono thread compare thread cstddef @@ -838,11 +839,15 @@ thread functional thread iosfwd thread limits +thread locale thread new thread ratio +thread string +thread string_view thread system_error thread tuple thread type_traits +thread vector thread version tuple compare tuple cstddef Index: libcxx/include/version =================================================================== --- libcxx/include/version +++ libcxx/include/version @@ -85,6 +85,7 @@ __cpp_lib_expected 202202L <expected> __cpp_lib_filesystem 201703L <filesystem> __cpp_lib_format 202106L <format> +__cpp_lib_formatters 202302L <stacktrace> <thread> __cpp_lib_forward_like 202207L <utility> __cpp_lib_gcd_lcm 201606L <numeric> __cpp_lib_generic_associative_lookup 201304L <map> <set> @@ -397,6 +398,9 @@ # define __cpp_lib_constexpr_memory 202202L # define __cpp_lib_constexpr_typeinfo 202106L # define __cpp_lib_expected 202202L +# if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) +// # define __cpp_lib_formatters 202302L +# endif # define __cpp_lib_forward_like 202207L # define __cpp_lib_invoke_r 202106L # define __cpp_lib_is_scoped_enum 202011L Index: libcxx/include/thread =================================================================== --- libcxx/include/thread +++ libcxx/include/thread @@ -64,6 +64,9 @@ basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& out, thread::id id); +template<class charT> +struct formatter<thread::id, charT>; + namespace this_thread { @@ -84,11 +87,18 @@ */ #include <__assert> // all public C++ headers provide the assertion handler +#include <__availability> #include <__chrono/steady_clock.h> #include <__chrono/time_point.h> +#include <__concepts/arithmetic.h> #include <__condition_variable/condition_variable.h> #include <__config> #include <__exception/terminate.h> +#include <__format/concepts.h> +#include <__format/format_parse_context.h> +#include <__format/formatter.h> +#include <__format/formatter_integral.h> +#include <__format/parser_std_format_spec.h> #include <__functional/hash.h> #include <__memory/addressof.h> #include <__memory/unique_ptr.h> @@ -224,6 +234,45 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) {return __os << __id.__id_;} +#if _LIBCPP_STD_VER >= 23 +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter<__thread_id, _CharT> { + public: + _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) + -> decltype(__parse_ctx.begin()) { + return __parser_.__parse(__parse_ctx, __format_spec::__fields_fill_align_width); + } + + _LIBCPP_HIDE_FROM_ABI auto format(__thread_id __id, auto& __ctx) const -> decltype(__ctx.out()) { + // In __threading_support __libcpp_thread_id is either a + // unsigned long long or a pthread_t. + // + // The type of pthread_t is left unspecified in POSIX so it can be any + // type. The most logical types are an integral or pointer. + // 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. + + 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); + } + + __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right}; +}; +#endif // _LIBCPP_STD_VER >= 23 + class _LIBCPP_TYPE_VIS thread { __libcpp_thread_t __t_; Index: libcxx/include/__threading_support =================================================================== --- libcxx/include/__threading_support +++ libcxx/include/__threading_support @@ -643,6 +643,8 @@ _LIBCPP_INLINE_VISIBILITY __thread_id(__libcpp_thread_id __id) : __id_(__id) {} + _LIBCPP_HIDE_FROM_ABI friend __libcpp_thread_id __get_underlying_id(const __thread_id __id) { return __id.__id_; } + friend __thread_id this_thread::get_id() _NOEXCEPT; friend class _LIBCPP_TYPE_VIS thread; friend struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>; Index: libcxx/include/__format/parser_std_format_spec.h =================================================================== --- libcxx/include/__format/parser_std_format_spec.h +++ libcxx/include/__format/parser_std_format_spec.h @@ -143,6 +143,7 @@ # if _LIBCPP_STD_VER >= 23 inline constexpr __fields __fields_tuple{.__use_range_fill_ = true}; inline constexpr __fields __fields_range{.__use_range_fill_ = true}; +inline constexpr __fields __fields_fill_align_width{}; # endif enum class _LIBCPP_ENUM_VIS __alignment : uint8_t { Index: libcxx/docs/Status/FormatPaper.csv =================================================================== --- libcxx/docs/Status/FormatPaper.csv +++ libcxx/docs/Status/FormatPaper.csv @@ -40,5 +40,5 @@ `[format.range.fmtstr] <https://wg21.link/format.range.fmtstr>`_,"Formatting for ranges: strings",,Mark de Wever,|In Progress|, `[format.range.fmtstr] <https://wg21.link/format.range.fmtstr>`_,"Formatting for ranges: strings",,Mark de Wever,|In Progress|, "`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``" -`[thread.thread.id] <https://wg21.link/thread.thread.id>`_,"Formatting ``thread::id``",,Mark de Wever,|In Progress|, +`[thread.thread.id] <https://wg21.link/thread.thread.id>`_,"Formatting ``thread::id``",,Mark de Wever,|Complete|,Clang 17 `[stacktrace.format] <https://wg21.link/stacktrace.format>`_,"Formatting ``stacktrace``",A ``<stacktrace>`` implementation,Mark de Wever,, Index: libcxx/docs/Status/Cxx2bPapers.csv =================================================================== --- libcxx/docs/Status/Cxx2bPapers.csv +++ libcxx/docs/Status/Cxx2bPapers.csv @@ -113,7 +113,7 @@ "`P2713R1 <https://wg21.link/P2713R1>`__","LWG", "Escaping improvements in ``std::format``","February 2023","","","|format|" "`P2675R1 <https://wg21.link/P2675R1>`__","LWG", "``format``'s width estimation is too approximate and not forward compatible","February 2023","","","|format|" "`P2572R1 <https://wg21.link/P2572R1>`__","LWG", "``std::format`` fill character allowances","February 2023","","","|format|" -"`P2693R1 <https://wg21.link/P2693R1>`__","LWG", "Formatting ``thread::id`` and ``stacktrace``","February 2023","","","|format|" +"`P2693R1 <https://wg21.link/P2693R1>`__","LWG", "Formatting ``thread::id`` and ``stacktrace``","February 2023","|Partial| [#note-P2693R1]_","","|format|" "`P2679R2 <https://wg21.link/P2679R2>`__","LWG", "Fixing ``std::start_lifetime_as`` for arrays","February 2023","","","" "`P2674R1 <https://wg21.link/P2674R1>`__","LWG", "A trait for implicit lifetime types","February 2023","","","" "`P2655R3 <https://wg21.link/P2655R3>`__","LWG", "``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type","February 2023","","","" Index: libcxx/docs/Status/Cxx2b.rst =================================================================== --- libcxx/docs/Status/Cxx2b.rst +++ libcxx/docs/Status/Cxx2b.rst @@ -44,6 +44,9 @@ clang doesn't issue a diagnostic for deprecated using template declarations. .. [#note-P2520R0] P2520R0: Libc++ implemented this paper as a DR in C++20 as well. .. [#note-P2711R1] P2711R1: ``join_with_view`` hasn't been done yet since this type isn't implemented yet. + .. [#note-P2693R1] P1413R3: The formatter for ``std::thread::id`` is implemented. + The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is + not implemented yet. .. _issues-status-cxx2b: Index: libcxx/docs/ReleaseNotes.rst =================================================================== --- libcxx/docs/ReleaseNotes.rst +++ libcxx/docs/ReleaseNotes.rst @@ -39,6 +39,7 @@ ------------------ - P2520R0 - ``move_iterator<T*>`` should be a random access iterator - P1328R1 - ``constexpr type_info::operator==()`` +- P1413R3 - Formatting ``thread::id`` (the ``stacktrace`` is not done yet) Improvements and New Features ----------------------------- Index: libcxx/docs/FeatureTestMacroTable.rst =================================================================== --- libcxx/docs/FeatureTestMacroTable.rst +++ libcxx/docs/FeatureTestMacroTable.rst @@ -322,6 +322,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_expected`` ``202202L`` ------------------------------------------------- ----------------- + ``__cpp_lib_formatters`` *unimplemented* + ------------------------------------------------- ----------------- ``__cpp_lib_forward_like`` ``202207L`` ------------------------------------------------- ----------------- ``__cpp_lib_invoke_r`` ``202106L``
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits