diff --git a/libcxx/docs/Cxx2aStatusIssuesStatus.csv b/libcxx/docs/Cxx2aStatusIssuesStatus.csv --- a/libcxx/docs/Cxx2aStatusIssuesStatus.csv +++ b/libcxx/docs/Cxx2aStatusIssuesStatus.csv @@ -275,7 +275,7 @@ "`3364 `__","Initialize data members of ranges and their iterators","Prague","","" "`3367 `__","Integer-class conversions should not throw","Prague","","" "`3369 `__","``span``\ 's deduction-guide for built-in arrays doesn't work","Prague","","" -"`3371 `__","``visit_format_arg``\ and ``make_format_args``\ are not hidden friends","Prague","","" +"`3371 `__","``visit_format_arg``\ and ``make_format_args``\ are not hidden friends","Prague","|Complete|","13.0" "`3372 `__","``vformat_to``\ should not try to deduce ``Out``\ twice","Prague","","" "`3373 `__","``{to,from}_chars_result``\ and ``format_to_n_result``\ need the ""we really mean what we say"" wording","Prague","","" "`3374 `__","P0653 + P1006 should have made the other ``std::to_address``\ overload ``constexpr``\ ","Prague","|Complete|","12.0" diff --git a/libcxx/docs/FormatStatus.rst b/libcxx/docs/FormatStatus.rst --- a/libcxx/docs/FormatStatus.rst +++ b/libcxx/docs/FormatStatus.rst @@ -39,8 +39,8 @@ (Please mark all Format-related TODO comments with the string ``TODO FMT``, so we can find them easily.) - * C++23 may break the ABI with `P2216 `_. - This ABI break may be backported to C++20. Therefore the library will not + * C++23 breaks the ABI with `P2216 `_. + This ABI break will be backported to C++20. Therefore the library will not be available on platforms where the ABI break is an issue. diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -7,7 +7,11 @@ __config __debug __errc + __format/format_arg.h + __format/format_args.h + __format/format_context.h __format/format_error.h + __format/format_fwd.h __format/format_parse_context.h __function_like.h __functional_03 diff --git a/libcxx/include/__availability b/libcxx/include/__availability --- a/libcxx/include/__availability +++ b/libcxx/include/__availability @@ -139,9 +139,9 @@ // # define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore // This controls the availability of the C++20 format library. - // The library is in development and not ABI stable yet. Currently - // P2216 is aiming to be retroactively accepted in C++20. This paper - // contains ABI breaking changes. + // The library is in development and not ABI stable yet. P2216 is + // retroactively accepted in C++20. This paper contains ABI breaking + // changes. # define _LIBCPP_AVAILABILITY_FORMAT // # define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format @@ -238,9 +238,9 @@ # endif // This controls the availability of the C++20 format library. - // The library is in development and not ABI stable yet. Currently - // P2216 is aiming to be retroactively accepted in C++20. This paper - // contains ABI breaking changes. + // The library is in development and not ABI stable yet. P2216 is + // retroactively accepted in C++20. This paper contains ABI breaking + // changes. # define _LIBCPP_AVAILABILITY_FORMAT \ __attribute__((unavailable)) # define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format diff --git a/libcxx/include/__format/format_arg.h b/libcxx/include/__format/format_arg.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__format/format_arg.h @@ -0,0 +1,294 @@ +// -*- 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_FORMAT_ARG_H +#define _LIBCPP___FORMAT_FORMAT_ARG_H + +#include <__config> +#include <__format/format_error.h> +#include <__format/format_fwd.h> +#include <__functional_base> +#include +#include +#include +#include // TODO FMT Use <__variant/monostate.h> + +#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 + +// 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) && \ + !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) + +namespace __format { +/** The type stored in @ref basic_format_arg. */ +enum class _LIBCPP_ENUM_VIS __arg_t : uint8_t { + __none, + __bool, + __char_type, + __int, + __long_long, +#ifndef _LIBCPP_HAS_NO_INT128 + __i128, +#endif + __unsigned, + __unsigned_long_long, +#ifndef _LIBCPP_HAS_NO_INT128 + __u128, +#endif + __float, + __double, + __long_double, + __const_char_type_ptr, + __string_view, + __ptr +}; +} // namespace __format + +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_FORMAT decltype(auto) +visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { + switch (__arg.__type_) { + case __format::__arg_t::__none: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), monostate{}); + case __format::__arg_t::__bool: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__bool); + case __format::__arg_t::__char_type: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__char_type); + case __format::__arg_t::__int: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__int); + case __format::__arg_t::__long_long: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__long_long); +#ifndef _LIBCPP_HAS_NO_INT128 + case __format::__arg_t::__i128: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__i128); +#endif + case __format::__arg_t::__unsigned: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__unsigned); + case __format::__arg_t::__unsigned_long_long: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), + __arg.__unsigned_long_long); +#ifndef _LIBCPP_HAS_NO_INT128 + case __format::__arg_t::__u128: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__u128); +#endif + case __format::__arg_t::__float: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__float); + case __format::__arg_t::__double: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__double); + case __format::__arg_t::__long_double: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__long_double); + case __format::__arg_t::__const_char_type_ptr: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), + __arg.__const_char_type_ptr); + case __format::__arg_t::__string_view: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__string_view); + case __format::__arg_t::__ptr: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__ptr); + } + _LIBCPP_UNREACHABLE(); +} + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_arg { +public: + // TODO FMT Define the handle class. + class handle; + + _LIBCPP_INLINE_VISIBILITY basic_format_arg() noexcept + : __type_{__format::__arg_t::__none} {} + + _LIBCPP_INLINE_VISIBILITY explicit operator bool() const noexcept { + return __type_ != __format::__arg_t::__none; + } + +private: + using char_type = typename _Context::char_type; + + // TODO FMT Implement constrain [format.arg]/4 + // Constraints: The template specialization + // typename Context::template formatter_type + // meets the Formatter requirements ([formatter.requirements]). The extent + // to which an implementation determines that the specialization meets the + // Formatter requirements is unspecified, except that as a minimum the + // expression + // typename Context::template formatter_type() + // .format(declval(), declval()) + // shall be well-formed when treated as an unevaluated operand. + + template + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_AVAILABILITY_FORMAT friend __format_arg_store<_Ctx, _Args...> + _VSTD::make_format_args(const _Args&...); + + template + _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_FORMAT friend decltype(auto) + _VSTD::visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx> __arg); + + union { + bool __bool; + char_type __char_type; + int __int; + unsigned __unsigned; + long long __long_long; + unsigned long long __unsigned_long_long; +#ifndef _LIBCPP_HAS_NO_INT128 + __int128_t __i128; + __uint128_t __u128; +#endif + float __float; + double __double; + long double __long_double; + const char_type* __const_char_type_ptr; + basic_string_view __string_view; + const void* __ptr; + // TODO FMT Add the handle. + }; + __format::__arg_t __type_; + + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(bool __v) noexcept + : __bool(__v), __type_(__format::__arg_t::__bool) {} + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(_Tp __v) noexcept + requires(same_as<_Tp, char_type> || + (same_as<_Tp, char> && same_as)) + : __char_type(__v), __type_(__format::__arg_t::__char_type) {} + + template <__libcpp_signed_integer _Tp> + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(_Tp __v) noexcept + requires(sizeof(_Tp) <= sizeof(int)) + : __int(__v), __type_(__format::__arg_t::__int) {} + + template <__libcpp_unsigned_integer _Tp> + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(_Tp __v) noexcept + requires(sizeof(_Tp) <= sizeof(unsigned)) + : __unsigned(__v), __type_(__format::__arg_t::__unsigned) {} + + template <__libcpp_signed_integer _Tp> + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(_Tp __v) noexcept + requires(sizeof(_Tp) > sizeof(int)) + : __long_long(__v), __type_(__format::__arg_t::__long_long) {} + + template <__libcpp_unsigned_integer _Tp> + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(_Tp __v) noexcept + requires(sizeof(_Tp) > sizeof(unsigned)) + : __unsigned_long_long(static_cast(__v)), + __type_(__format::__arg_t::__unsigned_long_long) {} + +#ifndef _LIBCPP_HAS_NO_INT128 + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(__int128_t __v) noexcept + : __i128(__v), __type_(__format::__arg_t::__i128) {} + + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(__uint128_t __v) noexcept + : __u128(__v), __type_(__format::__arg_t::__u128) {} +#endif + + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(float __v) noexcept + : __float(__v), __type_(__format::__arg_t::__float) {} + + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(double __v) noexcept + : __double(__v), __type_(__format::__arg_t::__double) {} + + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(long double __v) noexcept + : __long_double(__v), __type_(__format::__arg_t::__long_double) {} + + // Note not a 'noexcept' function. + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(const char_type* __s) + : __const_char_type_ptr(__s), + __type_(__format::__arg_t::__const_char_type_ptr) { + _LIBCPP_ASSERT(__s, "Used a nullptr argument to initialize a C-string"); + } + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg( + basic_string_view __s) noexcept + : __string_view{__s.data(), __s.size()}, + __type_(__format::__arg_t::__string_view) {} + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg( + const basic_string& __s) noexcept + : __string_view{__s.data(), __s.size()}, + __type_(__format::__arg_t::__string_view) {} + + _LIBCPP_INLINE_VISIBILITY + explicit basic_format_arg(nullptr_t) noexcept + : __ptr(nullptr), __type_(__format::__arg_t::__ptr) {} + + // TODO FMT Implement the _Tp* constructor. + + friend bool operator==(const basic_format_arg& __lhs, + const basic_format_arg& __rhs) { + if (__lhs.__type_ != __rhs.__type_) + return false; + switch (__lhs.__type_) { + case __format::__arg_t::__none: + return true; + case __format::__arg_t::__bool: + return __lhs.__bool == __rhs.__bool; + case __format::__arg_t::__char_type: + return __lhs.__char_type == __rhs.__char_type; + case __format::__arg_t::__int: + return __lhs.__int == __rhs.__int; + case __format::__arg_t::__long_long: + return __lhs.__long_long == __rhs.__long_long; +#ifndef _LIBCPP_HAS_NO_INT128 + case __format::__arg_t::__i128: + return __lhs.__i128 == __rhs.__i128; +#endif + case __format::__arg_t::__unsigned: + return __lhs.__unsigned == __rhs.__unsigned; + case __format::__arg_t::__unsigned_long_long: + return __lhs.__unsigned_long_long == __rhs.__unsigned_long_long; +#ifndef _LIBCPP_HAS_NO_INT128 + case __format::__arg_t::__u128: + return __lhs.__u128 == __rhs.__u128; +#endif + case __format::__arg_t::__float: + return __lhs.__float == __rhs.__float; + case __format::__arg_t::__double: + return __lhs.__double == __rhs.__double; + case __format::__arg_t::__long_double: + return __lhs.__long_double == __rhs.__long_double; + case __format::__arg_t::__const_char_type_ptr: + // Note this isn't efficient since the string is evaluated twice, but it + // works regardless of the type of char_type. User code shouldn't use + // this function, since it isn't promised to be available. + return basic_string_view(__lhs.__const_char_type_ptr) == + basic_string_view(__rhs.__const_char_type_ptr); + case __format::__arg_t::__string_view: + return __lhs.__string_view == __rhs.__string_view; + case __format::__arg_t::__ptr: + return __lhs.__ptr == __rhs.__ptr; + } + _LIBCPP_UNREACHABLE(); + } +}; + +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMAT_ARG_H diff --git a/libcxx/include/__format/format_args.h b/libcxx/include/__format/format_args.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__format/format_args.h @@ -0,0 +1,73 @@ +// -*- 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_FORMAT_ARGS_H +#define _LIBCPP___FORMAT_FORMAT_ARGS_H + +#include <__availability> +#include <__config> +#include <__format/format_fwd.h> +#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 + +// 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) && \ + !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_args { +public: + // TODO FMT Implement [format.args]/5 + // [Note 1: Implementations are encouraged to optimize the representation of + // basic_format_args for small number of formatting arguments by storing + // indices of type alternatives separately from values and packing the + // former. - end note] + _LIBCPP_INLINE_VISIBILITY basic_format_args() noexcept = default; + + template + _LIBCPP_INLINE_VISIBILITY basic_format_args( + const __format_arg_store<_Context, _Args...>& __store) noexcept + : __size_(sizeof...(_Args)), __data_(__store.__args.data()) {} + + _LIBCPP_INLINE_VISIBILITY + basic_format_arg<_Context> get(size_t __id) const noexcept { + return __id < __size_ ? __data_[__id] : basic_format_arg<_Context>(); + } + + [[nodiscard]] _LIBCPP_INLINE_VISIBILITY size_t __size() const noexcept { + return __size_; + } + +private: + size_t __size_{0}; + const basic_format_arg<_Context>* __data_{nullptr}; +}; + +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMAT_ARGS_H diff --git a/libcxx/include/__format/format_context.h b/libcxx/include/__format/format_context.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__format/format_context.h @@ -0,0 +1,121 @@ +// -*- 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_FORMAT_CONTEXT_H +#define _LIBCPP___FORMAT_FORMAT_CONTEXT_H + +#include <__availability> +#include <__config> +#include <__format/format_args.h> +#include <__format/format_fwd.h> +#include +#include +#include + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +#include +#include +#endif + +#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 + +// 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) && \ + !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) + +template +requires __output_iterator<_OutIt, const _CharT&> +class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_context { +public: + using iterator = _OutIt; + using char_type = _CharT; + template + using formatter_type = formatter<_Tp, _CharT>; + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + // Note: the Standard doesn't specify the required constructors. + _LIBCPP_INLINE_VISIBILITY + basic_format_context(_OutIt __out_it, + basic_format_args __args, + optional<_VSTD::locale>&& __loc = nullopt) + : __out_it_(_VSTD::move(__out_it)), __args_(__args), + __loc_(_VSTD::move(__loc)) {} +#else + _LIBCPP_INLINE_VISIBILITY + basic_format_context(_OutIt __out_it, + basic_format_args __args) + : __out_it_(_VSTD::move(__out_it)), __args_(__args) {} +#endif + + basic_format_context(const basic_format_context&) = delete; + basic_format_context& operator=(const basic_format_context&) = delete; + + _LIBCPP_INLINE_VISIBILITY basic_format_arg + arg(size_t __id) const { + return __args_.get(__id); + } +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + _LIBCPP_INLINE_VISIBILITY _VSTD::locale locale() { + if (!__loc_) + __loc_ = _VSTD::locale(); + return *__loc_; + } +#endif + _LIBCPP_INLINE_VISIBILITY iterator out() { return __out_it_; } + _LIBCPP_INLINE_VISIBILITY void advance_to(iterator __it) { __out_it_ = __it; } + +private: + iterator __out_it_; + basic_format_args __args_; +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + // The Standard doesn't specify how the locale is stored. + // [format.context]/6 + // std::locale locale(); + // Returns: The locale passed to the formatting function if the latter + // takes one, and std::locale() otherwise. + // This is done by storing the locale of the constructor in this optional. If + // locale() is called and the optional has no value the value will be created. + // This allows the implementation to lazily create the locale. + // TODO FMT Validate whether lazy creation is the best solution. + optional<_VSTD::locale> __loc_; +#endif +}; + +// TODO FMT Implement [format.context]/4 +// [Note 1: For a given type charT, implementations are encouraged to provide a +// single instantiation of basic_format_context for appending to +// basic_string, vector, or any other container with contiguous +// storage by wrapping those in temporary objects with a uniform interface +// (such as a span) and polymorphic reallocation. - end note] + +using format_context = basic_format_context, char>; +using wformat_context = + basic_format_context, wchar_t>; + +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H diff --git a/libcxx/include/__format/format_fwd.h b/libcxx/include/__format/format_fwd.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__format/format_fwd.h @@ -0,0 +1,68 @@ +// -*- 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_FORMAT_FWD_H +#define _LIBCPP___FORMAT_FORMAT_FWD_H + +#include <__availability> +#include <__config> +#include <__iterator/concepts.h> +#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 + +// 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) && \ + !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) + +// Currently libc++ hasn't implemented output_iterator. Use our own version +// that follows the wording of [iterator.concept.output]/1. +// TODO FMT Switch to the real concepts when they are available. +template +concept __output_iterator = input_or_output_iterator<_Ip> && + indirectly_writable<_Ip, _Tp> && requires(_Ip __i, _Tp&& __t) { + *__i++ = _VSTD::forward<_Tp>(__t); +}; + +// Forward declarations. + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_arg; + +template +struct _LIBCPP_TEMPLATE_VIS __format_arg_store; + +template +_LIBCPP_INLINE_VISIBILITY __format_arg_store<_Ctx, _Args...> +make_format_args(const _Args&...); + +template +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter; + +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMAT_FWD_H diff --git a/libcxx/include/concepts b/libcxx/include/concepts --- a/libcxx/include/concepts +++ b/libcxx/include/concepts @@ -445,6 +445,15 @@ template concept __different_from = !same_as, remove_cvref_t<_Up>>; +// Concept helpers for the internal type traits for the fundamental types. + +template +concept __libcpp_unsigned_integer = __libcpp_is_unsigned_integer<_Tp>::value; +template +concept __libcpp_signed_integer = __libcpp_is_signed_integer<_Tp>::value; +template +concept __libcpp_floating_point = __libcpp_is_floating_point<_Tp>::value; + #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/format b/libcxx/include/format --- a/libcxx/include/format +++ b/libcxx/include/format @@ -10,9 +10,148 @@ #ifndef _LIBCPP_FORMAT #define _LIBCPP_FORMAT +// TODO FMT Remove this once the library is complete. +/* + * WARNING + * The header is work in progress and not complete yet. The ABI isn't stable. + * Partly due to the lack of recommended optimizations, partly due to the + * current implementation not implementing: + * https://wg21.link/P2216 std::format improvements + */ + /* namespace std { + // [format.context], class template basic_format_context + template + class basic_format_context { + basic_format_args args_; // exposition only + Out out_; // exposition only + + public: + using iterator = Out; + using char_type = charT; + template using formatter_type = formatter; + + basic_format_arg arg(size_t id) const; + std::locale locale(); + + iterator out(); + void advance_to(iterator it); + }; + using format_context = basic_format_context; + using wformat_context = basic_format_context; + + // [format.args], class template basic_format_args + template + class basic_format_args { + size_t size_; // exposition only + const basic_format_arg* data_; // exposition only + + public: + basic_format_args() noexcept; + + template + basic_format_args(const format-arg-store& store) noexcept; + + basic_format_arg get(size_t i) const noexcept; + }; + using format_args = basic_format_args; + using wformat_args = basic_format_args; + + + template + using format_args_t = basic_format_args>; + + // [format.parse.ctx], class template basic_format_parse_context + 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); + }; + 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 { + 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; + }; + + 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 + array, sizeof...(Args)> args; + }; + + 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 : public runtime_error { public: @@ -56,12 +195,16 @@ */ #include <__config> +#include <__format/format_arg.h> +#include <__format/format_args.h> +#include <__format/format_context.h> #include <__format/format_error.h> #include <__format/format_parse_context.h> +#include #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header +#pragma GCC system_header #endif _LIBCPP_PUSH_MACROS @@ -71,6 +214,42 @@ #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) && \ + !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) + +// TODO FMT Evaluate which templates should be external templates. This +// improves the efficiency of the header. However since the header is still +// under heavy development and not all classes are stable it makes no sense +// to do this optimization now. + +using format_args = basic_format_args; +using wformat_args = basic_format_args; + +template +using format_args_t = basic_format_args>; + +template +struct _LIBCPP_TEMPLATE_VIS __format_arg_store { + array, sizeof...(_Args)> __args; +}; + +template +_LIBCPP_INLINE_VISIBILITY __format_arg_store<_Context, _Args...> +make_format_args(const _Args&... __args) { + return {basic_format_arg<_Context>(__args)...}; +} + +template +_LIBCPP_INLINE_VISIBILITY __format_arg_store +make_wformat_args(const _Args&... __args) { + return make_format_args(__args...); +} + +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) #endif //_LIBCPP_STD_VER > 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -297,7 +297,11 @@ export * module __format { + module format_arg { header "__format/format_arg.h" } + module format_args { header "__format/format_args.h" } + module format_context { header "__format/format_context.h" } module format_error { header "__format/format_error.h" } + module format_fwd { header "__format/format_fwd.h" } module format_parse_context { header "__format/format_parse_context.h" } } } diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -790,6 +790,7 @@ #endif // __has_keyword(__is_integral) // __libcpp_is_signed_integer, __libcpp_is_unsigned_integer +// implements __libcpp_signed_integer, __libcpp_unsigned_integer // [basic.fundamental] defines five standard signed integer types; // __int128_t is an extended signed integer type. @@ -817,6 +818,7 @@ #endif // is_floating_point +// implements __libcpp_floating_point template struct __libcpp_is_floating_point : public false_type {}; template <> struct __libcpp_is_floating_point : public true_type {}; diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/class.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/class.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/class.pass.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// template +// struct format-arg-store { // exposition only +// array, sizeof...(Args)> args; +// }; +// +// Note more testing is done in the unit test for: +// template +// see below visit_format_arg(Visitor&& vis, basic_format_arg arg); + +#include +#include +#include + +#include "test_macros.h" + +template +void test() { + using Context = std::basic_format_context; + { + auto store = std::make_format_args(); + static_assert( + std::is_same_v>); + static_assert( + std::is_same_v, 0>>); + assert(store.__args.size() == 0); + } + { + auto store = std::make_format_args(1); + static_assert( + std::is_same_v>); + static_assert( + std::is_same_v, 1>>); + assert(store.__args.size() == 1); + } + { + auto store = std::make_format_args(1, 'c'); + static_assert(std::is_same_v>); + static_assert( + std::is_same_v, 2>>); + assert(store.__args.size() == 2); + } + { + auto store = std::make_format_args(1, 'c', nullptr); + static_assert( + std::is_same_v>); + static_assert( + std::is_same_v, 3>>); + assert(store.__args.size() == 3); + } +} + +void test() { + test(); + test(); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// 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: gcc-11 + +// + +// template +// format-arg-store make_format_args(const Args&... args); + +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + using Context = std::basic_format_context< + std::back_insert_iterator>, char>; + + auto value = std::make_format_args(42, nullptr, false, 1.0); + auto expected = + std::make_format_args( + 42, nullptr, false, 1.0); + + assert(value.__args.size() == 4); + assert(expected.__args.size() == value.__args.size()); + + for (size_t i = 0, e = value.__args.size(); i != e; ++i) + assert(value.__args[i] == expected.__args[i]); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.sh.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.sh.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.sh.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Validate it works regardless of the signedness of `char`. +// RUN: %{cxx} %{flags} %{compile_flags} -fsigned-char -fsyntax-only %s +// RUN: %{cxx} %{flags} %{compile_flags} -funsigned-char -fsyntax-only %s + +// + +// [format.arg]/5.2 +// - otherwise, if T is char and char_type is wchar_t, initializes value with static_cast(v); + +#include + +void test() { + std::make_format_args>, wchar_t>>('c'); +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// template +// format-arg-store +// make_wformat_args(const Args&... args); + +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + using Context = std::basic_format_context< + std::back_insert_iterator>, wchar_t>; + + auto value = std::make_wformat_args(42, nullptr, false, 1.0); + auto expected = + std::make_format_args( + 42, nullptr, false, 1.0); + + assert(value.__args.size() == 4); + assert(expected.__args.size() == value.__args.size()); + + for (size_t i = 0, e = value.__args.size(); i != e; ++i) + assert(value.__args[i] == expected.__args[i]); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/ctor.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/ctor.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// basic_format_arg() noexcept; + +// The class has several exposition only private constructors. These are tested +// in visit_format_arg.pass.cpp + +#include +#include + +#include "test_macros.h" + +template +void test() { + using Context = std::basic_format_context; + + ASSERT_NOEXCEPT(std::basic_format_arg{}); + + std::basic_format_arg format_arg{}; + assert(!format_arg); +} + +void test() { + test(); + test(); +#ifndef _LIBCPP_HAS_NO_CHAR8_T + test(); +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test(); + test(); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/operator_bool.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/operator_bool.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/operator_bool.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// explicit operator bool() const noexcept +// +// Note more testing is done in the unit test for: +// template +// see below visit_format_arg(Visitor&& vis, basic_format_arg arg); + +#include +#include +#include + +#include "test_macros.h" + +void test(const auto& store) { + for (const auto& arg : store.__args) { + assert(arg); + assert(static_cast(arg)); + } +} + +template +void test() { + using Context = std::basic_format_context; + { + std::basic_format_arg format_arg{}; + ASSERT_NOEXCEPT(!format_arg); + assert(!format_arg); + ASSERT_NOEXCEPT(static_cast(format_arg)); + assert(!static_cast(format_arg)); + } + test(std::make_format_args()); + test(std::make_format_args(1)); + test(std::make_format_args(1, 'c')); + test(std::make_format_args(1, 'c', nullptr)); +} + +void test() { + test(); + test(); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp @@ -0,0 +1,306 @@ +//===----------------------------------------------------------------------===// +// 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 + +// 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 + +// + +// template +// see below visit_format_arg(Visitor&& vis, basic_format_arg arg); + +#include +#include +#include + +#include "test_macros.h" +#include "make_string.h" + +template +void test(From value) { + auto format_args = std::make_format_args(value); + assert(format_args.__args.size() == 1); + assert(format_args.__args[0]); + auto result = std::visit_format_arg( + [v = To(value)](auto&& a) -> To { + if constexpr (std::is_same_v>) { + assert(v == a); + return a; + } else { + assert(false); + return 0; + } + }, + format_args.__args[0]); + + using ct = std::common_type_t; + assert(static_cast(result) == static_cast(value)); +} + +template +void test() { + using Context = std::basic_format_context; + std::basic_string empty; + std::basic_string str = MAKE_STRING(CharT, "abc"); + + // Test boolean types. + + test(true); + test(false); + + // Test CharT types. + + test('a'); + test('z'); + test('0'); + test('9'); + + // Test char types. + + if (std::is_same_v) { + // char to char -> char + test('a'); + test('z'); + test('0'); + test('9'); + } else { + if (std::is_same_v) { + // char to wchar_t -> wchar_t + test('a'); + test('z'); + test('0'); + test('9'); + } else if (std::is_signed_v) { + // char to CharT -> int + // This happens when CharT is a char8_t, char16_t, or char32_t and char + // is a signed type. + // Note if sizeof(CharT) > sizeof(int) this test fails. If there are + // platforms where that occurs extra tests need to be added for char32_t + // testing it against a long long. + test('a'); + test('z'); + test('0'); + test('9'); + } else { + // char to CharT -> unsigned + // This happens when CharT is a char8_t, char16_t, or char32_t and char + // is an unsigned type. + // Note if sizeof(CharT) > sizeof(unsigned) this test fails. If there are + // platforms where that occurs extra tests need to be added for char32_t + // testing it against an unsigned long long. + test('a'); + test('z'); + test('0'); + test('9'); + } + } + + // Test signed integer types. + + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(0); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + +#ifndef _LIBCPP_HAS_NO_INT128 + test(std::numeric_limits<__int128_t>::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test( + std::numeric_limits::min()); + test(0); + test( + std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits<__int128_t>::max()); +#endif + + // Test unsigned integer types. + + test(0); + test( + std::numeric_limits::max()); + + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test, + unsigned long>(0); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + +#ifndef _LIBCPP_HAS_NO_INT128 + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits<__uint128_t>::max()); +#endif + + // Test floating point types. + + test(-std::numeric_limits::max()); + test(-std::numeric_limits::min()); + test(-0.0); + test(0.0); + test(std::numeric_limits::min()); + test(std::numeric_limits::max()); + + test(-std::numeric_limits::max()); + test(-std::numeric_limits::min()); + test(-0.0); + test(0.0); + test(std::numeric_limits::min()); + test(std::numeric_limits::max()); + + test( + -std::numeric_limits::max()); + test( + -std::numeric_limits::min()); + test(-0.0); + test(0.0); + test( + std::numeric_limits::min()); + test( + std::numeric_limits::max()); + + // Test const CharT pointer types. + + test(empty.c_str()); + test(str.c_str()); + + // Test string_view types. + + test>(std::basic_string_view()); + test, std::basic_string_view>( + empty); + test, std::basic_string_view>( + str); + + // Test string types. + + test>(std::basic_string()); + test, std::basic_string>(empty); + test, std::basic_string>(str); + + // Test pointer types. + + test(nullptr); +} + +void test() { + test(); + test(); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// basic_format_args() noexcept; +// template +// basic_format_args(const format-arg-store& store) noexcept; + +#include +#include + +#include "test_macros.h" + +template +void test() { + using Context = std::basic_format_context; + { + ASSERT_NOEXCEPT(std::basic_format_args{}); + + std::basic_format_args format_args{}; + assert(!format_args.get(0)); + } + { + auto store = std::make_format_args(1); + ASSERT_NOEXCEPT(std::basic_format_args{store}); + std::basic_format_args format_args{store}; + assert(format_args.get(0)); + assert(!format_args.get(1)); + } + { + auto store = std::make_format_args(1, 'c'); + ASSERT_NOEXCEPT(std::basic_format_args{store}); + std::basic_format_args format_args{store}; + assert(format_args.get(0)); + assert(format_args.get(1)); + assert(!format_args.get(2)); + } + { + auto store = std::make_format_args(1, 'c', nullptr); + ASSERT_NOEXCEPT(std::basic_format_args{store}); + std::basic_format_args format_args{store}; + assert(format_args.get(0)); + assert(format_args.get(1)); + assert(format_args.get(2)); + assert(!format_args.get(3)); + } +} + +void test() { + test(); + test(); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.args/get.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.args/get.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.args/get.pass.cpp @@ -0,0 +1,310 @@ +//===----------------------------------------------------------------------===// +// 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 + +// 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 + +// + +// basic_format_arg get(size_t i) const noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "make_string.h" + +template +void test(From value) { + auto store = std::make_format_args(value); + const std::basic_format_args format_args{store}; + + std::visit_format_arg( + [v = To(value)](auto&& a) { + if constexpr (std::is_same_v>) + assert(v == a); + else + assert(false); + }, + format_args.get(0)); +} + +template +void test() { + using Context = std::basic_format_context; + { + const std::basic_format_args format_args{}; + ASSERT_NOEXCEPT(format_args.get(0)); + assert(!format_args.get(0)); + } + + using char_type = typename Context::char_type; + std::basic_string empty; + std::basic_string str = MAKE_STRING(char_type, "abc"); + + // Test boolean types. + + test(true); + test(false); + + // Test char_type types. + + test('a'); + test('z'); + test('0'); + test('9'); + + // Test char types. + + if (std::is_same_v) { + // char to char -> char + test('a'); + test('z'); + test('0'); + test('9'); + } else { + if (std::is_same_v) { + // char to wchar_t -> wchar_t + test('a'); + test('z'); + test('0'); + test('9'); + } else if (std::is_signed_v) { + // char to char_type -> int + // This happens when Context::char_type is a char8_t, char16_t, or + // char32_t and char is a signed type. + // Note if sizeof(char_type) > sizeof(int) this test fails. If there are + // platforms where that occurs extra tests need to be added for char32_t + // testing it against a long long. + test('a'); + test('z'); + test('0'); + test('9'); + } else { + // char to char_type -> unsigned + // This happens when Context::char_type is a char8_t, char16_t, or + // char32_t and char is an unsigned type. + // Note if sizeof(char_type) > sizeof(unsigned) this test fails. If there + // are platforms where that occurs extra tests need to be added for + // char32_t testing it against an unsigned long long. + test('a'); + test('z'); + test('0'); + test('9'); + } + } + + // Test signed integer types. + + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(0); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + +#ifndef _LIBCPP_HAS_NO_INT128 + test(std::numeric_limits<__int128_t>::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test( + std::numeric_limits::min()); + test(0); + test( + std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits<__int128_t>::max()); +#endif + + // Test unsigned integer types. + + test(0); + test( + std::numeric_limits::max()); + + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test, + unsigned long>(0); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + +#ifndef _LIBCPP_HAS_NO_INT128 + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits<__uint128_t>::max()); +#endif + + // Test floating point types. + + test(-std::numeric_limits::max()); + test(-std::numeric_limits::min()); + test(-0.0); + test(0.0); + test(std::numeric_limits::min()); + test(std::numeric_limits::max()); + + test(-std::numeric_limits::max()); + test(-std::numeric_limits::min()); + test(-0.0); + test(0.0); + test(std::numeric_limits::min()); + test(std::numeric_limits::max()); + + test( + -std::numeric_limits::max()); + test( + -std::numeric_limits::min()); + test(-0.0); + test(0.0); + test( + std::numeric_limits::min()); + test( + std::numeric_limits::max()); + + // Test const char_type pointer types. + + test(empty.c_str()); + test(str.c_str()); + + // Test string_view types. + + test>( + std::basic_string_view()); + test, + std::basic_string_view>(empty); + test, + std::basic_string_view>(str); + + // Test string types. + + test>( + std::basic_string()); + test, + std::basic_string>(empty); + test, + std::basic_string>(str); + + // Test pointer types. + + test(nullptr); +} + +void test() { + test(); + test(); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.args/types.compile.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.args/types.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.args/types.compile.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// Namespace std typedefs: +// using format_args = basic_format_args; +// using wformat_args = basic_format_args; +// template +// using format_args_t = basic_format_args>; + +#include +#include +#include + +#include "test_macros.h" + +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +static_assert(std::is_same_v< + std::format_args_t, char>, + std::basic_format_args, char>>>); + +static_assert( + std::is_same_v< + std::format_args_t, wchar_t>, + std::basic_format_args, wchar_t>>>); + +static_assert( + std::is_same_v< + std::format_args_t>, char>, + std::basic_format_args>, char>>>); + +// Required for MSVC internal test runner compatibility. +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/advance_to.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/advance_to.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/advance_to.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// void advance_to(iterator it); + +#include +#include + +#include "test_macros.h" + +template +void test( + std::basic_format_args> args) { + { + std::basic_string str[3]; + std::basic_format_context context{OutIt{str[0]}, args}; + context.out() = CharT('a'); + context.advance_to(OutIt{str[1]}); + context.out() = CharT('b'); + context.advance_to(OutIt{str[2]}); + context.out() = CharT('c'); + + assert(str[0].size() == 1); + assert(str[0].front() == CharT('a')); + assert(str[1].size() == 1); + assert(str[1].front() == CharT('b')); + assert(str[2].size() == 1); + assert(str[2].front() == CharT('c')); + } +} + +void test() { + test(std::basic_format_args( + std::make_format_args>, char>>())); + + test(std::basic_format_args( + std::make_format_args>, wchar_t>>())); +#ifndef _LIBCPP_HAS_NO_CHAR8_T + test(std::basic_format_args( + std::make_format_args>, char8_t>>())); +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test(std::basic_format_args( + std::make_format_args>, + char16_t>>())); + test(std::basic_format_args( + std::make_format_args>, + char32_t>>())); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/arg.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/arg.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/arg.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// basic_format_arg arg(size_t id) const; + +#include +#include + +#include "test_macros.h" +#include "make_string.h" + +template +void test() { + std::basic_string string = MAKE_STRING(CharT, "string"); + auto store = + std::make_format_args, CharT>( + true, CharT('a'), 42, string); + std::basic_format_args args = store; + + std::basic_string str; + { + const std::basic_format_context context{OutIt{str}, args}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) { + assert(context.arg(i)); + assert(context.arg(i) == args.get(i)); + } + assert(!context.arg(args.__size())); + } +} + +int main(int, char**) { + test>, char>(); + test>, wchar_t>(); +#ifndef _LIBCPP_HAS_NO_CHAR8_T + test>, char8_t>(); +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test>, char16_t>(); + test>, char32_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/ctor.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/ctor.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// 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-localization + +// REQUIRES: locale.en_US.UTF-8 +// REQUIRES: locale.fr_FR.UTF-8 + +// + +// The Standard does not specifiy a constructor +// basic_format_context(Out out, +// basic_format_args args, +// std::optional&& loc = std::nullopt); +// If compliled with -D_LIBCPP_HAS_NO_LOCALIZATION +// basic_format_context(Out out, +// basic_format_args args); + +#include +#include +#include + +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +template +void test() { + static_assert( + !std::is_copy_constructible_v>); + static_assert( + !std::is_copy_assignable_v>); + // The move operations are implicitly deleted due to the + // deleted copy operations. + static_assert( + !std::is_move_constructible_v>); + static_assert( + !std::is_move_assignable_v>); + + std::basic_string string = MAKE_STRING(CharT, "string"); + std::basic_format_args args = + std::make_format_args, CharT>( + true, CharT('a'), 42, string); + + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.front() == CharT('a')); + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + assert(context.locale() == std::locale()); +#endif + } + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + std::locale en_US{LOCALE_en_US_UTF_8}; + std::locale fr_FR{LOCALE_fr_FR_UTF_8}; + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args, en_US}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.front() == CharT('a')); + + assert(context.locale() != fr_FR); + assert(context.locale() == en_US); + } + + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args, fr_FR}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.front() == CharT('a')); + + assert(context.locale() == fr_FR); + assert(context.locale() != en_US); + } +#endif +} + +void test() { + test>, char>(); + test>, wchar_t>(); +#ifndef _LIBCPP_HAS_NO_CHAR8_T + test>, char8_t>(); +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test>, char16_t>(); + test>, char32_t>(); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/locale.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/locale.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/locale.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// 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-localization + +// REQUIRES: locale.en_US.UTF-8 +// REQUIRES: locale.fr_FR.UTF-8 + +// + +// std::locale locale(); + +#include +#include + +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +template +void test() { + std::locale en_US{LOCALE_en_US_UTF_8}; + std::locale fr_FR{LOCALE_fr_FR_UTF_8}; + std::basic_string string = MAKE_STRING(CharT, "string"); + std::basic_format_args args = + std::make_format_args, CharT>( + true, CharT('a'), 42, string); + + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args, en_US}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.front() == CharT('a')); + + assert(context.locale() != fr_FR); + assert(context.locale() == en_US); + } + + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args, fr_FR}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.front() == CharT('a')); + + assert(context.locale() == fr_FR); + assert(context.locale() != en_US); + } +} + +void test() { + test>, char>(); + test>, wchar_t>(); +#ifndef _LIBCPP_HAS_NO_CHAR8_T + test>, char8_t>(); +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test>, char16_t>(); + test>, char32_t>(); +#endif +} +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/out.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/out.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/out.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// iterator out(); + +#include +#include + +#include "test_macros.h" + +template +void test( + std::basic_format_args> args) { + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args}; + context.out() = CharT('a'); + context.out() = CharT('b'); + context.out() = CharT('c'); + + assert(str.size() == 3); + assert(str[0] == CharT('a')); + assert(str[1] == CharT('b')); + assert(str[2] == CharT('c')); + } +} + +void test() { + test(std::basic_format_args( + std::make_format_args>, char>>())); + test(std::basic_format_args( + std::make_format_args>, wchar_t>>())); +#ifndef _LIBCPP_HAS_NO_CHAR8_T + test(std::basic_format_args( + std::make_format_args>, char8_t>>())); +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test(std::basic_format_args( + std::make_format_args>, + char16_t>>())); + test(std::basic_format_args( + std::make_format_args>, + char32_t>>())); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/types.compile.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/types.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/types.compile.pass.cpp @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// Class typedefs: +// template +// class basic_format_context { +// public: +// using iterator = Out +// using char_type = charT; +// template using formatter_type = formatter; +// } +// +// Namespace std typedefs: +// using format_context = basic_format_context; +// using wformat_context = basic_format_context; + +#include +#include + +#include "test_macros.h" + +template +constexpr void test() { + static_assert( + std::is_same_v::iterator, + OutIt>); + static_assert( + std::is_same_v< + typename std::basic_format_context::char_type, CharT>); + static_assert(std::is_same_v::template formatter_type, + std::formatter>); + static_assert( + std::is_same_v::template formatter_type, + std::formatter>); + static_assert(std::is_same_v::template formatter_type, + std::formatter>); + static_assert( + std::is_same_v::template formatter_type, + std::formatter>); + static_assert( + std::is_same_v::template formatter_type, + std::formatter>); + static_assert( + std::is_same_v:: + template formatter_type, + std::formatter>); +#ifndef _LIBCPP_HAS_NO_INT128 + static_assert( + std::is_same_v::template formatter_type<__int128_t>, + std::formatter<__int128_t, CharT>>); + static_assert( + std::is_same_v::template formatter_type<__uint128_t>, + std::formatter<__uint128_t, CharT>>); +#endif + static_assert( + std::is_same_v::template formatter_type, + std::formatter>); + static_assert( + std::is_same_v::template formatter_type, + std::formatter>); + static_assert( + std::is_same_v::template formatter_type, + std::formatter>); + static_assert( + std::is_same_v::template formatter_type, + std::formatter>); + static_assert( + std::is_same_v:: + template formatter_type>, + std::formatter, CharT>>); + static_assert( + std::is_same_v::template formatter_type, + std::formatter>); +} + +constexpr void test() { + test>, char>(); + test>, wchar_t>(); + test>, char8_t>(); + test>, char16_t>(); + test>, char32_t>(); +} + +static_assert(std::is_same_v< + std::format_context, + std::basic_format_context< + std::back_insert_iterator>, char>>); +static_assert( + std::is_same_v< + std::wformat_context, + std::basic_format_context< + std::back_insert_iterator>, wchar_t>>); + +// Required for MSVC internal test runner compatibility. +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/check_arg_id.verify.cpp b/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/check_arg_id.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/check_arg_id.verify.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// 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 + +// constexpr void check_arg_id(size_t id); + +#include + +#include "test_macros.h" + +constexpr bool test() { + // [format.parse.ctx]/11 + // Remarks: Call expressions where id >= num_args_ are not + // core constant expressions ([expr.const]). + std::format_parse_context context("", 0); + context.check_arg_id(1); + + return true; +} + +int main(int, char**) { + // expected-error@+1 {{static_assert expression is not an integral constant expression}} + static_assert(test()); + + return 0; +}