diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -320,6 +320,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_expected`` ``202202L`` ------------------------------------------------- ----------------- + ``__cpp_lib_formatters`` *unimplemented* + ------------------------------------------------- ----------------- ``__cpp_lib_forward_like`` ``202207L`` ------------------------------------------------- ----------------- ``__cpp_lib_invoke_r`` ``202106L`` diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -39,6 +39,7 @@ ------------------ - P1328R1 - ``constexpr type_info::operator==()`` +- P1413R3 - Formatting ``thread::id`` (the ``stacktrace`` is not done yet) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx2b.rst b/libcxx/docs/Status/Cxx2b.rst --- a/libcxx/docs/Status/Cxx2b.rst +++ b/libcxx/docs/Status/Cxx2b.rst @@ -42,6 +42,9 @@ .. [#note-P0533R9] P0533R9: ``isfinite``, ``isinf``, ``isnan`` and ``isnormal`` are implemented. .. [#note-P1413R3] P1413R3: ``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but clang doesn't issue a diagnostic for deprecated using template declarations. + .. [#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: diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -113,7 +113,7 @@ "`P2713R1 `__","LWG", "Escaping improvements in ``std::format``","February 2023","","","|format|" "`P2675R1 `__","LWG", "``format``'s width estimation is too approximate and not forward compatible","February 2023","","","|format|" "`P2572R1 `__","LWG", "``std::format`` fill character allowances","February 2023","","","|format|" -"`P2693R1 `__","LWG", "Formatting ``thread::id`` and ``stacktrace``","February 2023","","","|format|" +"`P2693R1 `__","LWG", "Formatting ``thread::id`` and ``stacktrace``","February 2023","|Partial| [#note-P2693R1]_","","|format|" "`P2679R2 `__","LWG", "Fixing ``std::start_lifetime_as`` for arrays","February 2023","","","" "`P2674R1 `__","LWG", "A trait for implicit lifetime types","February 2023","","","" "`P2655R3 `__","LWG", "``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type","February 2023","","","" diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv --- a/libcxx/docs/Status/FormatPaper.csv +++ b/libcxx/docs/Status/FormatPaper.csv @@ -40,5 +40,5 @@ `[format.range.fmtstr] `_,"Formatting for ranges: strings",,Mark de Wever,|In Progress|, `[format.range.fmtstr] `_,"Formatting for ranges: strings",,Mark de Wever,|In Progress|, "`P2693R1 `__","Formatting ``thread::id`` and ``stacktrace``" -`[thread.thread.id] `_,"Formatting ``thread::id``",,Mark de Wever,|In Progress|, +`[thread.thread.id] `_,"Formatting ``thread::id``",,Mark de Wever,|Complete|,Clang 17 `[stacktrace.format] `_,"Formatting ``stacktrace``",A ```` implementation,Mark de Wever,, diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h --- a/libcxx/include/__format/parser_std_format_spec.h +++ b/libcxx/include/__format/parser_std_format_spec.h @@ -142,6 +142,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 { diff --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support --- a/libcxx/include/__threading_support +++ b/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>; diff --git a/libcxx/include/thread b/libcxx/include/thread --- a/libcxx/include/thread +++ b/libcxx/include/thread @@ -64,6 +64,9 @@ basic_ostream& operator<<(basic_ostream& out, thread::id id); +template +struct formatter; + namespace this_thread { @@ -84,9 +87,16 @@ */ #include <__assert> // all public C++ headers provide the assertion handler +#include <__availability> +#include <__concepts/arithmetic.h> #include <__config> #include <__functional/hash.h> #include <__memory/unique_ptr.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 <__mutex_base> #include <__thread/poll_with_backoff.h> #include <__thread/timed_backoff_policy.h> @@ -219,6 +229,46 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) {return __os << __id.__id_;} +#if _LIBCPP_STD_VER > 20 +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT 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. + + using _Tp = decltype(__get_underlying_id(__id)); + + if constexpr (integral<_Tp>) + return __formatter::__format_integer( + __get_underlying_id(__id), __ctx, __parser_.__get_parsed_std_specifications(__ctx)); +# if 0 + // This alternative is disabled on purpose. Without a platform using + // pointers it's not possible to properly verify the output is correct. + else if constexpr (is_pointer_v<_Tp>) + return __formatter::__format_integer( + reinterpret_cast(__get_underlying_id(__id)), + __ctx, + __parser_.__get_parsed_std_specifications(__ctx)); +# endif + else + // TODO FMT use static_assert(false, ...); + static_assert(sizeof(_CharT) == 0, "unsupported thread::id type, please file a bug report"); + } + + __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right}; +}; +#endif // _LIBCPP_STD_VER + class _LIBCPP_TYPE_VIS thread { __libcpp_thread_t __t_; diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -85,6 +85,7 @@ __cpp_lib_expected 202202L __cpp_lib_filesystem 201703L __cpp_lib_format 202106L +__cpp_lib_formatters 202302L __cpp_lib_forward_like 202207L __cpp_lib_gcd_lcm 201606L __cpp_lib_generic_associative_lookup 201304L @@ -394,6 +395,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 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/thread.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/thread.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/thread.version.compile.pass.cpp +++ b/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 -/* Constant Value - __cpp_lib_jthread 201911L [C++20] +/* Constant Value + __cpp_lib_formatters 202302L [C++2b] + __cpp_lib_jthread 201911L [C++20] */ #include @@ -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" diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/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] @@ -429,6 +430,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 @@ -1076,6 +1081,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 @@ -1837,6 +1846,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 @@ -2877,6 +2890,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 @@ -4103,6 +4120,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 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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.format.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// 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 + +// This test requires the dylib support introduced in D92214. +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}} +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}} + +// + +// template +// struct formatter; + +// template +// string format(format_string fmt, Args&&... args); +// template +// wstring format(wformat_string fmt, Args&&... args); + +#include +#include + +#include "assert_macros.h" +#include "concat_macros.h" +#include "format.functions.tests.h" +#include "test_format_string.h" +#include "test_macros.h" + +auto test = []( + std::basic_string_view expected, test_format_string fmt, Args&&... args) { + std::basic_string out = std::format(fmt, std::forward(args)...); + TEST_REQUIRE(out == expected, + TEST_WRITE_CONCATENATED( + "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n')); +}; + +auto test_exception = [](std::string_view, std::basic_string_view, Args&&...) { + // After P2216 most exceptions thrown by std::format become ill-formed. + // Therefore this tests does nothing. +}; + +int main(int, char**) { + format_tests(test, test_exception); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + format_tests(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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.tests.h @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// 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 + +#include "format.functions.common.h" +#include "test_macros.h" + +template +void format_test_integral(TestFunction check, ExceptionTest check_exception, auto&& input) { + 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); + + check(SV(" 0"), SV("{:{}}"), input, 5); + check(SV("0****"), SV("{:*<{}}"), input, 5); + check(SV("__0__"), SV("{:_^{}}"), input, 5); + check(SV("::::0"), SV("{::>{}}"), input, 5); // This is not a range, so : is allowed as fill character. + + 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 fmt : fmt_invalid_types("")) + check_exception("The replacement field misses a terminating '}'", fmt, input); +} + +template +void format_tests(TestFunction check, ExceptionTest check_exception) { + // note it is not guaranteed a thread::id is an integral, for other types + // different formatting results may occur, format needs to do the same as + // the stream operator. + format_test_integral(check, check_exception, std::thread::id()); +} + +#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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.functions.vformat.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// 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: libcpp-has-no-incomplete-format + +// TODO FMT Fix this test using GCC, it currently times out. +// UNSUPPORTED: gcc-12 + +// This test requires the dylib support introduced in D92214. +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}} +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}} + +// + +// template +// struct formatter; + +// string vformat(string_view fmt, format_args args); +// wstring vformat(wstring_view fmt, wformat_args args); + +#include +#include + +#include "assert_macros.h" +#include "concat_macros.h" +#include "format.functions.tests.h" +#include "test_macros.h" + +auto test = []( + std::basic_string_view expected, std::basic_string_view fmt, Args&&... args) { + std::basic_string out = std::vformat(fmt, std::make_format_args>(args...)); + TEST_REQUIRE(out == expected, + TEST_WRITE_CONCATENATED( + "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n')); +}; + +auto test_exception = + []( + [[maybe_unused]] std::string_view what, + [[maybe_unused]] std::basic_string_view 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>(args...))); + }; + +int main(int, char**) { + format_tests(test, test_exception); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + format_tests(test, 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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// 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: libcpp-has-no-incomplete-format + +// TODO FMT Fix this test using GCC, it currently times out. +// UNSUPPORTED: gcc-12 + +// This test requires the dylib support introduced in D92214. +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}} +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}} + +// + +// template +// struct formatter; + +// template +// 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 +#include +#include + +#include "test_format_context.h" +#include "test_macros.h" +#include "make_string.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +void test_format(StringViewT expected, std::thread::id arg) { + using CharT = typename StringViewT::value_type; + using String = std::basic_string; + using OutIt = std::back_insert_iterator; + using FormatCtxT = std::basic_format_context; + + const std::formatter formatter; + + String result; + OutIt out = std::back_inserter(result); + FormatCtxT format_ctx = test_format_context_create(out, std::make_format_args(arg)); + formatter.format(arg, format_ctx); + assert(result == expected); +} + +template +void test_fmt() { + test_format(SV("0"), std::thread::id()); +} + +void test() { + test_fmt(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_fmt(); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/parse.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/parse.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/parse.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// 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 + +// This test requires the dylib support introduced in D92214. +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}} +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}} + +// + +// template +// struct formatter; + +// template +// 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 +#include +#include + +#include "test_format_context.h" +#include "test_macros.h" +#include "make_string.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +constexpr void test_parse(StringViewT fmt) { + using CharT = typename StringViewT::value_type; + auto parse_ctx = std::basic_format_parse_context(fmt); + std::formatter formatter; + static_assert(std::semiregular); + + std::same_as auto it = formatter.parse(parse_ctx); + assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}')); +} + +template +constexpr void test_fmt() { + test_parse(SV("")); + test_parse(SV("1")); + + test_parse(SV("}")); + test_parse(SV("1}")); +} + +constexpr bool test() { + test_fmt(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_fmt(); +#endif + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} 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 --- 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 @@ -18,16 +18,36 @@ // operator<<(basic_ostream& out, thread::id id); #include +#include #include #include +#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 +static void test() { + std::thread::id id0 = std::this_thread::get_id(); + std::basic_ostringstream 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 + // text representation for charT + // this definition is used for both streaming and formatting. + // + // Test whether the output is identical. + std::basic_string s = std::format(MAKE_STRING_VIEW(CharT, "{}"), id0); + assert(s == os.str()); +#endif +} + +int main(int, char**) { + test(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif return 0; } 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 --- 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 @@ -174,7 +174,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 void test_P1636() { assert_is_not_formattable, CharT>(); @@ -190,7 +191,7 @@ assert_is_not_formattable, CharT>(); #endif #ifndef TEST_HAS_NO_THREADS - assert_is_not_formattable(); + assert_is_formattable(); #endif assert_is_not_formattable, CharT>(); } diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -329,6 +329,13 @@ "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_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 },