diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst index 50f7ef58395e..549efe727f2c 100644 --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -64,6 +64,12 @@ Deprecations and Removals - The headers ```` and ```` have been removed, since all the contents have been implemented in namespace ``std`` for at least two releases. +- The formatter specialization ``template struct formatter`` + has been removed. Since libc++'s format library was marked experimental there + is no backwards compatibility option. This specialization has been removed + from the Standard since it was never used, the proper specialization to use + instead is ``template struct formatter``. + Upcoming Deprecations and Removals ---------------------------------- diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv index 1635613be418..324643b96a81 100644 --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -289,7 +289,7 @@ "`3810 `__","CTAD for ``std::basic_format_args``","February 2023","|Complete|","17.0","|format|" "`3827 `__","Deprecate ```` and ```` macros","February 2023","","","" "`3828 `__","Sync ``intmax_t`` and ``uintmax_t`` with C2x","February 2023","","","" -"`3833 `__","Remove specialization ``template struct formatter``","February 2023","","","|format|" +"`3833 `__","Remove specialization ``template struct formatter``","February 2023","|Complete|","17.0","|format|" "`3836 `__","``std::expected`` conversion constructor ``expected(const expected&)`` should take precedence over ``expected(U&&)`` with operator ``bool``","February 2023","","","" "`3843 `__","``std::expected::value() &`` assumes ``E`` is copy constructible","February 2023","","","" "`3847 `__","``ranges::to`` can still return views","February 2023","","","|ranges|" diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h index 8e880ce6e8f0..e11708d8e28c 100644 --- a/libcxx/include/__format/formatter_string.h +++ b/libcxx/include/__format/formatter_string.h @@ -115,17 +115,6 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<_CharT[_Size], } }; -// Formatter const char[]. -template <__fmt_char_type _CharT, size_t _Size> -struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter - : public __formatter_string<_CharT> { - using _Base = __formatter_string<_CharT>; - - _LIBCPP_HIDE_FROM_ABI auto format(const _CharT __str[_Size], auto& __ctx) const -> decltype(__ctx.out()) { - return _Base::format(basic_string_view<_CharT>(__str, _Size), __ctx); - } -}; - // Formatter std::string. template <__fmt_char_type _CharT, class _Traits, class _Allocator> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter, _CharT> diff --git a/libcxx/include/__format/range_default_formatter.h b/libcxx/include/__format/range_default_formatter.h index b8fe4d2e294d..136ff063d069 100644 --- a/libcxx/include/__format/range_default_formatter.h +++ b/libcxx/include/__format/range_default_formatter.h @@ -83,23 +83,6 @@ inline constexpr range_format format_kind<_Rp> = [] { return range_format::sequence; }(); -// This is a non-standard work-around to fix instantiation of -// formatter -// const _CharT[N] satisfies the ranges::input_range concept. -// remove_cvref_t is _CharT[N] so it does not satisfy the -// requirement of the above specialization. Instead it will instantiate the -// primary template, which is ill-formed. -// -// An alternative solution is to remove the offending formatter. -// -// https://godbolt.org/z/bqjhhaexx -// -// The removal is proposed in LWG3833, but use the work-around until the issue -// has been adopted. -// TODO FMT Implement LWG3833. -template -inline constexpr range_format format_kind = range_format::disabled; - template struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter; diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.const_char_array.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.const_char_array.pass.cpp deleted file mode 100644 index 815bd449b979..000000000000 --- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.const_char_array.pass.cpp +++ /dev/null @@ -1,151 +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 -// TODO FMT Evaluate gcc-12 status -// UNSUPPORTED: gcc-12 - -// - -// C++23 the formatter is a debug-enabled specialization. -// [format.formatter.spec]: -// Each header that declares the template `formatter` provides the following -// enabled specializations: -// For each `charT`, the string type specializations -// template struct formatter; - -#include -#include -#include -#include -#include - -#include "test_format_context.h" -#include "test_macros.h" -#include "make_string.h" - -#define STR(S) MAKE_STRING(CharT, S) -#define SV(S) MAKE_STRING_VIEW(CharT, S) -#define CSTR(S) MAKE_CSTRING(CharT, S) - -// This is based on the method found in -// clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-cxx20.cpp -template -struct Tester { - // This is not part of the real test, but is used the deduce the size of the input. - constexpr Tester(const char (&r)[N]) { __builtin_memcpy(text, r, N); } - char text[N]; - - // The size of the array shouldn't include the NUL character. - static const size_t size = N - 1; - - template - void test(const std::basic_string& expected, - const std::basic_string_view& fmt) const { - using Str = const CharT[size]; - std::basic_format_parse_context parse_ctx{fmt}; - std::formatter formatter; - static_assert(std::semiregular); - - auto it = formatter.parse(parse_ctx); - assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}')); - - std::basic_string result; - auto out = std::back_inserter(result); - using FormatCtxT = std::basic_format_context; - - std::basic_string buffer{text, text + N}; - // Note not too found of this hack - Str* data = reinterpret_cast(buffer.c_str()); - - FormatCtxT format_ctx = - test_format_context_create(out, std::make_format_args(*data)); - formatter.format(*data, format_ctx); - assert(result == expected); - } - - template - void test_termination_condition(const std::basic_string& expected, - const std::basic_string& f) const { - // The format-spec is valid if completely consumed or terminates at a '}'. - // The valid inputs all end with a '}'. The test is executed twice: - // - first with the terminating '}', - // - second consuming the entire input. - std::basic_string_view fmt{f}; - assert(fmt.back() == CharT('}') && "Pre-condition failure"); - - test(expected, fmt); - fmt.remove_suffix(1); - test(expected, fmt); - } -}; - -template -Tester(const char (&)[N]) -> Tester; - -template -void test_helper_wrapper(std::basic_string expected, - std::basic_string fmt) { - t.test_termination_condition(expected, fmt); -} - -#if TEST_STD_VER > 20 -template -constexpr bool test_set_debug_format() { - std::formatter formatter; - LIBCPP_ASSERT(formatter.__parser_.__type_ == std::__format_spec::__type::__default); - - formatter.set_debug_format(); - LIBCPP_ASSERT(formatter.__parser_.__type_ == std::__format_spec::__type::__debug); - - std::basic_string_view fmt = SV("s}"); - std::basic_format_parse_context parse_ctx{fmt}; - formatter.parse(parse_ctx); - LIBCPP_ASSERT(formatter.__parser_.__type_ == std::__format_spec::__type::__string); - - formatter.set_debug_format(); - LIBCPP_ASSERT(formatter.__parser_.__type_ == std::__format_spec::__type::__debug); - - return true; -} -#endif -template -void test_array() { - test_helper_wrapper<" azAZ09,./<>?">(STR(" azAZ09,./<>?"), STR("}")); - - std::basic_string s(CSTR("abc\0abc"), 7); - test_helper_wrapper<"abc\0abc">(s, STR("}")); - - test_helper_wrapper<"world">(STR("world"), STR("}")); - test_helper_wrapper<"world">(STR("world"), STR("_>}")); - - test_helper_wrapper<"world">(STR(" world"), STR(">8}")); - test_helper_wrapper<"world">(STR("___world"), STR("_>8}")); - test_helper_wrapper<"world">(STR("_world__"), STR("_^8}")); - test_helper_wrapper<"world">(STR("world___"), STR("_<8}")); - - test_helper_wrapper<"world">(STR("world"), STR(".5}")); - test_helper_wrapper<"universe">(STR("unive"), STR(".5}")); - - test_helper_wrapper<"world">(STR("%world%"), STR("%^7.7}")); - test_helper_wrapper<"universe">(STR("univers"), STR("%^7.7}")); - -#if TEST_STD_VER > 20 - test_set_debug_format(); - static_assert(test_set_debug_format()); -#endif -} - -int main(int, char**) { - test_array(); -#ifndef TEST_HAS_NO_WIDE_CHARACTERS - test_array(); -#endif - - return 0; -}