diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -178,6 +178,7 @@ __filesystem/recursive_directory_iterator.h __filesystem/space_info.h __filesystem/u8path.h + __format/concepts.h __format/format_arg.h __format/format_args.h __format/format_context.h diff --git a/libcxx/include/__format/concepts.h b/libcxx/include/__format/concepts.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__format/concepts.h @@ -0,0 +1,52 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 _LIBCPP___FORMAT_CONCEPTS_H +#define _LIBCPP___FORMAT_CONCEPTS_H + +#include <__concepts/same_as.h> +#include <__concepts/semiregular.h> +#include <__config> +#include <__format/format_fwd.h> +#include <__format/format_parse_context.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +// TODO FMT Remove this once we require compilers with proper C++20 support. +// If the compiler has no concepts support, the format header will be disabled. +// Without concepts support enable_if needs to be used and that too much effort +// to support compilers with partial C++20 support. +# if !defined(_LIBCPP_HAS_NO_CONCEPTS) + +// 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<_CharT*, _CharT> __fc, basic_format_parse_context<_CharT> __pc) { + { __f.parse(__pc) } -> same_as::iterator>; + { __cf.format(__t, __fc) } -> same_as<_CharT*>; +}; + +# endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_CONCEPTS_H diff --git a/libcxx/include/__format/format_context.h b/libcxx/include/__format/format_context.h --- a/libcxx/include/__format/format_context.h +++ b/libcxx/include/__format/format_context.h @@ -37,10 +37,6 @@ // to support compilers with partial C++20 support. #if !defined(_LIBCPP_HAS_NO_CONCEPTS) -template -requires output_iterator<_OutIt, const _CharT&> -class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_context; - #ifndef _LIBCPP_HAS_NO_LOCALIZATION /** * Helper to create a basic_format_context. diff --git a/libcxx/include/__format/format_fwd.h b/libcxx/include/__format/format_fwd.h --- a/libcxx/include/__format/format_fwd.h +++ b/libcxx/include/__format/format_fwd.h @@ -12,6 +12,7 @@ #include <__availability> #include <__config> +#include <__iterator/concepts.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -33,6 +34,10 @@ template struct _LIBCPP_TEMPLATE_VIS __format_arg_store; +template + requires output_iterator<_OutIt, const _CharT&> +class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_context; + template struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter; diff --git a/libcxx/include/format b/libcxx/include/format --- a/libcxx/include/format +++ b/libcxx/include/format @@ -125,6 +125,7 @@ #include <__algorithm/clamp.h> #include <__config> #include <__debug> +#include <__format/concepts.h> #include <__format/format_arg.h> #include <__format/format_args.h> #include <__format/format_context.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -500,6 +500,7 @@ export * module __format { + module concepts { private header "__format/concepts.h" } module format_arg { private header "__format/format_arg.h" } module format_args { private header "__format/format_args.h" } module format_context { diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/format/concepts.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/format/concepts.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/format/concepts.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__format/concepts.h'}} +#include <__format/concepts.h> diff --git a/libcxx/test/libcxx/utilities/format/format.formatter/format.formatter.spec/formattable.compile.pass.cpp b/libcxx/test/libcxx/utilities/format/format.formatter/format.formatter.spec/formattable.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/format/format.formatter/format.formatter.spec/formattable.compile.pass.cpp @@ -0,0 +1,330 @@ +//===----------------------------------------------------------------------===// +// 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 + +// TODO FMT Move to std after P2286 has been accepted. + +// + +// template +// concept formattable = ... + +#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 + +template +void assert_is_not_formattable() { + static_assert(!std::__formattable); +} + +template +void assert_is_formattable() { + // 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(std::__formattable); + else + assert_is_not_formattable(); +} + +// 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_is_formattable(); +#endif + assert_is_formattable(); + + assert_is_formattable(); + assert_is_formattable(); + assert_is_formattable(); // LWG-XXXX + assert_is_formattable, CharT>(); + assert_is_formattable, CharT>(); + + assert_is_formattable(); + + assert_is_formattable(); + assert_is_formattable(); + assert_is_formattable(); + assert_is_formattable(); + assert_is_formattable(); +#ifndef TEST_HAS_NO_INT128 + assert_is_formattable<__int128_t, CharT>(); +#endif + + assert_is_formattable(); + assert_is_formattable(); + assert_is_formattable(); + assert_is_formattable(); + assert_is_formattable(); +#ifndef TEST_HAS_NO_INT128 + assert_is_formattable<__uint128_t, CharT>(); +#endif + + assert_is_formattable(); + assert_is_formattable(); + assert_is_formattable(); + + assert_is_formattable(); + assert_is_formattable(); + assert_is_formattable(); +} + +// 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_is_not_formattable(); + + assert_is_not_formattable, CharT>(); + //assert_is_formattable, CharT>(); + //assert_is_formattable, CharT>(); + //assert_is_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable, CharT>(); + + //assert_is_formattable(); + //assert_is_formattable(); + + //assert_is_formattable(); +} + +// 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_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable(); +#ifndef TEST_HAS_NO_FILESYSTEM_LIBRARY + assert_is_not_formattable(); +#endif + assert_is_not_formattable, CharT>(); +#ifndef TEST_HAS_NO_LOCALIZATION + assert_is_not_formattable, CharT>(); +#endif +#ifndef TEST_HAS_NO_THREADS + assert_is_not_formattable(); +#endif + assert_is_not_formattable, 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_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, 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_is_not_formattable(); +#endif + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable(); + assert_is_not_formattable(); + assert_is_not_formattable(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, CharT>(); + + assert_is_not_formattable, CharT>(); + assert_is_not_formattable, 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(); +}