diff --git a/libcxx/include/__format/formatter.h b/libcxx/include/__format/formatter.h --- a/libcxx/include/__format/formatter.h +++ b/libcxx/include/__format/formatter.h @@ -38,26 +38,20 @@ // to support compilers with partial C++20 support. #if !defined(_LIBCPP_HAS_NO_CONCEPTS) -// Currently not implemented specializations throw an exception when used. This -// does not conform to the Standard. However not all Standard defined formatters -// have been implemented yet. Until that time the current behavior is intended. -// TODO FMT Disable the default template. +/// The default formatter template. +/// +/// [format.formatter.spec]/5 +/// If F is a disabled specialization of formatter, these values are false: +/// - is_default_constructible_v, +/// - is_copy_constructible_v, +/// - is_move_constructible_v, +/// - is_copy_assignable, and +/// - is_move_assignable. template struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter { - _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto parse(auto& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - __throw(); - } - - _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto format(_Tp, auto& __ctx) - -> decltype(__ctx.out()) { - __throw(); - } - -private: - _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void __throw() { - __throw_format_error("Argument type not implemented yet"); - } + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; }; namespace __format_spec { diff --git a/libcxx/include/__format/formatter_bool.h b/libcxx/include/__format/formatter_bool.h --- a/libcxx/include/__format/formatter_bool.h +++ b/libcxx/include/__format/formatter_bool.h @@ -102,7 +102,7 @@ // For each charT, for each cv-unqualified arithmetic type ArithmeticT other // than char, wchar_t, char8_t, char16_t, or char32_t, a specialization -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_bool<_CharT> { using _Base = __format_spec::__formatter_bool<_CharT>; diff --git a/libcxx/include/__format/formatter_integer.h b/libcxx/include/__format/formatter_integer.h --- a/libcxx/include/__format/formatter_integer.h +++ b/libcxx/include/__format/formatter_integer.h @@ -81,25 +81,25 @@ // than char, wchar_t, char8_t, char16_t, or char32_t, a specialization // Signed integral types. -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; #ifndef _LIBCPP_HAS_NO_INT128 -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<__int128_t, _CharT> : public __format_spec::__formatter_integer<_CharT> { @@ -119,28 +119,28 @@ #endif // Unsigned integral types. -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_integer<_CharT> {}; #ifndef _LIBCPP_HAS_NO_INT128 -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<__uint128_t, _CharT> : public __format_spec::__formatter_integer<_CharT> { diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h --- a/libcxx/include/__format/formatter_string.h +++ b/libcxx/include/__format/formatter_string.h @@ -65,7 +65,7 @@ // [format.formatter.spec]/2.2 For each charT, the string type specializations // Formatter const char*. -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_string<_CharT> { @@ -99,7 +99,7 @@ }; // Formatter char*. -template +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<_CharT*, _CharT> : public formatter { using _Base = formatter; @@ -111,7 +111,7 @@ }; // Formatter const char[]. -template +template <__formatter::__char_type _CharT, size_t _Size> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter : public __format_spec::__formatter_string<_CharT> { @@ -124,7 +124,7 @@ }; // Formatter std::string. -template +template <__formatter::__char_type _CharT, class _Traits, class _Allocator> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter, _CharT> : public __format_spec::__formatter_string<_CharT> { @@ -139,7 +139,7 @@ }; // Formatter std::string_view. -template +template <__formatter::__char_type _CharT, class _Traits> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter, _CharT> : public __format_spec::__formatter_string<_CharT> { using _Base = __format_spec::__formatter_string<_CharT>; 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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/types.compile.pass.cpp @@ -0,0 +1,274 @@ +//===----------------------------------------------------------------------===// +// 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-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// + +// 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 + +// 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 + 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, 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 _LIBCPP_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 _LIBCPP_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() { + 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_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_enabled(); + //assert_formatter_is_enabled(); + + //assert_formatter_is_enabled(); +} + +// 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(); + assert_formatter_is_disabled(); + assert_formatter_is_disabled, CharT>(); + assert_formatter_is_disabled, CharT>(); + assert_formatter_is_disabled(); + 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() { + 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>(); +} + +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/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 @@ -2507,7 +2507,7 @@ template void format_test_pointer(TestFunction check, ExceptionTest check_exception) { - format_test_pointer(check, check_exception); + format_test_pointer(check, check_exception); format_test_pointer(check, check_exception); format_test_pointer(check, check_exception); }