diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv --- a/libcxx/docs/Cxx2aStatusPaperStatus.csv +++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -103,7 +103,7 @@ "`P0466 `__","LWG","Layout-compatibility and Pointer-interconvertibility Traits","Cologne","","" "`P0553 `__","LWG","Bit operations","Cologne","|Complete|","9.0" "`P0631 `__","LWG","Math Constants","Cologne","|Complete|","11.0" -"`P0645 `__","LWG","Text Formatting","Cologne","","" +"`P0645 `__","LWG","Text Formatting","Cologne","|In Progress|","" "`P0660 `__","LWG","Stop Token and Joining Thread, Rev 10","Cologne","","" "`P0784 `__","CWG","More constexpr containers","Cologne","|Complete|","12.0" "`P0980 `__","LWG","Making std::string constexpr","Cologne","","" diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -206,6 +206,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_erase_if`` ``202002L`` ------------------------------------------------- ----------------- + ``__cpp_lib_format`` *unimplemented* + ------------------------------------------------- ----------------- ``__cpp_lib_generic_unordered_lookup`` ``201811L`` ------------------------------------------------- ----------------- ``__cpp_lib_int_pow2`` ``202002L`` diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -94,6 +94,7 @@ fenv.h filesystem float.h + format forward_list fstream functional diff --git a/libcxx/include/format b/libcxx/include/format new file mode 100644 --- /dev/null +++ b/libcxx/include/format @@ -0,0 +1,242 @@ +// -*- C++ -*- +//===--------------------------- format -----------------------------------===// +// +// 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 +#define _LIBCPP_FORMAT + +/* + +namespace std { + // [format.context], class template basic_format_context + template class basic_format_context; + using format_context = basic_format_context; + using wformat_context = basic_format_context; + + // [format.args], class template basic_format_args + template class basic_format_args; + using format_args = basic_format_args; + using wformat_args = basic_format_args; + + template + using format_args_t = basic_format_args>; + + // [format.functions], formatting functions + template + string format(string_view fmt, const Args&... args); + template + wstring format(wstring_view fmt, const Args&... args); + template + string format(const locale& loc, string_view fmt, const Args&... args); + template + wstring format(const locale& loc, wstring_view fmt, const Args&... args); + + string vformat(string_view fmt, format_args args); + wstring vformat(wstring_view fmt, wformat_args args); + string vformat(const locale& loc, string_view fmt, format_args args); + wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); + + template + Out format_to(Out out, string_view fmt, const Args&... args); + template + Out format_to(Out out, wstring_view fmt, const Args&... args); + template + Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args); + template + Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args); + + template + Out vformat_to(Out out, string_view fmt, + format_args_t, char> args); + template + Out vformat_to(Out out, wstring_view fmt, + format_args_t, wchar_t> args); + template + Out vformat_to(Out out, const locale& loc, string_view fmt, + format_args_t, char> args); + template + Out vformat_to(Out out, const locale& loc, wstring_view fmt, + format_args_t, wchar_t> args); + + template struct format_to_n_result { + Out out; + iter_difference_t size; + }; + + template + format_to_n_result format_to_n(Out out, iter_difference_t n, + string_view fmt, const Args&... args); + template + format_to_n_result format_to_n(Out out, iter_difference_t n, + wstring_view fmt, const Args&... args); + template + format_to_n_result format_to_n(Out out, iter_difference_t n, + const locale& loc, string_view fmt, + const Args&... args); + template + format_to_n_result format_to_n(Out out, iter_difference_t n, + const locale& loc, wstring_view fmt, + const Args&... args); + + template + size_t formatted_size(string_view fmt, const Args&... args); + template + size_t formatted_size(wstring_view fmt, const Args&... args); + template + size_t formatted_size(const locale& loc, string_view fmt, const Args&... args); + template + size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args); + + // [format.formatter], formatter + template struct formatter; + + // [format.parse.ctx], class template basic_format_parse_context + template class basic_format_parse_context; + using format_parse_context = basic_format_parse_context; + using wformat_parse_context = basic_format_parse_context; + + // [format.arguments], arguments + // [format.arg], class template basic_format_arg + template class basic_format_arg; + + template + see below visit_format_arg(Visitor&& vis, basic_format_arg arg); + + // [format.arg.store], class template format-arg-store + template struct format-arg-store; // exposition only + + template + format-arg-store + make_format_args(const Args&... args); + template + format-arg-store + make_wformat_args(const Args&... args); + + // [format.error], class format_error + class format_error; +} + +namespace std { + template + class basic_format_parse_context { + public: + using char_type = charT; + using const_iterator = typename basic_string_view::const_iterator; + using iterator = const_iterator; + + private: + iterator begin_; // exposition only + iterator end_; // exposition only + enum indexing { unknown, manual, automatic }; // exposition only + indexing indexing_; // exposition only + size_t next_arg_id_; // exposition only + size_t num_args_; // exposition only + + public: + constexpr explicit basic_format_parse_context(basic_string_view fmt, + size_t num_args = 0) noexcept; + basic_format_parse_context(const basic_format_parse_context&) = delete; + basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; + + constexpr const_iterator begin() const noexcept; + constexpr const_iterator end() const noexcept; + constexpr void advance_to(const_iterator it); + + constexpr size_t next_arg_id(); + constexpr void check_arg_id(size_t id); + }; +} + +namespace std { + template + class basic_format_arg { + public: + class handle; + + private: + using char_type = typename Context::char_type; // exposition only + + variant, + const void*, handle> value; // exposition only + + template explicit basic_format_arg(const T& v) noexcept; // exposition only + explicit basic_format_arg(float n) noexcept; // exposition only + explicit basic_format_arg(double n) noexcept; // exposition only + explicit basic_format_arg(long double n) noexcept; // exposition only + explicit basic_format_arg(const char_type* s); // exposition only + + template + explicit basic_format_arg( + basic_string_view s) noexcept; // exposition only + + template + explicit basic_format_arg( + const basic_string& s) noexcept; // exposition only + + explicit basic_format_arg(nullptr_t) noexcept; // exposition only + + template + explicit basic_format_arg(const T* p) noexcept; // exposition only + + public: + basic_format_arg() noexcept; + + explicit operator bool() const noexcept; + }; +} + +namespace std { + template + struct format-arg-store { // exposition only + array, sizeof...(Args)> args; + }; +} + +namespace std { + class format_error : public runtime_error { + public: + explicit format_error(const string& what_arg); + explicit format_error(const char* what_arg); + }; +} +*/ + +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +class _LIBCPP_EXCEPTION_ABI format_error : public runtime_error { +public: + _LIBCPP_INLINE_VISIBILITY explicit format_error(const string& __s) + : runtime_error(__s) {} + _LIBCPP_INLINE_VISIBILITY explicit format_error(const char* __s) + : runtime_error(__s) {} + virtual ~format_error() noexcept; +}; + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_FORMAT diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -292,6 +292,10 @@ header "filesystem" export * } + module format { + header "format" + export * + } module forward_list { header "forward_list" export initializer_list diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -59,6 +59,7 @@ __cpp_lib_exchange_function 201304L __cpp_lib_execution 201603L __cpp_lib_filesystem 201703L +__cpp_lib_format 201907L __cpp_lib_gcd_lcm 201606L __cpp_lib_generic_associative_lookup 201304L __cpp_lib_generic_unordered_lookup 201811L @@ -261,6 +262,7 @@ # endif # define __cpp_lib_endian 201907L # define __cpp_lib_erase_if 202002L +// # define __cpp_lib_format 201907L # define __cpp_lib_generic_unordered_lookup 201811L # define __cpp_lib_int_pow2 202002L # define __cpp_lib_interpolate 201902L diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.v1.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.v1.abilist --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.v1.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.v1.abilist @@ -712,6 +712,9 @@ {'is_defined': True, 'name': '_ZNSt3__112ctype_bynameIwED0Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112ctype_bynameIwED1Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112ctype_bynameIwED2Ev', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__112format_errorD0Ev', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__112format_errorD1Ev', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__112format_errorD2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112future_errorC1ENS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112future_errorC2ENS_10error_codeE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112future_errorD0Ev', 'type': 'FUNC'} @@ -1620,6 +1623,7 @@ {'is_defined': True, 'name': '_ZTINSt3__112codecvt_baseE', 'size': 16, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__112ctype_bynameIcEE', 'size': 24, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__112ctype_bynameIwEE', 'size': 24, 'type': 'OBJECT'} +{'is_defined': True, 'name': '_ZTINSt3__112format_errorE', 'size': 24, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__112future_errorE', 'size': 24, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__112strstreambufE', 'size': 24, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__112system_errorE', 'size': 24, 'type': 'OBJECT'} @@ -1744,6 +1748,7 @@ {'is_defined': True, 'name': '_ZTSNSt3__112codecvt_baseE', 'size': 23, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__112ctype_bynameIcEE', 'size': 26, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__112ctype_bynameIwEE', 'size': 26, 'type': 'OBJECT'} +{'is_defined': True, 'name': '_ZTSNSt3__112format_errorE', 'size': 23, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__112future_errorE', 'size': 23, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__112strstreambufE', 'size': 23, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__112system_errorE', 'size': 23, 'type': 'OBJECT'} @@ -1872,6 +1877,7 @@ {'is_defined': True, 'name': '_ZTVNSt3__112bad_weak_ptrE', 'size': 40, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__112ctype_bynameIcEE', 'size': 104, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__112ctype_bynameIwEE', 'size': 136, 'type': 'OBJECT'} +{'is_defined': True, 'name': '_ZTVNSt3__112format_errorE', 'size': 40, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__112future_errorE', 'size': 40, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__112strstreambufE', 'size': 128, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__112system_errorE', 'size': 40, 'type': 'OBJECT'} diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -12,6 +12,7 @@ condition_variable.cpp condition_variable_destructor.cpp exception.cpp + format.cpp functional.cpp future.cpp hash.cpp diff --git a/libcxx/src/format.cpp b/libcxx/src/format.cpp new file mode 100644 --- /dev/null +++ b/libcxx/src/format.cpp @@ -0,0 +1,19 @@ +//===------------------------- format.cpp ---------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "format" + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +format_error::~format_error() noexcept = default; + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp --- a/libcxx/test/libcxx/double_include.sh.cpp +++ b/libcxx/test/libcxx/double_include.sh.cpp @@ -75,6 +75,7 @@ #include #include #include +#include #include #ifndef _LIBCPP_HAS_NO_THREADS #include diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/format.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/format.version.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/format.version.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_format 201907L [C++2a] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_format +# error "__cpp_lib_format should not be defined before c++2a" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_format +# error "__cpp_lib_format should not be defined before c++2a" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_format +# error "__cpp_lib_format should not be defined before c++2a" +# endif + +#elif TEST_STD_VER > 17 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_format +# error "__cpp_lib_format should be defined in c++2a" +# endif +# if __cpp_lib_format != 201907L +# error "__cpp_lib_format should have the value 201907L in c++2a" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_format +# error "__cpp_lib_format should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#endif // TEST_STD_VER > 17 + +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -51,6 +51,7 @@ __cpp_lib_exchange_function 201304L [C++14] __cpp_lib_execution 201603L [C++17] __cpp_lib_filesystem 201703L [C++17] + __cpp_lib_format 201907L [C++2a] __cpp_lib_gcd_lcm 201606L [C++17] __cpp_lib_generic_associative_lookup 201304L [C++14] __cpp_lib_generic_unordered_lookup 201811L [C++2a] @@ -263,6 +264,10 @@ # error "__cpp_lib_filesystem should not be defined before c++17" # endif +# ifdef __cpp_lib_format +# error "__cpp_lib_format should not be defined before c++2a" +# endif + # ifdef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should not be defined before c++17" # endif @@ -658,6 +663,10 @@ # error "__cpp_lib_filesystem should not be defined before c++17" # endif +# ifdef __cpp_lib_format +# error "__cpp_lib_format should not be defined before c++2a" +# endif + # ifdef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should not be defined before c++17" # endif @@ -1179,6 +1188,10 @@ # error "__cpp_lib_filesystem should have the value 201703L in c++17" # endif +# ifdef __cpp_lib_format +# error "__cpp_lib_format should not be defined before c++2a" +# endif + # ifndef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should be defined in c++17" # endif @@ -1991,6 +2004,19 @@ # error "__cpp_lib_filesystem should have the value 201703L in c++2a" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_format +# error "__cpp_lib_format should be defined in c++2a" +# endif +# if __cpp_lib_format != 201907L +# error "__cpp_lib_format should have the value 201907L in c++2a" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_format +# error "__cpp_lib_format should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should be defined in c++2a" # endif diff --git a/libcxx/test/std/utilities/format/format.error/format.error.pass.cpp b/libcxx/test/std/utilities/format/format.error/format.error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.error/format.error.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// This test requires the dylib support introduced in D92214. +// XFAIL: with_system_cxx_lib=macosx10.15 +// XFAIL: with_system_cxx_lib=macosx10.14 +// XFAIL: with_system_cxx_lib=macosx10.13 +// XFAIL: with_system_cxx_lib=macosx10.12 +// XFAIL: with_system_cxx_lib=macosx10.11 +// XFAIL: with_system_cxx_lib=macosx10.10 +// XFAIL: with_system_cxx_lib=macosx10.9 + +// + +// class format_error; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + static_assert(std::is_base_of_v); + static_assert(std::is_polymorphic_v); + + { + const char* msg = "format_error message c-string"; + std::format_error e(msg); + assert(std::strcmp(e.what(), msg) == 0); + std::format_error e2(e); + assert(std::strcmp(e2.what(), msg) == 0); + e2 = e; + assert(std::strcmp(e2.what(), msg) == 0); + } + { + std::string msg("format_error message std::string"); + std::format_error e(msg); + assert(e.what() == msg); + std::format_error e2(e); + assert(e2.what() == msg); + e2 = e; + assert(e2.what() == msg); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/format/version.compile.pass.cpp b/libcxx/test/std/utilities/format/version.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/version.compile.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +#include + +#include "test_macros.h" + +#ifndef _LIBCPP_VERSION +# error _LIBCPP_VERSION not defined +#endif + +// Required for MSVC internal test runner compatibility. +int main(int, char**) { return 0; } diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -483,6 +483,11 @@ "name": "__cpp_lib_constexpr_dynamic_alloc", "values": { "c++2a": int(201907) }, "headers": ["memory"] + }, { + "name": "__cpp_lib_format", + "values": { "c++2a": int(201907) }, + "headers": ["format"], + "unimplemented": True }, ]], key=lambda tc: tc["name"])