[libcxx-commits] [libcxx] d7444d9 - [libc++][format] Implement formatters.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Sat Sep 4 02:41:29 PDT 2021


Author: Mark de Wever
Date: 2021-09-04T11:41:08+02:00
New Revision: d7444d9f41e34886d7d316659090ba6bf4d61cba

URL: https://github.com/llvm/llvm-project/commit/d7444d9f41e34886d7d316659090ba6bf4d61cba
DIFF: https://github.com/llvm/llvm-project/commit/d7444d9f41e34886d7d316659090ba6bf4d61cba.diff

LOG: [libc++][format] Implement formatters.

This implements the initial version of the `std::formatter` class and its specializations. It also implements the following formatting functions:
- `format`
- `vformat`
- `format_to`
- `vformat_to`
- `format_to_n`
- `formatted_size`

All functions have a `char` and `wchar_t` version. Parsing the format-spec and
using the parsed format-spec hasn't been implemented. The code isn't optimized,
neither for speed, nor for size.

The goal is to have the rudimentary basics working, which can be used as a
basis to improve upon. The formatters used in this commit are simple stubs that
will be replaced by real formatters in later commits.

The formatters that are slated to be replaced in this patch series don't have
an availability macro to avoid merge conflicts.

Note the formatter for `bool` uses `0` and `1` instead of "false" and
"true". This will be fixed when the stub is replaced with a real
formatter.

Implements parts of:
- P0645 Text Formatting

Completes:
- LWG3539 format_to must not copy models of output_iterator<const charT&>

Reviewed By: ldionne, #libc, vitaut

Differential Revision: https://reviews.llvm.org/D96664

Added: 
    libcxx/include/__format/format_string.h
    libcxx/include/__format/formatter.h
    libcxx/test/libcxx/diagnostics/detail.headers/format/format_string.module.verify.cpp
    libcxx/test/libcxx/diagnostics/detail.headers/format/formatter.module.verify.cpp
    libcxx/test/libcxx/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp
    libcxx/test/libcxx/utilities/format/format.arguments/format.args/get.pass.cpp
    libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.bool.pass.cpp
    libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.c_string.pass.cpp
    libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.char.pass.cpp
    libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.const_char_array.pass.cpp
    libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp
    libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.signed_integral.pass.cpp
    libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.string.pass.cpp
    libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.unsigned_integral.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format_tests.h
    libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp
    libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp
    libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
    libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp

Modified: 
    libcxx/docs/ReleaseNotes.rst
    libcxx/include/CMakeLists.txt
    libcxx/include/format
    libcxx/include/module.modulemap
    libcxx/test/std/utilities/format/format.arguments/format.arg/operator_bool.pass.cpp

Removed: 
    libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp
    libcxx/test/std/utilities/format/format.arguments/format.args/get.pass.cpp


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index a70f012505537..f8b428c3f0c09 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -38,7 +38,10 @@ What's New in Libc++ 14.0.0?
 New Features
 ------------
 
