diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -189,4 +189,5 @@ "`3629 `__","``make_error_code`` and ``make_error_condition`` are customization points","Not voted in","|Complete|","16.0","" "`3631 `__","``basic_format_arg(T&&)`` should use ``remove_cvref_t`` throughout","Not voted in","|Complete|","15.0","" "`3645 `__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","Not voted in","|Complete|","14.0","" +"`3636 `__","``formatter::format`` should be ``const``-qualified","Not voted in","|Complete|","16.0","" "","","","","" 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 @@ -28,7 +28,7 @@ `[time.syn] `_,"Formatter ``chrono::local_info``",A ```` implementation,Not assigned,, `[time.syn] `_,"Formatter ``chrono::zoned_time``",A ```` implementation,Not assigned,, `P2286R8 `__,"Formatting ranges" -`[format.syn] `_,"Concept ``formattable``",,Mark de Wever,|In Progress|, +`[format.syn] `_,"Concept ``formattable``",,Mark de Wever,|Complete|, Clang 16 `[format.string.std] `_,"std-format-spec ``type`` debug",,Mark de Wever,|In Progress|, `[format.range] `_,"Formatting for ranges: sequences",,Mark de Wever,|In Progress|, `[format.range] `_,"Formatting for ranges: associative",,Mark de Wever,, diff --git a/libcxx/include/__format/concepts.h b/libcxx/include/__format/concepts.h --- a/libcxx/include/__format/concepts.h +++ b/libcxx/include/__format/concepts.h @@ -41,20 +41,22 @@ template using __fmt_iter_for = _CharT*; -// The concept is based on P2286R6 -// It lacks the const of __cf as required by, the not yet accepted, LWG-3636. -// The current formatters can't be easily adapted, but that is WIP. -// TODO FMT properly implement this concepts once accepted. template -concept __formattable = (semiregular, _CharT>>) && - requires(formatter, _CharT> __f, - formatter, _CharT> __cf, _Tp __t, - basic_format_context<__fmt_iter_for<_CharT>, _CharT> __fc, - basic_format_parse_context<_CharT> __pc) { - { __f.parse(__pc) } -> same_as::iterator>; - { __cf.format(__t, __fc) } -> same_as<__fmt_iter_for<_CharT>>; - }; +concept __formattable = + (semiregular, _CharT>>) && + requires(formatter, _CharT> __f, + const formatter, _CharT> __cf, + _Tp __t, + basic_format_context<__fmt_iter_for<_CharT>, _CharT> __fc, + basic_format_parse_context<_CharT> __pc) { + { __f.parse(__pc) } -> same_as::iterator>; + { __cf.format(__t, __fc) } -> same_as<__fmt_iter_for<_CharT>>; + }; +# if _LIBCPP_STD_VER > 20 +template +concept formattable = __formattable<_Tp, _CharT>; +# endif //_LIBCPP_STD_VER > 20 #endif //_LIBCPP_STD_VER > 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/libcxx/utilities/format/format.formatter/format.formatter.spec/formattable.compile.pass.cpp b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp rename from libcxx/test/libcxx/utilities/format/format.formatter/format.formatter.spec/formattable.compile.pass.cpp rename to libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp --- a/libcxx/test/libcxx/utilities/format/format.formatter/format.formatter.spec/formattable.compile.pass.cpp +++ b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp @@ -5,11 +5,9 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // UNSUPPORTED: libcpp-has-no-incomplete-format -// TODO FMT Move to std after P2286 has been accepted. - // // template @@ -53,7 +51,7 @@ template void assert_is_not_formattable() { - static_assert(!std::__formattable); + static_assert(!std::formattable); } template @@ -66,7 +64,7 @@ || std::same_as #endif ) - static_assert(std::__formattable); + static_assert(std::formattable); else assert_is_not_formattable(); } diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.handle.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.handle.pass.cpp --- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.handle.pass.cpp +++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.handle.pass.cpp @@ -32,7 +32,9 @@ template <> struct std::formatter : std::formatter { - auto format(color c, auto& ctx) { return formatter::format(color_names[static_cast(c)], ctx); } + auto format(color c, auto& ctx) const { + return formatter::format(color_names[static_cast(c)], ctx); + } }; void test(std::string expected, std::string_view fmt, color arg) { diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/types.compile.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/types.compile.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/types.compile.pass.cpp +++ /dev/null @@ -1,383 +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 -// UNSUPPORTED: libcpp-has-no-incomplete-format - -// - -// template -// struct formatter; - -// Tests the enabled and disabled requirements for std::formatter. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test_macros.h" - -#ifndef TEST_HAS_NO_FILESYSTEM_LIBRARY -# include -#endif -#ifndef TEST_HAS_NO_LOCALIZATION -# include -#endif -#ifndef TEST_HAS_NO_THREADS -# include -#endif - -// Validate default template argument. -static_assert(std::same_as, std::formatter>); - -// Concept for an enabled formatter. -// -// Since it's not possible to extract the T and CharT types from the formatter -// they are specified and the proper formatter is always intended to be -// defaulted. -// -// [formatter.requirements]/2 -// A type F meets the Formatter requirements if it meets the BasicFormatter -// requirements and the expressions shown in Table 71 are valid and have the -// indicated semantics. -template > -concept enabled = - // The basic BasicFormatter requirements: - std::default_initializable && std::copyable && std::destructible && std::swappable && - // The expressions shown in Table 71 - requires(F f, std::basic_format_parse_context pc, T u, std::basic_format_context fc) { - { f.parse(pc) } -> std::same_as; - { f.format(u, fc) } -> std::same_as; -}; - -// Concept for a disabled formatter. -// -// This uses the same template arguments as enable. This isn't required since -// the concept doesn't need to inspect T and CharT. This makes it easier for -// future changes. For example P2286 formatting ranges intents to change -// std::formatter> from disabled to enabled. The current way -// makes it easy to define a macro like -// #if TEST_STD_VER > 23 -// TEST_ENABLED_AFTER_CXX23(T, CharT) enabled -// #else -// TEST_ENABLED_AFTER_CXX23(T, CharT) disabled -// #endif -template > -// [formatter.requirements]/5 -// If F is a disabled specialization of formatter, these values are false: -concept disabled = !std::is_default_constructible_v && !std::is_copy_constructible_v && - !std::is_move_constructible_v && !std::is_copy_assignable_v && !std::is_move_assignable_v; - -template -void assert_formatter_is_disabled() { - static_assert(disabled); -} - -template -void assert_formatter_is_enabled() { - // Only formatters for CharT == char || CharT == wchar_t are enabled for the - // standard formatters. When CharT is a different type the formatter should - // be disabled. - if constexpr (std::same_as -#ifndef TEST_HAS_NO_WIDE_CHARACTERS - || std::same_as -#endif - ) - static_assert(enabled); - else - assert_formatter_is_disabled(); -} - -// Tests for P0645 Text Formatting -template -void test_P0645() { -#ifndef TEST_HAS_NO_WIDE_CHARACTERS - // Tests the special formatter that converts a char to a wchar_t. - assert_formatter_is_enabled(); -#endif - assert_formatter_is_enabled(); - - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled, CharT>(); - assert_formatter_is_enabled, CharT>(); - - assert_formatter_is_enabled(); - - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); -#ifndef TEST_HAS_NO_INT128 - assert_formatter_is_enabled<__int128_t, CharT>(); -#endif - - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); -#ifndef TEST_HAS_NO_INT128 - assert_formatter_is_enabled<__uint128_t, CharT>(); -#endif - - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); -} - -// Tests for P1361 Integration of chrono with text formatting -// -// Some tests are commented out since these types haven't been implemented in -// chrono yet. After P1361 has been implemented these formatters should be all -// enabled. -template -void test_P1361() { -// The chrono formatters require localization support. -// [time.format]/7 -// If the chrono-specs is omitted, the chrono object is formatted as if by -// streaming it to std::ostringstream os with the formatting -// locale imbued and copying os.str() through the output iterator of the -// context with additional padding and adjustments as specified by the format -// specifiers. -// In libc++ std:::ostringstream requires localization support. -#ifndef TEST_HAS_NO_LOCALIZATION - - assert_formatter_is_disabled(); - - assert_formatter_is_disabled, CharT>(); - //assert_formatter_is_enabled, CharT>(); - //assert_formatter_is_enabled, CharT>(); - //assert_formatter_is_enabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - assert_formatter_is_enabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled, CharT>(); - - //assert_formatter_is_enabled(); - //assert_formatter_is_enabled(); - - //assert_formatter_is_enabled(); - -#endif // TEST_HAS_NO_LOCALIZATION -} - -// 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. -template -void test_P1636() { - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled(); -#ifndef TEST_HAS_NO_FILESYSTEM_LIBRARY - assert_formatter_is_disabled(); -#endif - assert_formatter_is_disabled, CharT>(); -#ifndef TEST_HAS_NO_LOCALIZATION - assert_formatter_is_disabled, CharT>(); -#endif -#ifndef TEST_HAS_NO_THREADS - assert_formatter_is_disabled(); -#endif - assert_formatter_is_disabled, CharT>(); -} - -// Tests for P2286 Formatting ranges -// -// 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. -template -void test_P2286() { - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); -} - -class c { - void f(); - void fc() const; - static void sf(); -}; -enum e { a }; -enum class ec { a }; -template -void test_disabled() { -#ifndef TEST_HAS_NO_WIDE_CHARACTERS - assert_formatter_is_disabled(); -#endif - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - assert_formatter_is_disabled(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); - - assert_formatter_is_disabled, CharT>(); - assert_formatter_is_disabled, CharT>(); -} - -template -void test() { - test_P0645(); - test_P1361(); - test_P1636(); - test_P2286(); - test_disabled(); -} - -void test() { - test(); -#ifndef TEST_HAS_NO_WIDE_CHARACTERS - test(); -#endif - test(); - test(); - test(); - - test(); -} diff --git a/libcxx/test/std/utilities/format/format.functions/P2418.pass.cpp b/libcxx/test/std/utilities/format/format.functions/P2418.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/P2418.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/P2418.pass.cpp @@ -28,8 +28,7 @@ template struct std::formatter : std::formatter { - // TODO FMT Make this a const member function after the base class has been adapted. - auto format(const MoveOnly& m, auto& ctx) -> decltype(ctx.out()) { + auto format(const MoveOnly& m, auto& ctx) const -> decltype(ctx.out()) { return std::formatter::format(m.get(), ctx); } }; diff --git a/libcxx/test/std/utilities/format/format.functions/format_tests.h b/libcxx/test/std/utilities/format/format.functions/format_tests.h --- a/libcxx/test/std/utilities/format/format.functions/format_tests.h +++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h @@ -84,7 +84,7 @@ } template - auto format(status s, basic_format_context& ctx) -> decltype(ctx.out()) { + auto format(status s, basic_format_context& ctx) const -> decltype(ctx.out()) { const char* names[] = {"foo", "bar", "foobar"}; char buffer[7]; const char* begin = names[0];