[libc++][format] Addresses LWG3833.

LWG3833 Remove specialization template<size_t N> struct formatter<const charT[N], charT>

Depends on D143845

Reviewed By: #libc, ldionne

Differential Revision: https://reviews.llvm.org/D143850
This commit is contained in:
Mark de Wever 2023-02-12 19:46:13 +01:00
parent 20b538fc64
commit faacf8bca3
5 changed files with 7 additions and 180 deletions

View File

@ -64,6 +64,12 @@ Deprecations and Removals
- The headers ``<experimental/algorithm>`` and ``<experimental/functional>`` have been removed, since all the contents
have been implemented in namespace ``std`` for at least two releases.
- The formatter specialization ``template<size_t N> struct formatter<const charT[N], charT>``
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<size_t N> struct formatter<charT[N], charT>``.
Upcoming Deprecations and Removals
----------------------------------

View File

@ -289,7 +289,7 @@
"`3810 <https://wg21.link/LWG3810>`__","CTAD for ``std::basic_format_args``","February 2023","|Complete|","17.0","|format|"
"`3827 <https://wg21.link/LWG3827>`__","Deprecate ``<stdalign.h>`` and ``<stdbool.h>`` macros","February 2023","","",""
"`3828 <https://wg21.link/LWG3828>`__","Sync ``intmax_t`` and ``uintmax_t`` with C2x","February 2023","","",""
"`3833 <https://wg21.link/LWG3833>`__","Remove specialization ``template<size_t N> struct formatter<const charT[N], charT>``","February 2023","","","|format|"
"`3833 <https://wg21.link/LWG3833>`__","Remove specialization ``template<size_t N> struct formatter<const charT[N], charT>``","February 2023","|Complete|","17.0","|format|"
"`3836 <https://wg21.link/LWG3836>`__","``std::expected<bool, E1>`` conversion constructor ``expected(const expected<U, G>&)`` should take precedence over ``expected(U&&)`` with operator ``bool``","February 2023","","",""
"`3843 <https://wg21.link/LWG3843>`__","``std::expected<T,E>::value() &`` assumes ``E`` is copy constructible","February 2023","","",""
"`3847 <https://wg21.link/LWG3847>`__","``ranges::to`` can still return views","February 2023","","","|ranges|"

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -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<const _CharT[_Size], _CharT>
: 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<basic_string<_CharT, _Traits, _Allocator>, _CharT>

View File

@ -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], _CharT>
// const _CharT[N] satisfies the ranges::input_range concept.
// remove_cvref_t<const _CharT[N]> 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 <class _CharT, size_t N>
inline constexpr range_format format_kind<const _CharT[N]> = range_format::disabled;
template <range_format _Kp, ranges::input_range _Rp, class _CharT>
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter;

View File

@ -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
// <format>
// 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<size_t N> struct formatter<const charT[N], charT>;
#include <format>
#include <cassert>
#include <concepts>
#include <iterator>
#include <type_traits>
#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 <size_t N>
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 <class CharT>
void test(const std::basic_string<CharT>& expected,
const std::basic_string_view<CharT>& fmt) const {
using Str = const CharT[size];
std::basic_format_parse_context<CharT> parse_ctx{fmt};
std::formatter<Str, CharT> formatter;
static_assert(std::semiregular<decltype(formatter)>);
auto it = formatter.parse(parse_ctx);
assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
std::basic_string<CharT> result;
auto out = std::back_inserter(result);
using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
std::basic_string<CharT> buffer{text, text + N};
// Note not too found of this hack
Str* data = reinterpret_cast<Str*>(buffer.c_str());
FormatCtxT format_ctx =
test_format_context_create<decltype(out), CharT>(out, std::make_format_args<FormatCtxT>(*data));
formatter.format(*data, format_ctx);
assert(result == expected);
}
template <class CharT>
void test_termination_condition(const std::basic_string<CharT>& expected,
const std::basic_string<CharT>& 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<CharT> fmt{f};
assert(fmt.back() == CharT('}') && "Pre-condition failure");
test(expected, fmt);
fmt.remove_suffix(1);
test(expected, fmt);
}
};
template <size_t N>
Tester(const char (&)[N]) -> Tester<N>;
template <Tester t, class CharT>
void test_helper_wrapper(std::basic_string<CharT> expected,
std::basic_string<CharT> fmt) {
t.test_termination_condition(expected, fmt);
}
#if TEST_STD_VER > 20
template <class CharT>
constexpr bool test_set_debug_format() {
std::formatter<const CharT[1], CharT> 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<CharT> 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 <class CharT>
void test_array() {
test_helper_wrapper<" azAZ09,./<>?">(STR(" azAZ09,./<>?"), STR("}"));
std::basic_string<CharT> 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<CharT>();
static_assert(test_set_debug_format<CharT>());
#endif
}
int main(int, char**) {
test_array<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test_array<wchar_t>();
#endif
return 0;
}