-- ...
+- There's initial support for the C++20 header ``<format>``. The implementation
+  is incomplete. Some functions are known to be inefficient; both in memory
+  usage and performance. The implementation is considered experimental and isn't
+  considered ABI stable.
 
 API Changes
 -----------

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 33bc1ec0a6141..3a926e68d52ef 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -134,6 +134,8 @@ set(files
   __format/format_error.h
   __format/format_fwd.h
   __format/format_parse_context.h
+  __format/format_string.h
+  __format/formatter.h
   __function_like.h
   __functional_base
   __functional/binary_function.h

diff  --git a/libcxx/include/__format/format_string.h b/libcxx/include/__format/format_string.h
new file mode 100644
index 0000000000000..864053f64cde8
--- /dev/null
+++ b/libcxx/include/__format/format_string.h
@@ -0,0 +1,174 @@
+// -*- 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_STRING_H
+#define _LIBCPP___FORMAT_FORMAT_STRING_H
+
+#include <__config>
+#include <__debug>
+#include <__format/format_error.h>
+#include <cstddef>
+#include <cstdint>
+
+#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)
+
+namespace __format {
+
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS __parse_number_result {
+  const _CharT* __ptr;
+  uint32_t __value;
+};
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_number(const _CharT* __begin, const _CharT* __end);
+
+/**
+ * The maximum value of a numeric argument.
+ *
+ * This is used for:
+ * * arg-id
+ * * width as value or arg-id.
+ * * precision as value or arg-id.
+ *
+ * The value is compatible with the maximum formatting width and precision
+ * using the `%*` syntax on a 32-bit system.
+ */
+inline constexpr uint32_t __number_max = INT32_MAX;
+
+namespace __detail {
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_zero(const _CharT* __begin, const _CharT*, auto& __parse_ctx) {
+  __parse_ctx.check_arg_id(0);
+  return {++__begin, 0}; // can never be larger than the maximum.
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_automatic(const _CharT* __begin, const _CharT*, auto& __parse_ctx) {
+  size_t __value = __parse_ctx.next_arg_id();
+  _LIBCPP_ASSERT(__value <= __number_max,
+                 "Compilers don't support this number of arguments");
+
+  return {__begin, uint32_t(__value)};
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_manual(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
+  __parse_number_result<_CharT> __r = __parse_number(__begin, __end);
+  __parse_ctx.check_arg_id(__r.__value);
+  return __r;
+}
+
+} // namespace __detail
+
+/**
+ * Parses a number.
+ *
+ * The number is used for the 31-bit values @em width and @em precision. This
+ * allows a maximum value of 2147483647.
+ */
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_number(const _CharT* __begin, const _CharT* __end_input) {
+  static_assert(__format::__number_max == INT32_MAX,
+                "The algorithm is implemented based on this value.");
+  /*
+   * Limit the input to 9 digits, otherwise we need two checks during every
+   * iteration:
+   * - Are we at the end of the input?
+   * - Does the value exceed width of an uint32_t? (Switching to uint64_t would
+   *   have the same issue, but with a higher maximum.)
+   */
+  const _CharT* __end = __end_input - __begin > 9 ? __begin + 9 : __end_input;
+  uint32_t __value = *__begin - _CharT('0');
+  while (++__begin != __end) {
+    if (*__begin < _CharT('0') || *__begin > _CharT('9'))
+      return {__begin, __value};
+
+    __value = __value * 10 + *__begin - _CharT('0');
+  }
+
+  if (__begin != __end_input && *__begin >= _CharT('0') &&
+      *__begin <= _CharT('9')) {
+
+    /*
+     * There are more than 9 digits, do additional validations:
+     * - Does the 10th digit exceed the maximum allowed value?
+     * - Are there more than 10 digits?
+     * (More than 10 digits always overflows the maximum.)
+     */
+    uint64_t __v = uint64_t(__value) * 10 + *__begin++ - _CharT('0');
+    if (__v > __number_max ||
+        (__begin != __end_input && *__begin >= _CharT('0') &&
+         *__begin <= _CharT('9')))
+      __throw_format_error("The numeric value of the format-spec is too large");
+
+    __value = __v;
+  }
+
+  return {__begin, __value};
+}
+
+/**
+ * Multiplexer for all parse functions.
+ *
+ * The parser will return a pointer beyond the last consumed character. This
+ * should be the closing '}' of the arg-id.
+ */
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_arg_id(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
+  switch (*__begin) {
+  case _CharT('0'):
+    return __detail::__parse_zero(__begin, __end, __parse_ctx);
+
+  case _CharT(':'):
+    // This case is conditionally valid. It's allowed in an arg-id in the
+    // replacement-field, but not in the std-format-spec. The caller can
+    // provide a better diagnostic, so accept it here unconditionally.
+  case _CharT('}'):
+    return __detail::__parse_automatic(__begin, __end, __parse_ctx);
+  }
+  if (*__begin < _CharT('0') || *__begin > _CharT('9'))
+    __throw_format_error(
+        "The arg-id of the format-spec starts with an invalid character");
+
+  return __detail::__parse_manual(__begin, __end, __parse_ctx);
+}
+
+} // namespace __format
+
+#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___FORMAT_FORMAT_STRING_H

diff  --git a/libcxx/include/__format/formatter.h b/libcxx/include/__format/formatter.h
new file mode 100644
index 0000000000000..2aec2f4e28466
--- /dev/null
+++ b/libcxx/include/__format/formatter.h
@@ -0,0 +1,64 @@
+// -*- 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_FORMATTER_H
+#define _LIBCPP___FORMAT_FORMATTER_H
+
+#include <__availability>
+#include <__config>
+#include <__format/format_error.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)
+
+// Currently not implemented specializations throw an exception when used. This
+// does not conform to the Standard. However not all Standard defined formatters
+// have been implemented yet. Until that time the current behavior is intended.
+// TODO FMT Disable the default template.
+template <class _Tp, class _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter {
+  _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto parse(auto& __parse_ctx)
+      -> decltype(__parse_ctx.begin()) {
+    __throw();
+  }
+
+  _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto format(_Tp, auto& __ctx)
+      -> decltype(__ctx.out()) {
+    __throw();
+  }
+
+private:
+  _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void __throw() {
+    __throw_format_error("Argument type not implemented yet");
+  }
+};
+
+#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___FORMAT_FORMATTER_H

diff  --git a/libcxx/include/format b/libcxx/include/format
index b320b75b7d9ec..90547e2ce8daf 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -54,6 +54,85 @@ namespace std {
   template<class Out, class charT>
     using format_args_t = basic_format_args<basic_format_context<Out, charT>>;
 
+  // [format.functions], formatting functions
+  template<class... Args>
+    string format(string_view fmt, const Args&... args);
+  template<class... Args>
+    wstring format(wstring_view fmt, const Args&... args);
+  template<class... Args>
+    string format(const locale& loc, string_view fmt, const Args&... args);
+  template<class... Args>
+    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<class Out, class... Args>
+    Out format_to(Out out, string_view fmt, const Args&... args);
+  template<class Out, class... Args>
+    Out format_to(Out out, wstring_view fmt, const Args&... args);
+  template<class Out, class... Args>
+    Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args);
+  template<class Out, class... Args>
+    Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args);
+
+  template<class Out>
+    Out vformat_to(Out out, string_view fmt,
+                   format_args_t<type_identity_t<Out>, char> args);
+  template<class Out>
+    Out vformat_to(Out out, wstring_view fmt,
+                   format_args_t<type_identity_t<Out>, wchar_t> args);
+  template<class Out>
+    Out vformat_to(Out out, const locale& loc, string_view fmt,
+                   format_args_t<type_identity_t<Out>, char> args);
+  template<class Out>
+    Out vformat_to(Out out, const locale& loc, wstring_view fmt,
+                   format_args_t<type_identity_t<Out>, wchar_t> args);
+
+  template<class Out> struct format_to_n_result {
+    Out out;
+    iter_
diff erence_t<Out> size;
+  };
+
+ template<class Out, class... Args>
+    format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
+                                        string_view fmt, const Args&... args);
+  template<class Out, class... Args>
+    format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
+                                        wstring_view fmt, const Args&... args);
+  template<class Out, class... Args>
+    format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
+                                        const locale& loc, string_view fmt,
+                                        const Args&... args);
+  template<class Out, class... Args>
+    format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
+                                        const locale& loc, wstring_view fmt,
+                                        const Args&... args);
+
+  template<class... Args>
+    size_t formatted_size(string_view fmt, const Args&... args);
+  template<class... Args>
+    size_t formatted_size(wstring_view fmt, const Args&... args);
+  template<class... Args>
+    size_t formatted_size(const locale& loc, string_view fmt, const Args&... args);
+  template<class... Args>
+    size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);
+
+  // [format.formatter], formatter
+  template<> struct formatter<char, char>;
+  template<> struct formatter<char, wchar_t>;
+  template<> struct formatter<wchar_t, wchar_t>;
+
+  template<> struct formatter<charT*, charT>;
+  template<> struct formatter<const charT*, charT>;
+  template<size_t N> struct formatter<const charT[N], charT>;
+  template<class traits, class Allocator>
+    struct formatter<basic_string<charT, traits, Allocator>, charT>;
+  template<class traits>
+    struct formatter<basic_string_view<charT, traits>, charT>;
+
   // [format.parse.ctx], class template basic_format_parse_context
   template<class charT>
   class basic_format_parse_context {
@@ -191,17 +270,32 @@ namespace std {
 #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
 
 #include <__config>
+#include <__debug>
 #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 <__format/format_string.h>
+#include <__format/formatter.h>
+#include <__variant/monostate.h>
 #include <array>
+#include <concepts>
+#include <string>
+#include <string_view>
+#include <type_traits>
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+#include <locale>
+#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
@@ -241,11 +335,604 @@ make_wformat_args(const _Args&... __args) {
   return _VSTD::make_format_args<wformat_context>(__args...);
 }
 
+namespace __format {
+template <class _Tp, class _CharT>
+struct _LIBCPP_TEMPLATE_VIS __formatter_char {
+  _LIBCPP_HIDE_FROM_ABI
+  auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
+    // TODO FMT Implement this function.
+    return __parse_ctx.begin();
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  auto format(_Tp __c, auto& __ctx) -> decltype(__ctx.out()) {
+    // TODO FMT Implement the parsed formatting arguments.
+    auto __out_it = __ctx.out();
+    *__out_it++ = _CharT(__c);
+    return __out_it;
+  }
+};
+
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS __formatter_c_string {
+  _LIBCPP_HIDE_FROM_ABI
+  auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
+    // TODO FMT Implement this function.
+    return __parse_ctx.begin();
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  auto format(const _CharT* __str, auto& __ctx) -> decltype(__ctx.out()) {
+    // TODO FMT Implement the parsed formatting arguments.
+    auto __out_it = __ctx.out();
+    while (*__str)
+      *__out_it++ = *__str++;
+    return __out_it;
+  }
+};
+
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS __formatter_string {
+  _LIBCPP_HIDE_FROM_ABI
+  auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
+    // TODO FMT Implement this function.
+    return __parse_ctx.begin();
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  auto format(basic_string_view<_CharT> __str, auto& __ctx)
+      -> decltype(__ctx.out()) {
+    // TODO FMT Implement the parsed formatting arguments.
+    auto __out_it = __ctx.out();
+    for (const auto __c : __str)
+      *__out_it++ = __c;
+    return __out_it;
+  }
+};
+
+template <class _Tp, class _CharT>
+requires(is_arithmetic_v<_Tp> &&
+         !same_as<_Tp, bool>) struct _LIBCPP_HIDE_FROM_ABI
+    __formatter_arithmetic {
+  _LIBCPP_HIDE_FROM_ABI
+  auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
+    // TODO FMT Implement
+    return __parse_ctx.begin();
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  auto format(_Tp __value, auto& __ctx) -> decltype(__ctx.out()) {
+    return __handle_format(__value, __ctx);
+  }
+
+private:
+  template <class _Uv>
+  _LIBCPP_HIDDEN static string
+  __convert(_Uv __value) requires(same_as<_CharT, char>) {
+    return _VSTD::to_string(__value);
+  }
+  template <class _Uv>
+  _LIBCPP_HIDDEN static wstring
+  __convert(_Uv __value) requires(same_as<_CharT, wchar_t>) {
+    return _VSTD::to_wstring(__value);
+  }
+
+  template <class _Uv>
+  _LIBCPP_HIDDEN auto __handle_format(_Uv __value, auto& __ctx)
+      -> decltype(__ctx.out())
+#ifndef _LIBCPP_HAS_NO_INT128
+          requires(!same_as<_Uv, __int128_t> && !same_as<_Uv, __uint128_t>)
+#endif
+  {
+    // TODO FMT Implement using formatting arguments
+    // TODO FMT Improve PoC since using std::to_string is inefficient.
+    // Note the code doesn't use std::string::iterator since the unit tests
+    // test with debug iterators and they fail with strings created from
+    // std::to_string.
+    auto __str = __convert(__value);
+    auto __out_it = __ctx.out();
+    for (size_t __i = 0, __e = __str.size(); __i != __e; ++__i)
+      *__out_it++ = __str[__i];
+    return __out_it;
+  }
+#ifndef _LIBCPP_HAS_NO_INT128
+  template <class _Uv>
+  _LIBCPP_HIDDEN auto __handle_format(_Uv __value, auto& __ctx)
+      -> decltype(__ctx.out()) requires(same_as<_Uv, __int128_t> ||
+                                        same_as<_Uv, __uint128_t>) {
+    using _To = conditional_t<is_signed_v<_Uv>, long long, unsigned long long>;
+    // TODO FMT Implement full 128-bit support.
+    if (__value < numeric_limits<_To>::min() ||
+        __value > numeric_limits<_To>::max())
+      __throw_format_error("128-bit value is outside of implemented range");
+
+    return __handle_format(static_cast<_To>(__value), __ctx);
+  }
+#endif
+};
+} // namespace __format
+
+// These specializations are helper stubs and not proper formatters.
+// TODO FMT Implement the proper formatter specializations.
+
+// [format.formatter.spec]/2.1 The specializations
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS formatter<char, char>
+    : public __format::__formatter_char<char, char> {};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS formatter<char, wchar_t>
+    : public __format::__formatter_char<char, wchar_t> {};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS formatter<wchar_t, wchar_t>
+    : public __format::__formatter_char<wchar_t, wchar_t> {};
+
+// [format.formatter.spec]/2.2 For each charT, the string type specializations
+
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT>
+    : public __format::__formatter_c_string<_CharT> {
+  using _Base = __format::__formatter_c_string<_CharT>;
+
+  _LIBCPP_HIDE_FROM_ABI auto format(_CharT* __str, auto& __ctx)
+      -> decltype(__ctx.out()) {
+    _LIBCPP_ASSERT(__str, "The basic_format_arg constructor should have "
+                          "prevented an invalid pointer");
+    return _Base::format(__str, __ctx);
+  }
+};
+
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT*, _CharT>
+    : public __format::__formatter_c_string<_CharT> {};
+
+template <class _CharT, size_t _Size>
+struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT[_Size], _CharT>
+    : public __format::__formatter_string<_CharT> {
+  using _Base = __format::__formatter_string<_CharT>;
+
+  _LIBCPP_HIDE_FROM_ABI auto format(const _CharT __str[_Size], auto& __ctx)
+      -> decltype(__ctx.out()) {
+    return _Base::format(_VSTD::basic_string_view<_CharT>(__str, _Size), __ctx);
+  }
+};
+
+template <class _CharT, class _Traits, class _Allocator>
+struct _LIBCPP_TEMPLATE_VIS
+    formatter<basic_string<_CharT, _Traits, _Allocator>, _CharT>
+    : public __format::__formatter_string<_CharT> {
+  using _Base = __format::__formatter_string<_CharT>;
+
+  _LIBCPP_HIDE_FROM_ABI auto
+  format(const basic_string<_CharT, _Traits, _Allocator>& __str, auto& __ctx)
+      -> decltype(__ctx.out()) {
+    return _Base::format(_VSTD::basic_string_view<_CharT>(__str), __ctx);
+  }
+};
+
+template <class _CharT, class _Traits>
+struct _LIBCPP_TEMPLATE_VIS
+    formatter<basic_string_view<_CharT, _Traits>, _CharT>
+    : public __format::__formatter_string<_CharT> {};
+
+// [format.formatter.spec]/2.3
+// For each charT, for each cv-unqualified arithmetic type ArithmeticT other
+// than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
+
+// Boolean.
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<bool, _CharT> {
+  _LIBCPP_HIDE_FROM_ABI
+  auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
+    // TODO FMT Implement
+    return __parse_ctx.begin();
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  auto format(bool __b, auto& __ctx) -> decltype(__ctx.out()) {
+    // TODO FMT Implement using formatting arguments
+    auto __out_it = __ctx.out();
+    *__out_it++ = _CharT('0') + __b;
+    return __out_it;
+  }
+};
+
+// Signed integral types.
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<signed char, _CharT>
+    : public __format::__formatter_arithmetic<signed char, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<short, _CharT>
+    : public __format::__formatter_arithmetic<short, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<int, _CharT>
+    : public __format::__formatter_arithmetic<int, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<long, _CharT>
+    : public __format::__formatter_arithmetic<long, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<long long, _CharT>
+    : public __format::__formatter_arithmetic<long long, _CharT> {};
+#ifndef _LIBCPP_HAS_NO_INT128
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<__int128_t, _CharT>
+    : public __format::__formatter_arithmetic<__int128_t, _CharT> {};
+#endif
+
+// Unsigned integral types.
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<unsigned char, _CharT>
+    : public __format::__formatter_arithmetic<unsigned char, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<unsigned short, _CharT>
+    : public __format::__formatter_arithmetic<unsigned short, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<unsigned, _CharT>
+    : public __format::__formatter_arithmetic<unsigned, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long, _CharT>
+    : public __format::__formatter_arithmetic<unsigned long, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long long, _CharT>
+    : public __format::__formatter_arithmetic<unsigned long long, _CharT> {};
+#ifndef _LIBCPP_HAS_NO_INT128
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<__uint128_t, _CharT>
+    : public __format::__formatter_arithmetic<__uint128_t, _CharT> {};
+#endif
+
+// Floating point types.
+// TODO FMT There are no replacements for the floating point stubs due to not
+// having floating point support in std::to_chars yet. These stubs aren't
+// removed since they are useful for developing the real versions.
+// Ultimately the stubs should be implemented properly and this code can be
+// removed.
+#if 0
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<float, _CharT>
+    : public __format::__formatter_arithmetic<float, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT
+    formatter<double, _CharT>
+    : public __format::__formatter_arithmetic<double, _CharT> {};
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT
+    formatter<long double, _CharT>
+    : public __format::__formatter_arithmetic<long double, _CharT> {};
+#endif
+
+namespace __format {
+
+template <class _CharT, class _ParseCtx, class _Ctx>
+_LIBCPP_HIDE_FROM_ABI const _CharT*
+__handle_replacement_field(const _CharT* __begin, const _CharT* __end,
+                           _ParseCtx& __parse_ctx, _Ctx& __ctx) {
+  __format::__parse_number_result __r =
+      __format::__parse_arg_id(__begin, __end, __parse_ctx);
+
+  switch (*__r.__ptr) {
+  case _CharT(':'):
+    // The arg-id has a format-specifier, advance the input to the format-spec.
+    __parse_ctx.advance_to(__r.__ptr + 1);
+    break;
+  case _CharT('}'):
+    // The arg-id has no format-specifier.
+    __parse_ctx.advance_to(__r.__ptr);
+    break;
+  default:
+    __throw_format_error(
+        "The replacement field arg-id should terminate at a ':' or '}'");
+  }
+
+  _VSTD::visit_format_arg(
+      [&](auto __arg) {
+        if constexpr (same_as<decltype(__arg), monostate>)
+          __throw_format_error("Argument index out of bounds");
+        else {
+          formatter<decltype(__arg), _CharT> __formatter;
+          __parse_ctx.advance_to(__formatter.parse(__parse_ctx));
+          __ctx.advance_to(__formatter.format(__arg, __ctx));
+        }
+      },
+      __ctx.arg(__r.__value));
+
+  __begin = __parse_ctx.begin();
+  if (__begin == __end || *__begin != _CharT('}'))
+    __throw_format_error("The replacement field misses a terminating '}'");
+
+  return ++__begin;
+}
+
+template <class _ParseCtx, class _Ctx>
+_LIBCPP_HIDE_FROM_ABI typename _Ctx::iterator
+__vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
+  using _CharT = typename _ParseCtx::char_type;
+  static_assert(same_as<typename _Ctx::char_type, _CharT>);
+
+  const _CharT* __begin = __parse_ctx.begin();
+  const _CharT* __end = __parse_ctx.end();
+  typename _Ctx::iterator __out_it = __ctx.out();
+  while (__begin != __end) {
+    switch (*__begin) {
+    case _CharT('{'):
+      ++__begin;
+      if (__begin == __end)
+        __throw_format_error("The format string terminates at a '{'");
+
+      if (*__begin != _CharT('{')) [[likely]] {
+        __ctx.advance_to(_VSTD::move(__out_it));
+        __begin =
+            __handle_replacement_field(__begin, __end, __parse_ctx, __ctx);
+        __out_it = __ctx.out();
+
+        // The output is written and __begin points to the next character. So
+        // start the next iteration.
+        continue;
+      }
+      // The string is an escape character.
+      break;
+
+    case _CharT('}'):
+      ++__begin;
+      if (__begin == __end || *__begin != _CharT('}'))
+        __throw_format_error(
+            "The format string contains an invalid escape sequence");
+
+      break;
+    }
+
+    // Copy the character to the output verbatim.
+    *__out_it++ = *__begin++;
+  }
+  return __out_it;
+}
+
+} // namespace __format
+
+template <class _OutIt, class _CharT>
+requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
+    __vformat_to(_OutIt __out_it, basic_string_view<_CharT> __fmt,
+                 format_args_t<type_identity_t<_OutIt>, _CharT> __args) {
+  return __format::__vformat_to(
+      basic_format_parse_context{__fmt, __args.__size()},
+      _VSTD::__format_context_create(_VSTD::move(__out_it), __args));
+}
+
+template <output_iterator<const char&> _OutIt>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+vformat_to(_OutIt __out_it, string_view __fmt,
+           format_args_t<type_identity_t<_OutIt>, char> __args) {
+  return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
+}
+
+template <output_iterator<const wchar_t&> _OutIt>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+vformat_to(_OutIt __out_it, wstring_view __fmt,
+           format_args_t<type_identity_t<_OutIt>, wchar_t> __args) {
+  return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
+}
+
+template <output_iterator<const char&> _OutIt, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+format_to(_OutIt __out_it, string_view __fmt, const _Args&... __args) {
+  return _VSTD::vformat_to(
+      _VSTD::move(__out_it), __fmt,
+      _VSTD::make_format_args<basic_format_context<_OutIt, char>>(__args...));
+}
+
+template <output_iterator<const wchar_t&> _OutIt, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+format_to(_OutIt __out_it, wstring_view __fmt, const _Args&... __args) {
+  return _VSTD::vformat_to(
+      _VSTD::move(__out_it), __fmt,
+      _VSTD::make_format_args<basic_format_context<_OutIt, wchar_t>>(
+          __args...));
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
+vformat(string_view __fmt, format_args __args) {
+  string __res;
+  _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
+  return __res;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
+vformat(wstring_view __fmt, wformat_args __args) {
+  wstring __res;
+  _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
+  return __res;
+}
+
+template <class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
+format(string_view __fmt, const _Args&... __args) {
+  return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...));
+}
+
+template <class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
+format(wstring_view __fmt, const _Args&... __args) {
+  return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...));
+}
+
+template <class _OutIt>
+struct _LIBCPP_TEMPLATE_VIS format_to_n_result {
+  _OutIt out;
+  iter_
diff erence_t<_OutIt> size;
+};
+
+template <output_iterator<const char&> _OutIt, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, string_view __fmt,
+            const _Args&... __args) {
+  // TODO FMT Improve PoC: using std::string is inefficient.
+  string __str = _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...));
+  iter_
diff erence_t<_OutIt> __s = __str.size();
+  iter_
diff erence_t<_OutIt> __m =
+      _VSTD::clamp(__n, iter_
diff erence_t<_OutIt>(0), __s);
+  __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
+  return {_VSTD::move(__out_it), __s};
+}
+
+template <output_iterator<const wchar_t&> _OutIt, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, wstring_view __fmt,
+            const _Args&... __args) {
+  // TODO FMT Improve PoC: using std::string is inefficient.
+  wstring __str = _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...));
+  iter_
diff erence_t<_OutIt> __s = __str.size();
+  iter_
diff erence_t<_OutIt> __m =
+      _VSTD::clamp(__n, iter_
diff erence_t<_OutIt>(0), __s);
+  __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
+  return {_VSTD::move(__out_it), __s};
+}
+
+template <class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(string_view __fmt, const _Args&... __args) {
+  // TODO FMT Improve PoC: using std::string is inefficient.
+  return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)).size();
+}
+
+template <class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(wstring_view __fmt, const _Args&... __args) {
+  // TODO FMT Improve PoC: using std::string is inefficient.
+  return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)).size();
+}
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+
+template <class _OutIt, class _CharT>
+requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
+    __vformat_to(_OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt,
+                 format_args_t<type_identity_t<_OutIt>, _CharT> __args) {
+  return __format::__vformat_to(
+      basic_format_parse_context{__fmt, __args.__size()},
+      _VSTD::__format_context_create(_VSTD::move(__out_it), __args,
+                                     _VSTD::move(__loc)));
+}
+
+template <output_iterator<const char&> _OutIt>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+vformat_to(_OutIt __out_it, locale __loc, string_view __fmt,
+           format_args_t<type_identity_t<_OutIt>, char> __args) {
+  return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
+                             __args);
+}
+
+template <output_iterator<const wchar_t&> _OutIt>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+vformat_to(_OutIt __out_it, locale __loc, wstring_view __fmt,
+           format_args_t<type_identity_t<_OutIt>, wchar_t> __args) {
+  return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
+                             __args);
+}
+
+template <output_iterator<const char&> _OutIt, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to(
+    _OutIt __out_it, locale __loc, string_view __fmt, const _Args&... __args) {
+  return _VSTD::vformat_to(
+      _VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
+      _VSTD::make_format_args<basic_format_context<_OutIt, char>>(__args...));
+}
+
+template <output_iterator<const wchar_t&> _OutIt, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to(
+    _OutIt __out_it, locale __loc, wstring_view __fmt, const _Args&... __args) {
+  return _VSTD::vformat_to(
+      _VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
+      _VSTD::make_format_args<basic_format_context<_OutIt, wchar_t>>(
+          __args...));
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
+vformat(locale __loc, string_view __fmt, format_args __args) {
+  string __res;
+  _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
+                    __args);
+  return __res;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
+vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
+  wstring __res;
+  _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
+                    __args);
+  return __res;
+}
+
+template <class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
+format(locale __loc, string_view __fmt, const _Args&... __args) {
+  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
+                        _VSTD::make_format_args(__args...));
+}
+
+template <class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
+format(locale __loc, wstring_view __fmt, const _Args&... __args) {
+  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
+                        _VSTD::make_wformat_args(__args...));
+}
+
+template <output_iterator<const char&> _OutIt, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc,
+            string_view __fmt, const _Args&... __args) {
+  // TODO FMT Improve PoC: using std::string is inefficient.
+  string __str = _VSTD::vformat(_VSTD::move(__loc), __fmt,
+                                _VSTD::make_format_args(__args...));
+  iter_
diff erence_t<_OutIt> __s = __str.size();
+  iter_
diff erence_t<_OutIt> __m =
+      _VSTD::clamp(__n, iter_
diff erence_t<_OutIt>(0), __s);
+  __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
+  return {_VSTD::move(__out_it), __s};
+}
+
+template <output_iterator<const wchar_t&> _OutIt, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc,
+            wstring_view __fmt, const _Args&... __args) {
+  // TODO FMT Improve PoC: using std::string is inefficient.
+  wstring __str = _VSTD::vformat(_VSTD::move(__loc), __fmt,
+                                 _VSTD::make_wformat_args(__args...));
+  iter_
diff erence_t<_OutIt> __s = __str.size();
+  iter_
diff erence_t<_OutIt> __m =
+      _VSTD::clamp(__n, iter_
diff erence_t<_OutIt>(0), __s);
+  __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
+  return {_VSTD::move(__out_it), __s};
+}
+
+template <class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(locale __loc, string_view __fmt, const _Args&... __args) {
+  // TODO FMT Improve PoC: using std::string is inefficient.
+  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
+                        _VSTD::make_format_args(__args...))
+      .size();
+}
+
+template <class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(locale __loc, wstring_view __fmt, const _Args&... __args) {
+  // TODO FMT Improve PoC: using std::string is inefficient.
+  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
+                        _VSTD::make_wformat_args(__args...))
+      .size();
+}
+
+#endif
+
 #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
 #endif //_LIBCPP_STD_VER > 17
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
 
 #endif // _LIBCPP_FORMAT

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 5ef0f9ade9dfd..ba14615b372bb 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -441,6 +441,8 @@ module std [system] {
       module format_error         { private header "__format/format_error.h"         }
       module format_fwd           { private header "__format/format_fwd.h"           }
       module format_parse_context { private header "__format/format_parse_context.h" }
+      module format_string        { private header "__format/format_string.h"        }
+      module formatter            { private header "__format/formatter.h"            }
     }
   }
   module forward_list {

diff  --git a/libcxx/test/libcxx/diagnostics/detail.headers/format/format_string.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/format/format_string.module.verify.cpp
new file mode 100644
index 0000000000000..c331785f36777
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/format/format_string.module.verify.cpp
@@ -0,0 +1,16 @@
+// -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__format/format_string.h'}}
+#include <__format/format_string.h>

diff  --git a/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter.module.verify.cpp
new file mode 100644
index 0000000000000..4a5b4b380f6bb
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter.module.verify.cpp
@@ -0,0 +1,16 @@
+// -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__format/formatter.h'}}
+#include <__format/formatter.h>

diff  --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp b/libcxx/test/libcxx/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp
rename to libcxx/test/libcxx/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp

diff  --git a/libcxx/test/std/utilities/format/format.arguments/format.args/get.pass.cpp b/libcxx/test/libcxx/utilities/format/format.arguments/format.args/get.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/format/format.arguments/format.args/get.pass.cpp
rename to libcxx/test/libcxx/utilities/format/format.arguments/format.args/get.pass.cpp

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
index 37f97ffcd0c0d..1bf7fdc3503d7 100644
--- 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
@@ -24,10 +24,14 @@
 #include "test_macros.h"
 
 void test(const auto& store) {
+#if _LIBCPP_VERSION
   for (const auto& arg : store.__args) {
     assert(arg);
     assert(static_cast<bool>(arg));
   }
+#else
+  (void)store;
+#endif
 }
 
 template <class CharT>

diff  --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.bool.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.bool.pass.cpp
new file mode 100644
index 0000000000000..9a62d04be37f4
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.bool.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
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+
+// <format>
+
+// [format.formatter.spec]:
+// Each header that declares the template `formatter` provides the following
+// enabled specializations:
+// For each `charT`, for each cv-unqualified arithmetic type `ArithmeticT`
+// other than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
+//    template<> struct formatter<ArithmeticT, charT>
+//
+// This file tests with `ArithmeticT = bool`, for each valid `charT`.
+
+#include <format>
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+
+template <class StringT, class StringViewT>
+void test(StringT expected, StringViewT fmt, bool arg) {
+  using CharT = typename StringT::value_type;
+  auto parse_ctx = std::basic_format_parse_context<CharT>(fmt);
+  std::formatter<bool, CharT> formatter;
+  static_assert(std::semiregular<decltype(formatter)>);
+
+  auto it = formatter.parse(parse_ctx);
+  assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
+
+  StringT result;
+  auto out = std::back_inserter(result);
+  using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
+
+  auto format_ctx = std::__format_context_create<decltype(out), CharT>(
+      out, std::make_format_args<FormatCtxT>(arg));
+  formatter.format(arg, format_ctx);
+  assert(result == expected);
+}
+
+template <class StringT>
+void test_termination_condition(StringT expected, StringT f, bool arg) {
+  // The format-spec is valid if completely consumed or terminates at a '}'.
+  // The valid inputs all end with a '}'. The test is executed twice:
+  // - first with the terminating '}',
+  // - second consuming the entire input.
+  using CharT = typename StringT::value_type;
+  std::basic_string_view<CharT> fmt{f};
+  assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+  test(expected, fmt, arg);
+  fmt.remove_suffix(1);
+  test(expected, fmt, arg);
+}
+
+template <class CharT>
+void test_boolean() {
+  test_termination_condition(STR("1"), STR("}"), true);
+  test_termination_condition(STR("0"), STR("}"), false);
+}
+
+int main(int, char**) {
+  test_boolean<char>();
+  test_boolean<wchar_t>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.c_string.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.c_string.pass.cpp
new file mode 100644
index 0000000000000..7ae578a17bdda
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.c_string.pass.cpp
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+
+// <format>
+
+// [format.formatter.spec]:
+// Each header that declares the template `formatter` provides the following
+// enabled specializations:
+// For each `charT`, the string type specializations
+//   template<> struct formatter<charT*, charT>;
+//   template<> struct formatter<const charT*, charT>;
+
+#include <format>
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+#define CSTR(S) MAKE_CSTRING(CharT, S)
+
+template <class T, class StringT, class StringViewT, class CharT>
+void test(StringT expected, StringViewT fmt, const CharT* a) {
+  auto parse_ctx = std::basic_format_parse_context<CharT>(fmt);
+  std::formatter<T, CharT> formatter;
+  static_assert(std::semiregular<decltype(formatter)>);
+
+  auto it = formatter.parse(parse_ctx);
+  assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
+
+  StringT result;
+  auto out = std::back_inserter(result);
+  using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
+
+  auto* arg = const_cast<T>(a);
+  auto format_ctx = std::__format_context_create<decltype(out), CharT>(
+      out, std::make_format_args<FormatCtxT>(arg));
+  formatter.format(arg, format_ctx);
+  assert(result == expected);
+}
+
+template <class ArgumentT, class StringT, class CharT>
+void test_termination_condition(StringT expected, StringT f, const CharT* arg) {
+  // The format-spec is valid if completely consumed or terminates at a '}'.
+  // The valid inputs all end with a '}'. The test is executed twice:
+  // - first with the terminating '}',
+  // - second consuming the entire input.
+  std::basic_string_view<CharT> fmt{f};
+  assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+  test<ArgumentT>(expected, fmt, arg);
+  fmt.remove_suffix(1);
+  test<ArgumentT>(expected, fmt, arg);
+}
+
+template <class ArgumentT>
+void test_char_pointer() {
+  using CharT = std::remove_cv_t<std::remove_pointer_t<ArgumentT>>;
+
+  test_termination_condition<ArgumentT>(STR(" azAZ09,./<>?"), STR("}"),
+                                        CSTR(" azAZ09,./<>?"));
+
+  std::basic_string<CharT> s(CSTR("abc\0abc"), 7);
+  test_termination_condition<ArgumentT>(STR("abc"), STR("}"), s.c_str());
+}
+
+int main(int, char**) {
+  test_char_pointer<char*>();
+  test_char_pointer<const char*>();
+  test_char_pointer<wchar_t*>();
+  test_char_pointer<const wchar_t*>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.char.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.char.pass.cpp
new file mode 100644
index 0000000000000..f0ec2dd2350fc
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.char.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-incomplete-format
+
+// <format>
+
+// [format.formatter.spec]:
+// Each header that declares the template `formatter` provides the following
+// enabled specializations:
+// The specializations
+//   template<> struct formatter<char, char>;
+//   template<> struct formatter<char, wchar_t>;
+//   template<> struct formatter<wchar_t, wchar_t>;
+
+#include <format>
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+
+template <class StringT, class StringViewT, class ArgumentT>
+void test(StringT expected, StringViewT fmt, ArgumentT arg) {
+  using CharT = typename StringT::value_type;
+  auto parse_ctx = std::basic_format_parse_context<CharT>(fmt);
+  std::formatter<ArgumentT, CharT> formatter;
+  static_assert(std::semiregular<decltype(formatter)>);
+
+  auto it = formatter.parse(parse_ctx);
+  assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
+
+  StringT result;
+  auto out = std::back_inserter(result);
+  using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
+
+  auto format_ctx = std::__format_context_create<decltype(out), CharT>(
+      out, std::make_format_args<FormatCtxT>(arg));
+  formatter.format(arg, format_ctx);
+  assert(result == expected);
+}
+
+template <class StringT, class ArgumentT>
+void test_termination_condition(StringT expected, StringT f, ArgumentT arg) {
+  // The format-spec is valid if completely consumed or terminates at a '}'.
+  // The valid inputs all end with a '}'. The test is executed twice:
+  // - first with the terminating '}',
+  // - second consuming the entire input.
+  using CharT = typename StringT::value_type;
+  std::basic_string_view<CharT> fmt{f};
+  assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+  test(expected, fmt, arg);
+  fmt.remove_suffix(1);
+  test(expected, fmt, arg);
+}
+
+template <class ArgumentT, class CharT>
+void test_char_type() {
+  test_termination_condition(STR("a"), STR("}"), ArgumentT('a'));
+  test_termination_condition(STR("z"), STR("}"), ArgumentT('z'));
+  test_termination_condition(STR("A"), STR("}"), ArgumentT('A'));
+  test_termination_condition(STR("Z"), STR("}"), ArgumentT('Z'));
+  test_termination_condition(STR("0"), STR("}"), ArgumentT('0'));
+  test_termination_condition(STR("9"), STR("}"), ArgumentT('9'));
+}
+
+int main(int, char**) {
+  test_char_type<char, char>();
+  test_char_type<char, wchar_t>();
+  test_char_type<wchar_t, wchar_t>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.const_char_array.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.const_char_array.pass.cpp
new file mode 100644
index 0000000000000..608504759047a
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.const_char_array.pass.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// UNSUPPORTED: clang-11
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+// UNSUPPORTED: apple-clang-12
+
+// <format>
+
+// [format.formatter.spec]:
+// Each header that declares the template `formatter` provides the following
+// enabled specializations:
+// For each `charT`, the string type specializations
+//   template<size_t N> struct formatter<const charT[N], charT>;
+
+#include <format>
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+#define CSTR(S) MAKE_CSTRING(CharT, S)
+
+// This is based on the method found in
+// clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-cxx20.cpp
+template <size_t N>
+struct Tester {
+  // This is not part of the real test, but is used the deduce the size of the input.
+  constexpr Tester(const char (&r)[N]) { __builtin_memcpy(text, r, N); }
+  char text[N];
+
+  // The size of the array shouldn't include the NUL character.
+  static const size_t size = N - 1;
+
+  template <class CharT>
+  void test(const std::basic_string<CharT>& expected,
+            const std::basic_string_view<CharT>& fmt) const {
+    using Str = const CharT[size];
+    std::basic_format_parse_context<CharT> parse_ctx{fmt};
+    std::formatter<Str, CharT> formatter;
+    static_assert(std::semiregular<decltype(formatter)>);
+
+    auto it = formatter.parse(parse_ctx);
+    assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
+
+    std::basic_string<CharT> result;
+    auto out = std::back_inserter(result);
+    using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
+
+    std::basic_string<CharT> buffer{text, text + N};
+    // Note not too found of this hack
+    Str* data = reinterpret_cast<Str*>(buffer.c_str());
+
+    auto format_ctx = std::__format_context_create<decltype(out), CharT>(
+        out, std::make_format_args<FormatCtxT>(*data));
+    formatter.format(*data, format_ctx);
+    assert(result == expected);
+  }
+
+  template <class CharT>
+  void test_termination_condition(const std::basic_string<CharT>& expected,
+                                  const std::basic_string<CharT>& f) const {
+    // The format-spec is valid if completely consumed or terminates at a '}'.
+    // The valid inputs all end with a '}'. The test is executed twice:
+    // - first with the terminating '}',
+    // - second consuming the entire input.
+    std::basic_string_view<CharT> fmt{f};
+    assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+    test(expected, fmt);
+    fmt.remove_suffix(1);
+    test(expected, fmt);
+  }
+};
+
+template <Tester t, class CharT>
+void test_helper_wrapper(std::basic_string<CharT> expected,
+                         std::basic_string<CharT> fmt) {
+  t.test_termination_condition(expected, fmt);
+}
+
+template <class CharT>
+void test_array() {
+  test_helper_wrapper<" azAZ09,./<>?">(STR(" azAZ09,./<>?"), STR("}"));
+
+  std::basic_string<CharT> s(CSTR("abc\0abc"), 7);
+  test_helper_wrapper<"abc\0abc">(s, STR("}"));
+}
+
+int main(int, char**) {
+  test_array<char>();
+  test_array<wchar_t>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp
new file mode 100644
index 0000000000000..30708a1ef3719
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp
@@ -0,0 +1,122 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// UNSUPPORTED: LIBCXX-DEBUG-FIXME
+
+// <format>
+
+// [format.formatter.spec]:
+// Each header that declares the template `formatter` provides the following
+// enabled specializations:
+// For each `charT`, for each cv-unqualified arithmetic type `ArithmeticT`
+// other than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
+//    template<> struct formatter<ArithmeticT, charT>
+//
+// This file tests with `ArithmeticT = floating-point`, for each valid `charT`.
+// Where `floating-point` is one of:
+// - float
+// - double
+// - long double
+
+// TODO FMT Enable after floating-point support has been enabled
+#if 0
+#include <format>
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+
+template <class StringViewT, class ArithmeticT>
+void test(StringViewT fmt, ArithmeticT arg) {
+  using CharT = typename StringViewT::value_type;
+  auto parse_ctx = std::basic_format_parse_context<CharT>(fmt);
+  std::formatter<ArithmeticT, CharT> formatter;
+  static_assert(std::semiregular<decltype(formatter)>);
+
+  auto it = formatter.parse(parse_ctx);
+  assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
+
+  std::basic_string<CharT> result;
+  auto out = std::back_inserter(result);
+  using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
+
+  auto format_ctx = std::__format_context_create<decltype(out), CharT>(
+      out, std::make_format_args<FormatCtxT>(arg));
+  formatter.format(arg, format_ctx);
+  std::string expected = std::to_string(arg);
+  assert(result == std::basic_string<CharT>(expected.begin(), expected.end()));
+}
+
+template <class StringT, class ArithmeticT>
+void test_termination_condition(StringT f, ArithmeticT arg) {
+  // The format-spec is valid if completely consumed or terminates at a '}'.
+  // The valid inputs all end with a '}'. The test is executed twice:
+  // - first with the terminating '}',
+  // - second consuming the entire input.
+  using CharT = typename StringT::value_type;
+  std::basic_string_view<CharT> fmt{f};
+  assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+  test(fmt, arg);
+  fmt.remove_suffix(1);
+  test(fmt, arg);
+}
+
+template <class ArithmeticT, class CharT>
+void test_float_type() {
+  using A = ArithmeticT;
+  test_termination_condition(STR("}"), A(-std::numeric_limits<float>::max()));
+  test_termination_condition(STR("}"), A(-std::numeric_limits<float>::min()));
+  test_termination_condition(STR("}"), A(-0.0));
+  test_termination_condition(STR("}"), A(0.0));
+  test_termination_condition(STR("}"), A(std::numeric_limits<float>::min()));
+  test_termination_condition(STR("}"), A(std::numeric_limits<float>::max()));
+  if (sizeof(A) > sizeof(float)) {
+    test_termination_condition(STR("}"),
+                               A(-std::numeric_limits<double>::max()));
+    test_termination_condition(STR("}"),
+                               A(-std::numeric_limits<double>::min()));
+    test_termination_condition(STR("}"), A(std::numeric_limits<double>::min()));
+    test_termination_condition(STR("}"), A(std::numeric_limits<double>::max()));
+  }
+  if (sizeof(A) > sizeof(double)) {
+    test_termination_condition(STR("}"),
+                               A(-std::numeric_limits<long double>::max()));
+    test_termination_condition(STR("}"),
+                               A(-std::numeric_limits<long double>::min()));
+    test_termination_condition(STR("}"),
+                               A(std::numeric_limits<long double>::min()));
+    test_termination_condition(STR("}"),
+                               A(std::numeric_limits<long double>::max()));
+  }
+
+  // TODO FMT Also test with special floating point values: +/-Inf NaN.
+}
+
+template <class CharT>
+void test_all_float_types() {
+  test_float_type<float, CharT>();
+  test_float_type<double, CharT>();
+  test_float_type<long double, CharT>();
+}
+
+int main(int, char**) {
+  test_all_float_types<char>();
+  test_all_float_types<wchar_t>();
+
+  return 0;
+}
+#else
+int main(int, char**) { return 0; }
+#endif

diff  --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.signed_integral.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.signed_integral.pass.cpp
new file mode 100644
index 0000000000000..526531ff46ae1
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.signed_integral.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-incomplete-format
+
+// <format>
+
+// [format.formatter.spec]:
+// Each header that declares the template `formatter` provides the following
+// enabled specializations:
+// For each `charT`, for each cv-unqualified arithmetic type `ArithmeticT`
+// other than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
+//    template<> struct formatter<ArithmeticT, charT>
+//
+// This file tests with `ArithmeticT = signed integer`, for each valid `charT`.
+// Where `signed integer` is one of:
+// - signed char
+// - short
+// - int
+// - long
+// - long long
+// - __int128_t
+
+#include <format>
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+
+template <class StringT, class StringViewT, class ArithmeticT>
+void test(StringT expected, StringViewT fmt, ArithmeticT arg) {
+  using CharT = typename StringT::value_type;
+  auto parse_ctx = std::basic_format_parse_context<CharT>(fmt);
+  std::formatter<ArithmeticT, CharT> formatter;
+  static_assert(std::semiregular<decltype(formatter)>);
+
+  auto it = formatter.parse(parse_ctx);
+  assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
+
+  StringT result;
+  auto out = std::back_inserter(result);
+  using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
+
+  auto format_ctx = std::__format_context_create<decltype(out), CharT>(
+      out, std::make_format_args<FormatCtxT>(arg));
+  formatter.format(arg, format_ctx);
+  assert(result == expected);
+}
+
+template <class StringT, class ArithmeticT>
+void test_termination_condition(StringT expected, StringT f, ArithmeticT arg) {
+  // The format-spec is valid if completely consumed or terminates at a '}'.
+  // The valid inputs all end with a '}'. The test is executed twice:
+  // - first with the terminating '}',
+  // - second consuming the entire input.
+  using CharT = typename StringT::value_type;
+  std::basic_string_view<CharT> fmt{f};
+  assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+  test(expected, fmt, arg);
+  fmt.remove_suffix(1);
+  test(expected, fmt, arg);
+}
+
+template <class Arithmetic, class CharT>
+void test_signed_integral_type() {
+  using A = Arithmetic;
+  test_termination_condition(STR("-128"), STR("}"), A(-128));
+  test_termination_condition(STR("0"), STR("}"), A(0));
+  test_termination_condition(STR("127"), STR("}"), A(127));
+  if (sizeof(A) > 1) {
+    test_termination_condition(STR("-32768"), STR("}"), A(-32768));
+    test_termination_condition(STR("32767"), STR("}"), A(32767));
+  }
+  if (sizeof(A) > 2) {
+    test_termination_condition(STR("-2147483648"), STR("}"), A(-2147483648));
+    test_termination_condition(STR("2147483647"), STR("}"), A(2147483647));
+  }
+  if (sizeof(A) > 4) {
+    // -9223372036854775808 can't be used directly, it gives the following
+    // diagnostic:
+    // integer literal is too large to be represented in a signed integer type,
+    // interpreting as unsigned [-Werror,-Wimplicitly-unsigned-literal]
+    test_termination_condition(STR("-9223372036854775808"), STR("}"),
+                               A(-9223372036854775807 - 1));
+    test_termination_condition(STR("9223372036854775807"), STR("}"),
+                               A(9223372036854775807));
+  }
+
+  // TODO FMT Implement the __int128_t minimum and maximum once the formatter
+  // can handle these values.
+}
+
+template <class CharT>
+void test_all_signed_integral_types() {
+  test_signed_integral_type<signed char, CharT>();
+  test_signed_integral_type<short, CharT>();
+  test_signed_integral_type<int, CharT>();
+  test_signed_integral_type<long, CharT>();
+  test_signed_integral_type<long long, CharT>();
+#ifndef _LIBCPP_HAS_NO_INT128
+  test_signed_integral_type<__int128_t, CharT>();
+#endif
+}
+
+int main(int, char**) {
+  test_all_signed_integral_types<char>();
+  test_all_signed_integral_types<wchar_t>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.string.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.string.pass.cpp
new file mode 100644
index 0000000000000..7bd1d1c631175
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.string.pass.cpp
@@ -0,0 +1,100 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+
+// <format>
+
+// [format.formatter.spec]:
+// Each header that declares the template `formatter` provides the following
+// enabled specializations:
+// For each `charT`, the string type specializations
+//   template<class traits, class Allocator>
+//     struct formatter<basic_string<charT, traits, Allocator>, charT>;
+//   template<class traits>
+//     struct formatter<basic_string_view<charT, traits>, charT>;
+
+#include <format>
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+#define CSTR(S) MAKE_CSTRING(CharT, S)
+
+template <class T, class ArgumentT, class StringT, class StringViewT>
+void test(StringT expected, StringViewT fmt, StringT a) {
+  static_assert(
+      std::same_as<typename T::value_type,
+                   typename std::decay_t<ArgumentT>::value_type> &&
+      std::same_as<typename T::value_type, typename StringT::value_type>);
+  using CharT = typename T::value_type;
+
+  auto parse_ctx = std::basic_format_parse_context<CharT>(fmt);
+  std::formatter<T, CharT> formatter;
+  static_assert(std::semiregular<decltype(formatter)>);
+
+  auto it = formatter.parse(parse_ctx);
+  assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
+
+  StringT result;
+  auto out = std::back_inserter(result);
+  using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
+
+  ArgumentT arg = a;
+  auto format_ctx = std::__format_context_create<decltype(out), CharT>(
+      out, std::make_format_args<FormatCtxT>(std::forward<ArgumentT>(arg)));
+  formatter.format(arg, format_ctx);
+  assert(result == expected);
+}
+
+template <class T, class ArgumentT, class StringT>
+void test_termination_condition(StringT expected, StringT f, StringT arg) {
+  // The format-spec is valid if completely consumed or terminates at a '}'.
+  // The valid inputs all end with a '}'. The test is executed twice:
+  // - first with the terminating '}',
+  // - second consuming the entire input.
+  using CharT = typename StringT::value_type;
+  std::basic_string_view<CharT> fmt{f};
+  assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+  test<T, ArgumentT>(expected, fmt, arg);
+  fmt.remove_suffix(1);
+  test<T, ArgumentT>(expected, fmt, arg);
+}
+
+template <class T, class ArgumentT>
+void test_string_type() {
+  static_assert(std::same_as<typename T::value_type,
+                             typename std::decay_t<ArgumentT>::value_type>);
+  using CharT = typename T::value_type;
+
+  test_termination_condition<T, ArgumentT>(STR(" azAZ09,./<>?"), STR("}"),
+                                           STR(" azAZ09,./<>?"));
+
+  std::basic_string<CharT> s(CSTR("abc\0abc"), 7);
+  test_termination_condition<T, ArgumentT>(s, STR("}"), s);
+}
+
+template <class CharT>
+void test_all_string_types() {
+  test_string_type<std::basic_string<CharT>, const std::basic_string<CharT>&>();
+  test_string_type<std::basic_string_view<CharT>,
+                   std::basic_string_view<CharT>>();
+}
+
+int main(int, char**) {
+  test_all_string_types<char>();
+  test_all_string_types<wchar_t>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.unsigned_integral.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.unsigned_integral.pass.cpp
new file mode 100644
index 0000000000000..f2321126a0cf2
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.unsigned_integral.pass.cpp
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+
+// <format>
+
+// [format.formatter.spec]:
+// Each header that declares the template `formatter` provides the following
+// enabled specializations:
+// For each `charT`, for each cv-unqualified arithmetic type `ArithmeticT`
+// other than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
+//    template<> struct formatter<ArithmeticT, charT>
+//
+// This file tests with `ArithmeticT = unsigned integer`, for each valid `charT`.
+// Where `unsigned integer` is one of:
+// - unsigned char
+// - unsigned short
+// - unsigned
+// - unsigned long
+// - unsigned long long
+// - __uint128_t
+
+#include <format>
+#include <cassert>
+#include <concepts>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+
+template <class StringT, class StringViewT, class ArithmeticT>
+void test(StringT expected, StringViewT fmt, ArithmeticT arg) {
+  using CharT = typename StringT::value_type;
+  auto parse_ctx = std::basic_format_parse_context<CharT>(fmt);
+  std::formatter<ArithmeticT, CharT> formatter;
+  static_assert(std::semiregular<decltype(formatter)>);
+
+  auto it = formatter.parse(parse_ctx);
+  assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
+
+  StringT result;
+  auto out = std::back_inserter(result);
+  using FormatCtxT = std::basic_format_context<decltype(out), CharT>;
+
+  auto format_ctx = std::__format_context_create<decltype(out), CharT>(
+      out, std::make_format_args<FormatCtxT>(arg));
+  formatter.format(arg, format_ctx);
+  assert(result == expected);
+}
+
+template <class StringT, class ArithmeticT>
+void test_termination_condition(StringT expected, StringT f, ArithmeticT arg) {
+  // The format-spec is valid if completely consumed or terminates at a '}'.
+  // The valid inputs all end with a '}'. The test is executed twice:
+  // - first with the terminating '}',
+  // - second consuming the entire input.
+  using CharT = typename StringT::value_type;
+  std::basic_string_view<CharT> fmt{f};
+  assert(fmt.back() == CharT('}') && "Pre-condition failure");
+
+  test(expected, fmt, arg);
+  fmt.remove_suffix(1);
+  test(expected, fmt, arg);
+}
+
+template <class ArithmeticT, class CharT>
+void test_unsigned_integral_type() {
+  using A = ArithmeticT;
+  test_termination_condition(STR("0"), STR("}"), A(0));
+  test_termination_condition(STR("255"), STR("}"), A(255));
+  if (sizeof(A) > 1)
+    test_termination_condition(STR("65535"), STR("}"), A(65535));
+  if (sizeof(A) > 2)
+    test_termination_condition(STR("4294967295"), STR("}"), A(4294967295));
+  if (sizeof(A) > 4)
+    test_termination_condition(STR("8446744073709551615"), STR("}"),
+                               A(8446744073709551615));
+
+  // TODO FMT Implement the __uint128_t maximum once the formatter can handle
+  // these values.
+}
+
+template <class CharT>
+void test_all_unsigned_integral_types() {
+  test_unsigned_integral_type<unsigned char, CharT>();
+  test_unsigned_integral_type<unsigned short, CharT>();
+  test_unsigned_integral_type<unsigned, CharT>();
+  test_unsigned_integral_type<unsigned long, CharT>();
+  test_unsigned_integral_type<unsigned long long, CharT>();
+#ifndef _LIBCPP_HAS_NO_INT128
+  test_unsigned_integral_type<__uint128_t, CharT>();
+#endif
+}
+
+int main(int, char**) {
+  test_all_unsigned_integral_types<char>();
+  test_all_unsigned_integral_types<wchar_t>();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
new file mode 100644
index 0000000000000..1fb6c3b3df6d2
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+// 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
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// template<class... Args>
+//   string format(const locale& loc, string_view fmt, const Args&... args);
+// template<class... Args>
+//   wstring format(const locale& loc, wstring_view fmt, const Args&... args);
+
+#include <format>
+#include <cassert>
+#include <iostream>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  std::basic_string<CharT> out = std::format(std::locale(), fmt, args...);
+  if constexpr (std::same_as<CharT, char>)
+    if (out != expected)
+      std::cerr << "\nFormat string   " << fmt << "\nExpected output "
+                << expected << "\nActual output   " << out << '\n';
+  assert(out == expected);
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::format(std::locale(), fmt, args...);
+    if constexpr (std::same_as<CharT, char>)
+      std::cerr << "\nFormat string   " << fmt
+                << "\nDidn't throw an exception.\n";
+    assert(false);
+  } catch (std::format_error& e) {
+#ifdef _LIBCPP_VERSION
+    if constexpr (std::same_as<CharT, char>)
+      if (e.what() != what)
+        std::cerr << "\nFormat string   " << fmt << "\nExpected exception "
+                  << what << "\nActual exception   " << e.what() << '\n';
+#endif
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/format.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
new file mode 100644
index 0000000000000..acf775cf0531f
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format.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-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// Note this formatter shows additional information when tests are failing.
+// This aids the development. Since other formatters fail in the same fashion
+// they don't have this additional output.
+
+// <format>
+
+// template<class... Args>
+//   string format(string_view fmt, const Args&... args);
+// template<class... Args>
+//   wstring format(wstring_view fmt, const Args&... args);
+
+#include <format>
+#include <cassert>
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+#include <iostream>
+#endif
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  std::basic_string<CharT> out = std::format(fmt, args...);
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+  if constexpr (std::same_as<CharT, char>)
+    if (out != expected)
+      std::cerr << "\nFormat string   " << fmt << "\nExpected output "
+                << expected << "\nActual output   " << out << '\n';
+#endif
+  assert(out == expected);
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::format(fmt, args...);
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+    if constexpr (std::same_as<CharT, char>)
+      std::cerr << "\nFormat string   " << fmt
+                << "\nDidn't throw an exception.\n";
+#endif
+    assert(false);
+  } catch (std::format_error& e) {
+#if defined(_LIBCPP_VERSION) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+    if constexpr (std::same_as<CharT, char>)
+      if (e.what() != what)
+        std::cerr << "\nFormat string   " << fmt << "\nExpected exception "
+                  << what << "\nActual exception   " << e.what() << '\n';
+#endif
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_tests.h b/libcxx/test/std/utilities/format/format.functions/format_tests.h
new file mode 100644
index 0000000000000..770c0df629090
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h
@@ -0,0 +1,144 @@
+//===----------------------------------------------------------------------===//
+// 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 TEST_STD_UTILITIES_FORMAT_FORMAT_FUNCTIONS_FORMAT_TESTS_H
+#define TEST_STD_UTILITIES_FORMAT_FORMAT_FUNCTIONS_FORMAT_TESTS_H
+
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+
+// TestFunction must be callable as check(expected-result, string-to-format, args-to-format...)
+// ExceptionTest must be callable as check_exception(expected-exception, string-to-format, args-to-format...)
+template <class CharT, class TestFunction, class ExceptionTest>
+void format_tests(TestFunction check, ExceptionTest check_exception) {
+  // *** Test escaping  ***
+  check(STR("{"), STR("{{"));
+  check(STR("}"), STR("}}"));
+
+  // *** Test argument ID ***
+  check(STR("hello 01"), STR("hello {0:}{1:}"), false, true);
+  check(STR("hello 10"), STR("hello {1:}{0:}"), false, true);
+
+  // ** Test invalid format strings ***
+  check_exception("The format string terminates at a '{'", STR("{"));
+  check_exception("The replacement field misses a terminating '}'", STR("{:"),
+                  42);
+
+  check_exception("The format string contains an invalid escape sequence",
+                  STR("}"));
+  check_exception("The format string contains an invalid escape sequence",
+                  STR("{:}-}"), 42);
+
+  check_exception("The format string contains an invalid escape sequence",
+                  STR("} "));
+
+  check_exception(
+      "The arg-id of the format-spec starts with an invalid character",
+      STR("{-"), 42);
+  check_exception("Argument index out of bounds", STR("hello {}"));
+  check_exception("Argument index out of bounds", STR("hello {0}"));
+  check_exception("Argument index out of bounds", STR("hello {1}"), 42);
+
+  // *** Test char format argument ***
+  // The `char` to `wchar_t` formatting is tested separately.
+  check(STR("hello 09azAZ!"), STR("hello {}{}{}{}{}{}{}"), CharT('0'),
+        CharT('9'), CharT('a'), CharT('z'), CharT('A'), CharT('Z'), CharT('!'));
+
+  // *** Test string format argument ***
+  {
+    CharT buffer[] = {CharT('0'), CharT('9'), CharT('a'), CharT('z'),
+                      CharT('A'), CharT('Z'), CharT('!'), 0};
+    CharT* data = buffer;
+    check(STR("hello 09azAZ!"), STR("hello {}"), data);
+  }
+  {
+    CharT buffer[] = {CharT('0'), CharT('9'), CharT('a'), CharT('z'),
+                      CharT('A'), CharT('Z'), CharT('!'), 0};
+    const CharT* data = buffer;
+    check(STR("hello 09azAZ!"), STR("hello {}"), data);
+  }
+  {
+    std::basic_string<CharT> data = STR("world");
+    check(STR("hello world"), STR("hello {}"), data);
+  }
+  {
+    std::basic_string<CharT> buffer = STR("world");
+    std::basic_string_view<CharT> data = buffer;
+    check(STR("hello world"), STR("hello {}"), data);
+  }
+
+  // *** Test Boolean format argument ***
+  check(STR("hello 01"), STR("hello {}{}"), false, true);
+
+  // *** Test signed integral format argument ***
+  check(STR("hello 42"), STR("hello {}"), static_cast<signed char>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<short>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<int>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<long>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<long long>(42));
+#ifndef _LIBCPP_HAS_NO_INT128
+  check(STR("hello 42"), STR("hello {}"), static_cast<__int128_t>(42));
+  {
+    // Note 128-bit support is only partly implemented test the range
+    // conditions here.
+    std::basic_string<CharT> min =
+        std::format(STR("{}"), std::numeric_limits<long long>::min());
+    check(min, STR("{}"),
+          static_cast<__int128_t>(std::numeric_limits<long long>::min()));
+    std::basic_string<CharT> max =
+        std::format(STR("{}"), std::numeric_limits<long long>::max());
+    check(max, STR("{}"),
+          static_cast<__int128_t>(std::numeric_limits<long long>::max()));
+    check_exception(
+        "128-bit value is outside of implemented range", STR("{}"),
+        static_cast<__int128_t>(std::numeric_limits<long long>::min()) - 1);
+    check_exception(
+        "128-bit value is outside of implemented range", STR("{}"),
+        static_cast<__int128_t>(std::numeric_limits<long long>::max()) + 1);
+  }
+#endif
+
+  // ** Test unsigned integral format argument ***
+  check(STR("hello 42"), STR("hello {}"), static_cast<unsigned char>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<unsigned short>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<unsigned>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<unsigned long>(42));
+  check(STR("hello 42"), STR("hello {}"), static_cast<unsigned long long>(42));
+#ifndef _LIBCPP_HAS_NO_INT128
+  check(STR("hello 42"), STR("hello {}"), static_cast<__uint128_t>(42));
+  {
+    // Note 128-bit support is only partly implemented test the range
+    // conditions here.
+    std::basic_string<CharT> max =
+        std::format(STR("{}"), std::numeric_limits<unsigned long long>::max());
+    check(max, STR("{}"),
+          static_cast<__uint128_t>(
+              std::numeric_limits<unsigned long long>::max()));
+    check_exception("128-bit value is outside of implemented range", STR("{}"),
+                    static_cast<__uint128_t>(
+                        std::numeric_limits<unsigned long long>::max()) +
+                        1);
+  }
+#endif
+
+  // *** Test floating point format argument ***
+// TODO FMT Enable after floating-point support has been enabled
+#if 0
+  check(STR("hello 42.000000"), STR("hello {}"), static_cast<float>(42));
+  check(STR("hello 42.000000"), STR("hello {}"), static_cast<double>(42));
+  check(STR("hello 42.000000"), STR("hello {}"), static_cast<long double>(42));
+#endif
+}
+
+template <class TestFunction>
+void format_tests_char_to_wchar_t(TestFunction check) {
+  using CharT = wchar_t;
+  check(STR("hello 09azA"), STR("hello {}{}{}{}{}"), '0', '9', 'a', 'z', 'A');
+}
+
+#endif

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
new file mode 100644
index 0000000000000..9598bea7076da
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+// 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
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// template<class Out, class... Args>
+//   Out format_to(Out out, const locale& loc,
+//                 string_view fmt, const Args&... args);
+// template<class Out, class... Args>
+//   Out format_to(Out out, const locale& loc,
+//                 wstring_view fmt, const Args&... args);
+
+#include <format>
+#include <algorithm>
+#include <cassert>
+#include <list>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  {
+    std::basic_string<CharT> out(expected.size(), CharT(' '));
+    auto it = std::format_to(out.begin(), std::locale(), fmt, args...);
+    assert(it == out.end());
+    assert(out == expected);
+  }
+  {
+    std::list<CharT> out;
+    std::format_to(std::back_inserter(out), std::locale(), fmt, args...);
+    assert(
+        std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+  }
+  {
+    std::vector<CharT> out;
+    std::format_to(std::back_inserter(out), std::locale(), fmt, args...);
+    assert(
+        std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+  }
+  {
+    assert(expected.size() < 4096 && "Update the size of the buffer.");
+    CharT out[4096];
+    CharT* it = std::format_to(out, std::locale(), fmt, args...);
+    assert(std::distance(out, it) == int(expected.size()));
+    *it = '\0';
+    assert(out == expected);
+  }
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::basic_string<CharT> out;
+    std::format_to(std::back_inserter(out), std::locale(), fmt, args...);
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
new file mode 100644
index 0000000000000..795587cb4f993
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// The tests write fixed size buffer, make sure it remains in bounds.
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=1
+// UNSUPPORTED: libcxx-no-debug-mode
+
+// <format>
+
+// template<class Out, class... Args>
+//   Out format_to(Out out, string_view fmt, const Args&... args);
+// template<class Out, class... Args>
+//   Out format_to(Out out, wstring_view fmt, const Args&... args);
+
+#include <format>
+#include <algorithm>
+#include <cassert>
+#include <list>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  {
+    std::basic_string<CharT> out(expected.size(), CharT(' '));
+    auto it = std::format_to(out.begin(), fmt, args...);
+    assert(it == out.end());
+    assert(out == expected);
+  }
+  {
+    std::list<CharT> out;
+    std::format_to(std::back_inserter(out), fmt, args...);
+    assert(
+        std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+  }
+  {
+    std::vector<CharT> out;
+    std::format_to(std::back_inserter(out), fmt, args...);
+    assert(
+        std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+  }
+  {
+    assert(expected.size() < 4096 && "Update the size of the buffer.");
+    CharT out[4096];
+    CharT* it = std::format_to(out, fmt, args...);
+    assert(std::distance(out, it) == int(expected.size()));
+    *it = '\0';
+    assert(out == expected);
+  }
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::basic_string<CharT> out;
+    std::format_to(std::back_inserter(out), fmt, args...);
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp
new file mode 100644
index 0000000000000..40c502aba48ca
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp
@@ -0,0 +1,128 @@
+//===----------------------------------------------------------------------===//
+// 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
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// template<class Out, class... Args>
+//   format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
+//                                       const locale& loc, string_view fmt,
+//                                       const Args&... args);
+// template<class Out, class... Args>
+//   format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
+//                                       const locale& loc, wstring_view fmt,
+//                                       const Args&... args);
+
+#include <format>
+#include <algorithm>
+#include <cassert>
+#include <list>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  {
+    std::list<CharT> out;
+    std::format_to_n_result result = std::format_to_n(
+        std::back_inserter(out), 0, std::locale(), fmt, args...);
+    // To avoid signedness warnings make sure formatted_size uses the same type
+    // as result.size.
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(std::locale(), fmt, args...);
+
+    assert(result.size == formatted_size);
+    assert(out.empty());
+  }
+  {
+    std::vector<CharT> out;
+    std::format_to_n_result result = std::format_to_n(
+        std::back_inserter(out), 5, std::locale(), fmt, args...);
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(std::locale(), fmt, args...);
+    
diff _type size = std::min<
diff _type>(5, formatted_size);
+
+    assert(result.size == formatted_size);
+    assert(std::equal(out.begin(), out.end(), expected.begin(),
+                      expected.begin() + size));
+  }
+  {
+    std::basic_string<CharT> out;
+    std::format_to_n_result result = std::format_to_n(
+        std::back_inserter(out), 1000, std::locale(), fmt, args...);
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(std::locale(), fmt, args...);
+    
diff _type size = std::min<
diff _type>(1000, formatted_size);
+
+    assert(result.size == formatted_size);
+    assert(out == expected.substr(0, size));
+  }
+  {
+    // Test the returned iterator.
+    std::basic_string<CharT> out(10, CharT(' '));
+    std::format_to_n_result result =
+        std::format_to_n(out.begin(), 10, std::locale(), fmt, args...);
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(std::locale(), fmt, args...);
+    
diff _type size = std::min<
diff _type>(10, formatted_size);
+
+    assert(result.size == formatted_size);
+    assert(result.out == out.begin() + size);
+    assert(out.substr(0, size) == expected.substr(0, size));
+  }
+  {
+    static_assert(std::is_signed_v<std::iter_
diff erence_t<CharT*>>,
+                  "If the 
diff erence type isn't negative the test will fail "
+                  "due to using a large positive value.");
+    CharT buffer[1] = {CharT(0)};
+    std::format_to_n_result result =
+        std::format_to_n(buffer, -1, std::locale(), fmt, args...);
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(std::locale(), fmt, args...);
+
+    assert(result.size == formatted_size);
+    assert(result.out == buffer);
+    assert(buffer[0] == CharT(0));
+  }
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::basic_string<CharT> out;
+    std::format_to_n(std::back_inserter(out), 0, std::locale(), fmt, args...);
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp
new file mode 100644
index 0000000000000..98b7c0cbd1fab
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp
@@ -0,0 +1,124 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// template<class Out, class... Args>
+//   format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
+//                                       string_view fmt, const Args&... args);
+// template<class Out, class... Args>
+//   format_to_n_result<Out> format_to_n(Out out, iter_
diff erence_t<Out> n,
+//                                       wstring_view fmt, const Args&... args);
+
+#include <format>
+#include <algorithm>
+#include <cassert>
+#include <list>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  {
+    std::list<CharT> out;
+    std::format_to_n_result result =
+        std::format_to_n(std::back_inserter(out), 0, fmt, args...);
+    // To avoid signedness warnings make sure formatted_size uses the same type
+    // as result.size.
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(fmt, args...);
+
+    assert(result.size == formatted_size);
+    assert(out.empty());
+  }
+  {
+    std::vector<CharT> out;
+    std::format_to_n_result result =
+        std::format_to_n(std::back_inserter(out), 5, fmt, args...);
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(fmt, args...);
+    
diff _type size = std::min<
diff _type>(5, formatted_size);
+
+    assert(result.size == formatted_size);
+    assert(std::equal(out.begin(), out.end(), expected.begin(),
+                      expected.begin() + size));
+  }
+  {
+    std::basic_string<CharT> out;
+    std::format_to_n_result result =
+        std::format_to_n(std::back_inserter(out), 1000, fmt, args...);
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(fmt, args...);
+    
diff _type size = std::min<
diff _type>(1000, formatted_size);
+
+    assert(result.size == formatted_size);
+    assert(out == expected.substr(0, size));
+  }
+  {
+    // Test the returned iterator.
+    std::basic_string<CharT> out(10, CharT(' '));
+    std::format_to_n_result result =
+        std::format_to_n(out.begin(), 10, fmt, args...);
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(fmt, args...);
+    
diff _type size = std::min<
diff _type>(10, formatted_size);
+
+    assert(result.size == formatted_size);
+    assert(result.out == out.begin() + size);
+    assert(out.substr(0, size) == expected.substr(0, size));
+  }
+  {
+    static_assert(std::is_signed_v<std::iter_
diff erence_t<CharT*>>,
+                  "If the 
diff erence type isn't negative the test will fail "
+                  "due to using a large positive value.");
+    CharT buffer[1] = {CharT(0)};
+    std::format_to_n_result result = std::format_to_n(buffer, -1, fmt, args...);
+    using 
diff _type = decltype(result.size);
+    
diff _type formatted_size = std::formatted_size(fmt, args...);
+
+    assert(result.size == formatted_size);
+    assert(result.out == buffer);
+    assert(buffer[0] == CharT(0));
+  }
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::basic_string<CharT> out;
+    std::format_to_n(std::back_inserter(out), 0, fmt, args...);
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp
new file mode 100644
index 0000000000000..26f6ef90cb676
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+// 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
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// template<class... Args>
+//   size_t formatted_size(const locale& loc,
+//                         string_view fmt, const Args&... args);
+// template<class... Args>
+//   size_t formatted_size(const locale& loc,
+//                         wstring_view fmt, const Args&... args);
+
+#include <format>
+#include <cassert>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  size_t size = std::formatted_size(std::locale(), fmt, args...);
+  assert(size == expected.size());
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::formatted_size(std::locale(), fmt, args...);
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp
new file mode 100644
index 0000000000000..732a942c52405
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// template<class... Args>
+//   size_t formatted_size(string_view fmt, const Args&... args);
+// template<class... Args>
+//   size_t formatted_size(wstring_view fmt, const Args&... args);
+
+#include <format>
+#include <cassert>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  size_t size = std::formatted_size(fmt, args...);
+  assert(size == expected.size());
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::formatted_size(fmt, args...);
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
new file mode 100644
index 0000000000000..5a0fcaba6c94c
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+// 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
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// string vformat(const locale& loc, string_view fmt, format_args args);
+// wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
+
+#include <format>
+#include <cassert>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  std::basic_string<CharT> out = std::vformat(
+      std::locale(), fmt,
+      std::make_format_args<std::basic_format_context<
+          std::back_insert_iterator<std::basic_string<CharT>>, CharT>>(
+          args...));
+  assert(out == expected);
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::vformat(
+        std::locale(), fmt,
+        std::make_format_args<std::basic_format_context<
+            std::back_insert_iterator<std::basic_string<CharT>>, CharT>>(
+            args...));
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
new file mode 100644
index 0000000000000..cb3bd20fb1690
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// string vformat(string_view fmt, format_args args);
+// wstring vformat(wstring_view fmt, wformat_args args);
+
+#include <format>
+#include <cassert>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  std::basic_string<CharT> out = std::vformat(
+      fmt, std::make_format_args<std::basic_format_context<
+               std::back_insert_iterator<std::basic_string<CharT>>, CharT>>(
+               args...));
+  assert(out == expected);
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::vformat(
+        fmt, std::make_format_args<std::basic_format_context<
+                 std::back_insert_iterator<std::basic_string<CharT>>, CharT>>(
+                 args...));
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
new file mode 100644
index 0000000000000..6569934bec767
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+// 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
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// template<class Out>
+//   Out vformat_to(Out out, const locale& loc, string_view fmt,
+//                  format_args_t<type_identity_t<Out>, char> args);
+// template<class Out>
+//    Out vformat_to(Out out, const locale& loc, wstring_view fmt,
+//                   format_args_t<type_identity_t<Out>, wchar_t> args);
+
+#include <format>
+#include <algorithm>
+#include <cassert>
+#include <list>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  {
+    std::basic_string<CharT> out(expected.size(), CharT(' '));
+    auto it = std::vformat_to(
+        out.begin(), std::locale(), fmt,
+        std::make_format_args<std::basic_format_context<
+            typename std::basic_string<CharT>::iterator, CharT>>(args...));
+    assert(it == out.end());
+    assert(out == expected);
+  }
+  {
+    std::list<CharT> out;
+    std::vformat_to(
+        std::back_inserter(out), std::locale(), fmt,
+        std::make_format_args<std::basic_format_context<
+            std::back_insert_iterator<std::list<CharT>>, CharT>>(args...));
+    assert(
+        std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+  }
+  {
+    std::vector<CharT> out;
+    std::vformat_to(
+        std::back_inserter(out), std::locale(), fmt,
+        std::make_format_args<std::basic_format_context<
+            std::back_insert_iterator<std::vector<CharT>>, CharT>>(args...));
+    assert(
+        std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+  }
+  {
+    assert(expected.size() < 4096 && "Update the size of the buffer.");
+    CharT out[4096];
+    CharT* it = std::vformat_to(
+        out, std::locale(), fmt,
+        std::make_format_args<std::basic_format_context<CharT*, CharT>>(
+            args...));
+    assert(std::distance(out, it) == int(expected.size()));
+    *it = '\0';
+    assert(out == expected);
+  }
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::basic_string<CharT> out;
+    std::vformat_to(
+        std::back_inserter(out), std::locale(), fmt,
+        std::make_format_args<std::basic_format_context<
+            std::back_insert_iterator<std::basic_string<CharT>>, CharT>>(
+            args...));
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp
new file mode 100644
index 0000000000000..179776a7f0760
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// The tests write fixed size buffer, make sure it remains in bounds.
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=1
+// UNSUPPORTED: libcxx-no-debug-mode
+
+// <format>
+
+// template<class Out>
+//   Out vformat_to(Out out, string_view fmt,
+//                  format_args_t<type_identity_t<Out>, char> args);
+// template<class Out>
+//    Out vformat_to(Out out, wstring_view fmt,
+//                   format_args_t<type_identity_t<Out>, wchar_t> args);
+
+#include <format>
+#include <algorithm>
+#include <cassert>
+#include <list>
+#include <vector>
+
+#include "test_macros.h"
+#include "format_tests.h"
+
+auto test = []<class CharT, class... Args>(std::basic_string<CharT> expected,
+                                           std::basic_string<CharT> fmt,
+                                           const Args&... args) {
+  {
+    std::basic_string<CharT> out(expected.size(), CharT(' '));
+    auto it = std::vformat_to(
+        out.begin(), fmt,
+        std::make_format_args<std::basic_format_context<
+            typename std::basic_string<CharT>::iterator, CharT>>(args...));
+    assert(it == out.end());
+    assert(out == expected);
+  }
+  {
+    std::list<CharT> out;
+    std::vformat_to(
+        std::back_inserter(out), fmt,
+        std::make_format_args<std::basic_format_context<
+            std::back_insert_iterator<std::list<CharT>>, CharT>>(args...));
+    assert(
+        std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+  }
+  {
+    std::vector<CharT> out;
+    std::vformat_to(
+        std::back_inserter(out), fmt,
+        std::make_format_args<std::basic_format_context<
+            std::back_insert_iterator<std::vector<CharT>>, CharT>>(args...));
+    assert(
+        std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
+  }
+  {
+    assert(expected.size() < 4096 && "Update the size of the buffer.");
+    CharT out[4096];
+    CharT* it = std::vformat_to(
+        out, fmt,
+        std::make_format_args<std::basic_format_context<CharT*, CharT>>(
+            args...));
+    assert(std::distance(out, it) == int(expected.size()));
+    *it = '\0';
+    assert(out == expected);
+  }
+};
+
+auto test_exception = []<class CharT, class... Args>(
+    std::string_view what, std::basic_string<CharT> fmt, const Args&... args) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    std::basic_string<CharT> out;
+    std::vformat_to(
+        std::back_inserter(out), fmt,
+        std::make_format_args<std::basic_format_context<
+            std::back_insert_iterator<std::basic_string<CharT>>, CharT>>(
+            args...));
+    assert(false);
+  } catch (std::format_error& e) {
+    LIBCPP_ASSERT(e.what() == what);
+    return;
+  }
+  assert(false);
+#else
+  (void)what;
+  (void)fmt;
+  (void)sizeof...(args);
+#endif
+};
+
+int main(int, char**) {
+  format_tests_char_to_wchar_t(test);
+
+  format_tests<char>(test, test_exception);
+  format_tests<wchar_t>(test, test_exception);
+
+  return 0;
+}


        


More information about the libcxx-commits mailing list