diff --git a/libcxx/benchmarks/formatter_float.bench.cpp b/libcxx/benchmarks/formatter_float.bench.cpp
--- a/libcxx/benchmarks/formatter_float.bench.cpp
+++ b/libcxx/benchmarks/formatter_float.bench.cpp
@@ -221,7 +221,7 @@
 
     while (state.KeepRunningBatch(1000))
       for (F value : data)
-        benchmark::DoNotOptimize(std::format_to(output.begin(), fmt, value));
+        benchmark::DoNotOptimize(std::vformat_to(output.begin(), fmt, std::make_format_args(value)));
   }
 
   std::string name() const {
diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -69,6 +69,9 @@
    should include assertions or not by default. For details, see
    :ref:`the documentation <assertions-mode>` about this new feature.
 
+- Implemented P2216R3 (std::format improvements), this impacts the API as
+  described in the next section.
+
 API Changes
 -----------
 
@@ -109,6 +112,13 @@
 - ``vector<bool>::const_reference``, ``vector<bool>::const_iterator::reference``
   and ``bitset::const_reference`` are now aliases for `bool` in the unstable ABI.
 
+- The format functions (``std::format``, ``std:;format_to``,
+  ``std::format_to_n``, and ``std::formatted_size``) now validate the format
+  string compile-time. This means the argument needs to be a compile time
+  literal. This may break existing code. When the format string is invalid this
+  will make the code ill-formed instead of throwing an exception run-time.
+  (This does not affect the ``v`` functions.)
+
 ABI Changes
 -----------
 
diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -196,7 +196,7 @@
 "`P2231R1 <https://wg21.link/P2231R1>`__","LWG","Missing constexpr in std::optional and std::variant","June 2021","|In progress|","13.0"
 "`P2325R3 <https://wg21.link/P2325R3>`__","LWG","Views should not be required to be default constructible","June 2021","|In progress|",""
 "`P2210R2 <https://wg21.link/P2210R2>`__","LWG",Superior String Splitting,"June 2021","",""
-"`P2216R3 <https://wg21.link/P2216R3>`__","LWG",std::format improvements,"June 2021","|Partial|",""
+"`P2216R3 <https://wg21.link/P2216R3>`__","LWG",std::format improvements,"June 2021","|Complete|","15.0"
 "`P2281R1 <https://wg21.link/P2281R1>`__","LWG",Clarifying range adaptor objects,"June 2021","|Complete|","14.0"
 "`P2328R1 <https://wg21.link/P2328R1>`__","LWG",join_view should join all views of ranges,"June 2021","",""
 "`P2367R0 <https://wg21.link/P2367R0>`__","LWG",Remove misuses of list-initialization from Clause 24,"June 2021","",""
diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h
--- a/libcxx/include/__format/parser_std_format_spec.h
+++ b/libcxx/include/__format/parser_std_format_spec.h
@@ -252,25 +252,21 @@
   /** Determines whether the value stored is a width or an arg-id. */
   uint32_t __width_as_arg : 1 {0};
 
-protected:
   /**
-   * Does the supplied std-format-spec contain a width field?
+   * Does the supplied width field contain an arg-id?
    *
-   * When the field isn't present there's no padding required. This can be used
-   * to optimize the formatting.
+   * If @c true the formatter needs to call @ref __substitute_width_arg_id.
    */
-  constexpr bool __has_width_field() const noexcept {
-    return __width_as_arg || __width;
-  }
+  constexpr bool __width_needs_substitution() const noexcept { return __width_as_arg; }
 
+protected:
   /**
-   * Does the supplied width field contain an arg-id?
+   * Does the supplied std-format-spec contain a width field?
    *
-   * If @c true the formatter needs to call @ref __substitute_width_arg_id.
+   * When the field isn't present there's no padding required. This can be used
+   * to optimize the formatting.
    */
-  constexpr bool __width_needs_substitution() const noexcept {
-    return __width_as_arg;
-  }
+  constexpr bool __has_width_field() const noexcept { return __width_as_arg || __width; }
 
   template <class _CharT>
   _LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
@@ -327,6 +323,15 @@
    */
   uint32_t __precision_as_arg : 1 {1};
 
+  /**
+   * Does the supplied precision field contain an arg-id?
+   *
+   * If @c true the formatter needs to call @ref __substitute_precision_arg_id.
+   */
+  constexpr bool __precision_needs_substitution() const noexcept {
+    return __precision_as_arg && __precision != __format::__number_max;
+  }
+
 protected:
   /**
    * Does the supplied std-format-spec contain a precision field?
@@ -340,15 +345,6 @@
            __precision != __format::__number_max; // The arg-id is valid?
   }
 
-  /**
-   * Does the supplied precision field contain an arg-id?
-   *
-   * If @c true the formatter needs to call @ref __substitute_precision_arg_id.
-   */
-  constexpr bool __precision_needs_substitution() const noexcept {
-    return __precision_as_arg && __precision != __format::__number_max;
-  }
-
   template <class _CharT>
   _LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
   __parse(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
diff --git a/libcxx/include/format b/libcxx/include/format
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -23,15 +23,26 @@
   using format_args = basic_format_args<format_context>;
   using wformat_args = basic_format_args<wformat_context>;
 
+  // [format.fmt.string], class template basic-format-string
+  template<class charT, class... Args>
+    struct basic-format-string;                       // exposition only
+
+  template<class... Args>
+    using format-string =                             // exposition only
+      basic-format-string<char, type_identity_t<Args>...>;
+  template<class... Args>
+    using wformat-string =                            // exposition only
+      basic-format-string<wchar_t, type_identity_t<Args>...>;
+
   // [format.functions], formatting functions
   template<class... Args>
-    string format(string_view fmt, const Args&... args);
+    string format(format-string<Args...> fmt, const Args&... args);
   template<class... Args>
-    wstring format(wstring_view fmt, const Args&... args);
+    wstring format(wformat-string<Args...> fmt, const Args&... args);
   template<class... Args>
-    string format(const locale& loc, string_view fmt, const Args&... args);
+    string format(const locale& loc, format-string<Args...> fmt, const Args&... args);
   template<class... Args>
-    wstring format(const locale& loc, wstring_view fmt, const Args&... args);
+    wstring format(const locale& loc, wformat-string<Args...> fmt, const Args&... args);
 
   string vformat(string_view fmt, format_args args);
   wstring vformat(wstring_view fmt, wformat_args args);
@@ -39,13 +50,13 @@
   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);
+    Out format_to(Out out, format-string<Args...> fmt, const Args&... args);
   template<class Out, class... Args>
-    Out format_to(Out out, wstring_view fmt, const Args&... args);
+    Out format_to(Out out, wformat-string<Args...> fmt, const Args&... args);
   template<class Out, class... Args>
-    Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args);
+    Out format_to(Out out, const locale& loc, format-string<Args...> fmt, const Args&... args);
   template<class Out, class... Args>
-    Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args);
+    Out format_to(Out out, const locale& loc, wformat-string<Args...> fmt, const Args&... args);
 
   template<class Out>
     Out vformat_to(Out out, string_view fmt, format_args args);
@@ -64,27 +75,27 @@
   };
   template<class Out, class... Args>
     format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
-                                        string_view fmt, const Args&... args);
+                                        format-string<Args...> fmt, const Args&... args);
   template<class Out, class... Args>
     format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
-                                        wstring_view fmt, const Args&... args);
+                                        wformat-string<Args...> fmt, const Args&... args);
   template<class Out, class... Args>
     format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
-                                        const locale& loc, string_view fmt,
+                                        const locale& loc, format-string<Args...> fmt,
                                         const Args&... args);
   template<class Out, class... Args>
     format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
-                                        const locale& loc, wstring_view fmt,
+                                        const locale& loc, wformat-string<Args...> fmt,
                                         const Args&... args);
 
   template<class... Args>
-    size_t formatted_size(string_view fmt, const Args&... args);
+    size_t formatted_size(format-string<Args...> fmt, const Args&... args);
   template<class... Args>
-    size_t formatted_size(wstring_view fmt, const Args&... args);
+    size_t formatted_size(wformat-string<Args...> fmt, const Args&... args);
   template<class... Args>
-    size_t formatted_size(const locale& loc, string_view fmt, const Args&... args);
+    size_t formatted_size(const locale& loc, format-string<Args...> fmt, const Args&... args);
   template<class... Args>
-    size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);
+    size_t formatted_size(const locale& loc, wformat-string<Args...> fmt, const Args&... args);
 
   // [format.formatter], formatter
   template<class T, class charT = char> struct formatter;
@@ -202,8 +213,181 @@
 
 namespace __format {
 
+template <class _CharT>
+class _LIBCPP_TEMPLATE_VIS __compile_time_handle {
+public:
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr void __parse(basic_format_parse_context<_CharT>& __parse_ctx) const { __parse_(__parse_ctx); }
+
+  template <class _Tp>
+  _LIBCPP_HIDE_FROM_ABI constexpr void __enable() {
+    __parse_ = [](basic_format_parse_context<_CharT>& __parse_ctx) {
+      formatter<_Tp, _CharT> __f;
+      __parse_ctx.advance_to(__f.parse(__parse_ctx));
+    };
+  }
+
+  // Before calling __parse the proper handler needs to be set with __enable.
+  // The default handler isn't a core constant expression.
+  _LIBCPP_HIDE_FROM_ABI constexpr __compile_time_handle()
+      : __parse_([](basic_format_parse_context<_CharT>&) { __throw_format_error("Not a handle"); }) {}
+
+private:
+  void (*__parse_)(basic_format_parse_context<_CharT>&);
+};
+
+// Dummy format_context only providing the parts used during constant
+// validation of the basic-format-string.
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS __compile_time_basic_format_context {
+public:
+  using char_type = _CharT;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __compile_time_basic_format_context(
+      const __arg_t* __args, const __compile_time_handle<_CharT>* __handles)
+      : __args_(__args), __handles_(__handles) {}
+
+  // During the compile-time validation nothing needs to be written.
+  // Therefore all operations of this iterator are a NOP.
+  struct iterator {
+    _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator=(_CharT) { return *this; }
+    _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator*() { return *this; }
+    _LIBCPP_HIDE_FROM_ABI constexpr iterator operator++(int) { return *this; }
+  };
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __arg_t arg(size_t __id) const {
+    // Accessing array out of bounds is UB thus an error.
+    return __args_[__id];
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr const __compile_time_handle<_CharT>& __handle(size_t __id) const {
+    // Accessing array out of bounds is UB thus an error.
+    return __handles_[__id];
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr iterator out() { return {}; }
+  _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(iterator) {}
+
+private:
+  const __arg_t* __args_;
+  const __compile_time_handle<_CharT>* __handles_;
+};
+
+template <class _CharT, class _Tp, class... _Args>
+consteval void __get_handle(__compile_time_handle<_CharT>* __handle) {
+  using _Context = __format::__compile_time_basic_format_context<_CharT>;
+  if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle)
+    __handle->template __enable<_Tp>();
+
+  if constexpr (sizeof...(_Args))
+    __format::__get_handle<_CharT, _Args...>(++__handle);
+}
+
+template <class _CharT, class... _Args>
+consteval array<__compile_time_handle<_CharT>, sizeof...(_Args)> __get_handle() {
+  if constexpr (sizeof...(_Args) == 0)
+    return array<__compile_time_handle<_CharT>,0>{};
+  else {
+    array<__compile_time_handle<_CharT>, sizeof...(_Args)> __result;
+    __format::__get_handle<_CharT, _Args...>(__result.data());
+    return __result;
+  }
+}
+
+_LIBCPP_HIDE_FROM_ABI
+constexpr void __compile_time_validate_integral(__arg_t __type) {
+  switch (__type) {
+  case __arg_t::__int:
+  case __arg_t::__long_long:
+#  ifndef _LIBCPP_HAS_NO_INT128
+  case __arg_t::__i128:
+#  endif
+  case __arg_t::__unsigned:
+  case __arg_t::__unsigned_long_long:
+#  ifndef _LIBCPP_HAS_NO_INT128
+  case __arg_t::__u128:
+#  endif
+    return;
+
+  default:
+    __throw_format_error("Argument isn't an integral");
+  }
+}
+
+// _HasPrecision does the formatter have a precision?
+template <class _CharT, class _Tp, bool _HasPrecision = false>
+_LIBCPP_HIDE_FROM_ABI constexpr void
+__compile_time_validate_argument(basic_format_parse_context<_CharT>& __parse_ctx,
+                                 __compile_time_basic_format_context<_CharT>& __ctx) {
+  formatter<_Tp, _CharT> __formatter;
+  __parse_ctx.advance_to(__formatter.parse(__parse_ctx));
+  // [format.string.std]/7
+  // ... If the corresponding formatting argument is not of integral type, or
+  // its value is negative for precision or non-positive for width, an
+  // exception of type format_error is thrown.
+  //
+  // Validate whether the arguments are integrals.
+  if (__formatter.__width_needs_substitution())
+    __format::__compile_time_validate_integral(__ctx.arg(__formatter.__width));
+
+  if constexpr (_HasPrecision)
+    if (__formatter.__precision_needs_substitution())
+      __format::__compile_time_validate_integral(__ctx.arg(__formatter.__precision));
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(basic_format_parse_context<_CharT>& __parse_ctx,
+                                                                     __compile_time_basic_format_context<_CharT>& __ctx,
+                                                                     __arg_t __type) {
+  switch (__type) {
+  case __arg_t::__none:
+    __throw_format_error("Invalid argument");
+  case __arg_t::__boolean:
+    return __format::__compile_time_validate_argument<_CharT, bool>(__parse_ctx, __ctx);
+  case __arg_t::__char_type:
+    return __format::__compile_time_validate_argument<_CharT, _CharT>(__parse_ctx, __ctx);
+  case __arg_t::__int:
+    return __format::__compile_time_validate_argument<_CharT, int>(__parse_ctx, __ctx);
+  case __arg_t::__long_long:
+    return __format::__compile_time_validate_argument<_CharT, long long>(__parse_ctx, __ctx);
+  case __arg_t::__i128:
+#      ifndef _LIBCPP_HAS_NO_INT128
+    return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx);
+#      else
+    __throw_format_error("Invalid argument");
+#      endif
+    return;
+  case __arg_t::__unsigned:
+    return __format::__compile_time_validate_argument<_CharT, unsigned>(__parse_ctx, __ctx);
+  case __arg_t::__unsigned_long_long:
+    return __format::__compile_time_validate_argument<_CharT, unsigned long long>(__parse_ctx, __ctx);
+  case __arg_t::__u128:
+#      ifndef _LIBCPP_HAS_NO_INT128
+    return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx);
+#      else
+    __throw_format_error("Invalid argument");
+#      endif
+    return;
+  case __arg_t::__float:
+    return __format::__compile_time_validate_argument<_CharT, float, true>(__parse_ctx, __ctx);
+  case __arg_t::__double:
+    return __format::__compile_time_validate_argument<_CharT, double, true>(__parse_ctx, __ctx);
+  case __arg_t::__long_double:
+    return __format::__compile_time_validate_argument<_CharT, long double, true>(__parse_ctx, __ctx);
+  case __arg_t::__const_char_type_ptr:
+    return __format::__compile_time_validate_argument<_CharT, const _CharT*, true>(__parse_ctx, __ctx);
+  case __arg_t::__string_view:
+    return __format::__compile_time_validate_argument<_CharT, basic_string_view<_CharT>, true>(__parse_ctx, __ctx);
+  case __arg_t::__ptr:
+    return __format::__compile_time_validate_argument<_CharT, const void*>(__parse_ctx, __ctx);
+  case __arg_t::__handle:
+    __throw_format_error("Handle should use __compile_time_validate_handle_argument");
+  }
+  __throw_format_error("Invalid argument");
+}
+
 template <class _CharT, class _ParseCtx, class _Ctx>
-_LIBCPP_HIDE_FROM_ABI const _CharT*
+_LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
 __handle_replacement_field(const _CharT* __begin, const _CharT* __end,
                            _ParseCtx& __parse_ctx, _Ctx& __ctx) {
   __format::__parse_number_result __r =
@@ -223,19 +407,26 @@
         "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 if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>)
-          __arg.format(__parse_ctx, __ctx);
-        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));
+  if constexpr (same_as<_Ctx, __compile_time_basic_format_context<_CharT>>) {
+    __arg_t __type = __ctx.arg(__r.__value);
+    if (__type == __arg_t::__handle)
+      __ctx.__handle(__r.__value).__parse(__parse_ctx);
+    else
+      __format::__compile_time_visit_format_arg(__parse_ctx, __ctx, __type);
+  } else
+    _VSTD::visit_format_arg(
+        [&](auto __arg) {
+          if constexpr (same_as<decltype(__arg), monostate>)
+            __throw_format_error("Argument index out of bounds");
+          else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>)
+            __arg.format(__parse_ctx, __ctx);
+          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('}'))
@@ -245,7 +436,7 @@
 }
 
 template <class _ParseCtx, class _Ctx>
-_LIBCPP_HIDE_FROM_ABI typename _Ctx::iterator
+_LIBCPP_HIDE_FROM_ABI constexpr 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>);
@@ -288,8 +479,54 @@
   return __out_it;
 }
 
+template <class _Context, class... _Args>
+consteval array<__arg_t, sizeof...(_Args)> __get_types() {
+  if constexpr (sizeof...(_Args) != 0) {
+    array<__arg_t, sizeof...(_Args)> __result;
+    __arg_t* __types = __result.data();
+    ([&] { *__types++ = __determine_arg_t<_Context, _Args>(); }(), ...);
+    return __result;
+  } else
+    return {};
+}
+
 } // namespace __format
 
+template <class _CharT, class... _Args>
+struct _LIBCPP_TEMPLATE_VIS __basic_format_string {
+  basic_string_view<_CharT> __str_;
+
+  template <class _Tp>
+    requires convertible_to<const _Tp&, basic_string_view<_CharT>>
+  consteval __basic_format_string(const _Tp& __str) : __str_{__str} {
+    __format::__vformat_to(basic_format_parse_context<_CharT>{__str_, sizeof...(_Args)},
+                           _Context{__types_.data(), __handles_.data()});
+  }
+
+private:
+  using _Context = __format::__compile_time_basic_format_context<_CharT>;
+
+  static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{
+      __format::__get_types<_Context, remove_cvref_t<_Args>...>()};
+
+  static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{
+      __format::__get_handle<_CharT, remove_cvref_t<_Args>...>()};
+};
+// These aliases fail on both MinGW and clang-cl. Since the aliases are
+// exposition only it's not a big issue. However P2508 will use a similar alias
+// that's part of the API. Note this faiiling alias follows the wording of the
+// Standard.
+// TODO FMT Investigate why it doesn't work.
+#ifndef _WIN32
+template <class... _Args>
+using __format_string = __basic_format_string<char, type_identity_t<_Args>...>;
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <class... _Args>
+using __wformat_string = __basic_format_string<wchar_t, type_identity_t<_Args>...>;
+#endif
+#endif
+
 template <class _OutIt, class _CharT, class _FormatOutIt>
 requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
     __vformat_to(
@@ -328,16 +565,28 @@
 
 template <output_iterator<const char&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _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,
+format_to(_OutIt __out_it,
+#    ifdef _WIN32
+          __basic_format_string<char, type_identity_t<_Args>...> __fmt,
+#    else
+          __format_string<_Args...> __fmt,
+#    endif
+          const _Args&... __args) {
+  return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.__str_,
                            _VSTD::make_format_args(__args...));
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <output_iterator<const wchar_t&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _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,
+format_to(_OutIt __out_it,
+#      ifdef _WIN32
+          __basic_format_string<wchar_t, type_identity_t<_Args>...> __fmt,
+#      else
+          __wformat_string<_Args...> __fmt,
+#      endif
+          const _Args&... __args) {
+  return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.__str_,
                            _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -359,16 +608,26 @@
 #endif
 
 template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
-format(string_view __fmt, const _Args&... __args) {
-  return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...));
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(
+#    ifdef _WIN32
+    __basic_format_string<char, type_identity_t<_Args>...> __fmt,
+#    else
+    __format_string<_Args...> __fmt,
+#    endif
+    const _Args&... __args) {
+  return _VSTD::vformat(__fmt.__str_, _VSTD::make_format_args(__args...));
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
-format(wstring_view __fmt, const _Args&... __args) {
-  return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...));
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring format(
+#      ifdef _WIN32
+    __basic_format_string<wchar_t, type_identity_t<_Args>...> __fmt,
+#      else
+    __wformat_string<_Args...> __fmt,
+#      endif
+    const _Args&... __args) {
+  return _VSTD::vformat(__fmt.__str_, _VSTD::make_wformat_args(__args...));
 }
 #endif
 
@@ -384,15 +643,27 @@
 
 template <output_iterator<const char&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, string_view __fmt, const _Args&... __args) {
-  return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, __fmt, _VSTD::make_format_args(__args...));
+format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n,
+#    ifdef _WIN32
+            __basic_format_string<char, type_identity_t<_Args>...> __fmt,
+#    else
+            __format_string<_Args...> __fmt,
+#    endif
+            const _Args&... __args) {
+  return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, __fmt.__str_, _VSTD::make_format_args(__args...));
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wstring_view __fmt, const _Args&... __args) {
-  return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, __fmt, _VSTD::make_wformat_args(__args...));
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
+format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n,
+#      ifdef _WIN32
+            __basic_format_string<wchar_t, type_identity_t<_Args>...> __fmt,
+#      else
+            __wformat_string<_Args...> __fmt,
+#      endif
+            const _Args&... __args) {
+  return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, __fmt.__str_, _VSTD::make_wformat_args(__args...));
 }
 #endif
 
@@ -405,16 +676,26 @@
 }
 
 template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(string_view __fmt,
-                                                                                              const _Args&... __args) {
-  return _VSTD::__vformatted_size(__fmt, basic_format_args{_VSTD::make_format_args(__args...)});
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(
+#    ifdef _WIN32
+    __basic_format_string<char, type_identity_t<_Args>...> __fmt,
+#    else
+    __format_string<_Args...> __fmt,
+#    endif
+    const _Args&... __args) {
+  return _VSTD::__vformatted_size(__fmt.__str_, basic_format_args{_VSTD::make_format_args(__args...)});
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(wstring_view __fmt,
-                                                                                              const _Args&... __args) {
-  return _VSTD::__vformatted_size(__fmt, basic_format_args{_VSTD::make_wformat_args(__args...)});
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(
+#      ifdef _WIN32
+    __basic_format_string<wchar_t, type_identity_t<_Args>...> __fmt,
+#      else
+    __wformat_string<_Args...> __fmt,
+#      endif
+    const _Args&... __args) {
+  return _VSTD::__vformatted_size(__fmt.__str_, basic_format_args{_VSTD::make_wformat_args(__args...)});
 }
 #endif
 
@@ -457,17 +738,29 @@
 #endif
 
 template <output_iterator<const char&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _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,
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+format_to(_OutIt __out_it, locale __loc,
+#      ifdef _WIN32
+          __basic_format_string<char, type_identity_t<_Args>...> __fmt,
+#      else
+          __format_string<_Args...> __fmt,
+#      endif
+          const _Args&... __args) {
+  return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.__str_,
                            _VSTD::make_format_args(__args...));
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _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,
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+format_to(_OutIt __out_it, locale __loc,
+#        ifdef _WIN32
+          __basic_format_string<wchar_t, type_identity_t<_Args>...> __fmt,
+#        else
+           __wformat_string<_Args...> __fmt,
+#        endif
+          const _Args&... __args) {
+  return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.__str_,
                            _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -492,16 +785,28 @@
 
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
-format(locale __loc, string_view __fmt, const _Args&... __args) {
-  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
+format(locale __loc,
+#      ifdef _WIN32
+       __basic_format_string<char, type_identity_t<_Args>...> __fmt,
+#      else
+       __format_string<_Args...> __fmt,
+#      endif
+       const _Args&... __args) {
+  return _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_,
                         _VSTD::make_format_args(__args...));
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
-format(locale __loc, wstring_view __fmt, const _Args&... __args) {
-  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
+format(locale __loc,
+#        ifdef _WIN32
+       __basic_format_string<wchar_t, type_identity_t<_Args>...> __fmt,
+#        else
+       __wformat_string<_Args...> __fmt,
+#        endif
+       const _Args&... __args) {
+  return _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_,
                         _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -519,16 +824,28 @@
 
 template <output_iterator<const char&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, string_view __fmt, const _Args&... __args) {
-  return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt,
+format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc,
+#      ifdef _WIN32
+            __basic_format_string<char, type_identity_t<_Args>...> __fmt,
+#      else
+            __format_string<_Args...> __fmt,
+#      endif
+            const _Args&... __args) {
+  return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.__str_,
                                                _VSTD::make_format_args(__args...));
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <output_iterator<const wchar_t&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, wstring_view __fmt, const _Args&... __args) {
-  return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt,
+format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc,
+#        ifdef _WIN32
+            __basic_format_string<wchar_t, type_identity_t<_Args>...> __fmt,
+#        else
+            __wformat_string<_Args...> __fmt,
+#        endif
+            const _Args&... __args) {
+  return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.__str_,
                                                 _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -543,18 +860,28 @@
 }
 
 template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(locale __loc,
-                                                                                              string_view __fmt,
-                                                                                              const _Args&... __args) {
-  return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt, basic_format_args{_VSTD::make_format_args(__args...)});
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(locale __loc,
+#      ifdef _WIN32
+               __basic_format_string<char, type_identity_t<_Args>...> __fmt,
+#      else
+               __format_string<_Args...> __fmt,
+#      endif
+               const _Args&... __args) {
+  return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.__str_, basic_format_args{_VSTD::make_format_args(__args...)});
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(locale __loc,
-                                                                                              wstring_view __fmt,
-                                                                                              const _Args&... __args) {
-  return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt, basic_format_args{_VSTD::make_wformat_args(__args...)});
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(locale __loc,
+#        ifdef _WIN32
+               __basic_format_string<wchar_t, type_identity_t<_Args>...> __fmt,
+#        else
+               __wformat_string<_Args...> __fmt,
+#        endif
+               const _Args&... __args) {
+  return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.__str_, basic_format_args{_VSTD::make_wformat_args(__args...)});
 }
 #endif
 
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
--- a/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
@@ -16,9 +16,9 @@
 // <format>
 
 // template<class... Args>
-//   string format(const locale& loc, string_view fmt, const Args&... args);
+//   string format(const locale& loc, format-string<Args...> fmt, const Args&... args);
 // template<class... Args>
-//   wstring format(const locale& loc, wstring_view fmt, const Args&... args);
+//   wstring format(const locale& loc, wformat-string<Args...> fmt, const Args&... args);
 
 #include <format>
 #include <cassert>
@@ -39,30 +39,11 @@
   assert(out == expected);
 };
 
-auto test_exception = []<class CharT, class... Args>(std::string_view what, std::basic_string_view<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 (const 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
+auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, const Args&...) {
+  // After P2216 most exceptions thrown by std::format become ill-formed.
+  // Therefore this tests does nothing.
+  // A basic ill-formed test is done in format.localeverify.cpp
+  // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
 };
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/format.locale.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format.locale.verify.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format.locale.verify.cpp
@@ -0,0 +1,92 @@
+//===----------------------------------------------------------------------===//
+// 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: no-localization
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// Basic test to validate ill-formed code is properly detected.
+
+// <format>
+
+// template<class... Args>
+//   string format(const locale& loc, format-string<Args...> fmt, const Args&... args);
+// template<class... Args>
+//   wstring format(const locale& loc, wformat-string<Args...> fmt, const Args&... args);
+
+#include <format>
+#include <locale>
+
+#include "test_macros.h"
+
+// clang-format off
+
+void f() {
+  std::format(std::locale(), "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format(std::locale(), "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  std::format(std::locale(), L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format(std::locale(), L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(std::locale(), L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+#endif
+}
diff --git a/libcxx/test/std/utilities/format/format.functions/format.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
--- a/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
@@ -19,9 +19,9 @@
 // <format>
 
 // template<class... Args>
-//   string format(string_view fmt, const Args&... args);
+//   string format(format-string<Args...> fmt, const Args&... args);
 // template<class... Args>
-//   wstring format(wstring_view fmt, const Args&... args);
+//   wstring format(wformat-string<Args...> fmt, const Args&... args);
 
 #include <format>
 #include <cassert>
@@ -48,31 +48,11 @@
   assert(out == expected);
 };
 
-auto test_exception = []<class CharT, class... Args>(std::string_view what, std::basic_string_view<CharT> fmt,
-                                                     const Args&... args) {
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  try {
-    std::format(fmt, args...);
-#  ifndef TEST_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 (const std::format_error& e) {
-    if constexpr (std::same_as<CharT, char>)
-#  if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_LOCALIZATION)
-      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);
-#endif
-  (void)what;
-  (void)fmt;
-  (void)sizeof...(args);
+auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, const Args&...) {
+  // After P2216 most exceptions thrown by std::format become ill-formed.
+  // Therefore this tests does nothing.
+  // A basic ill-formed test is done in format.verify.cpp
+  // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
 };
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/format.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format.verify.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format.verify.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-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// Basic test to validate ill-formed code is properly detected.
+
+// <format>
+
+// template<class... Args>
+//   string format(format-string<Args...> fmt, const Args&... args);
+// template<class... Args>
+//   wstring format(wformat-string<Args...> fmt, const Args&... args);
+
+#include <format>
+
+#include "test_macros.h"
+
+// clang-format off
+
+void f() {
+  std::format("{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format("}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format("{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format("{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format("{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format("{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format("{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format("{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format("{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format("{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  std::format(L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format(L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format(L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+#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
--- 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
@@ -17,10 +17,10 @@
 
 // template<class Out, class... Args>
 //   Out format_to(Out out, const locale& loc,
-//                 string_view fmt, const Args&... args);
+//                 format-string<Args...> fmt, const Args&... args);
 // template<class Out, class... Args>
 //   Out format_to(Out out, const locale& loc,
-//                 wstring_view fmt, const Args&... args);
+//                 wformat-string<Args...> fmt, const Args&... args);
 
 #include <format>
 #include <algorithm>
@@ -60,23 +60,11 @@
   }
 };
 
-auto test_exception = []<class CharT, class... Args>(std::string_view what, std::basic_string_view<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 (const std::format_error& e) {
-    LIBCPP_ASSERT(e.what() == what);
-    return;
-  }
-  assert(false);
-#else
-  (void)what;
-  (void)fmt;
-  (void)sizeof...(args);
-#endif
+auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, const Args&...) {
+  // After P2216 most exceptions thrown by std::format_to become ill-formed.
+  // Therefore this tests does nothing.
+  // A basic ill-formed test is done in format_to.locale.verify.cpp
+  // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
 };
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.locale.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.locale.verify.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.locale.verify.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+// 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: no-localization
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// Basic test to validate ill-formed code is properly detected.
+
+// <format>
+
+// template<class Out, class... Args>
+//   Out format_to(Out out, const locale& loc,
+//                 format-string<Args...> fmt, const Args&... args);
+// template<class Out, class... Args>
+//   Out format_to(Out out, const locale& loc,
+//                 wformat-string<Args...> fmt, const Args&... args);
+
+#include <format>
+#include <locale>
+
+#include "test_macros.h"
+
+extern char* out;
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+extern wchar_t* wout;
+#endif
+
+// clang-format off
+
+void f() {
+  std::format_to(out, std::locale(), "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, std::locale(), "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, std::locale(), "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format_to(out, std::locale(), "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, std::locale(), "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, std::locale(), "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, std::locale(), "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, std::locale(), "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, std::locale(), "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, std::locale(), "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  std::format_to(wout, std::locale(), L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, std::locale(), L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, std::locale(), L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format_to(wout, std::locale(), L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, std::locale(), L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, std::locale(), L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, std::locale(), L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, std::locale(), L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, std::locale(), L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, std::locale(), L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+#endif
+}
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
--- a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
@@ -15,9 +15,9 @@
 // <format>
 
 // template<class Out, class... Args>
-//   Out format_to(Out out, string_view fmt, const Args&... args);
+//   Out format_to(Out out, format-string<Args...> fmt, const Args&... args);
 // template<class Out, class... Args>
-//   Out format_to(Out out, wstring_view fmt, const Args&... args);
+//   Out format_to(Out out, wformat-string<Args...> fmt, const Args&... args);
 
 #include <format>
 #include <algorithm>
@@ -57,23 +57,11 @@
   }
 };
 
-auto test_exception = []<class CharT, class... Args>(std::string_view what, std::basic_string_view<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 (const std::format_error& e) {
-    LIBCPP_ASSERT(e.what() == what);
-    return;
-  }
-  assert(false);
-#else
-  (void)what;
-  (void)fmt;
-  (void)sizeof...(args);
-#endif
+auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, const Args&...) {
+  // After P2216 most exceptions thrown by std::format become ill-formed.
+  // Therefore this tests does nothing.
+  // A basic ill-formed test is done in format.verify.cpp
+  // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
 };
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.verify.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.verify.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+// 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-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// <format>
+
+// Basic test to validate ill-formed code is properly detected.
+
+// template<class Out, class... Args>
+//   Out format_to(Out out, format-string<Args...> fmt, const Args&... args);
+// template<class Out, class... Args>
+//   Out format_to(Out out, wformat-string<Args...> fmt, const Args&... args);
+
+#include <format>
+
+#include "test_macros.h"
+
+extern char* out;
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+extern wchar_t* wout;
+#endif
+
+// clang-format off
+
+void f() {
+  std::format_to(out, "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format_to(out, "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(out, "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  std::format_to(wout, L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format_to(wout, L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to(wout, L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+#endif
+}
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
--- 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
@@ -17,11 +17,11 @@
 
 // template<class Out, class... Args>
 //   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
-//                                       const locale& loc, string_view fmt,
+//                                       const locale& loc, format-string<Args...> fmt,
 //                                       const Args&... args);
 // template<class Out, class... Args>
 //   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
-//                                       const locale& loc, wstring_view fmt,
+//                                       const locale& loc, wformat-string<Args...> fmt,
 //                                       const Args&... args);
 
 #include <format>
@@ -98,23 +98,11 @@
   }
 };
 
-auto test_exception = []<class CharT, class... Args>(std::string_view what, std::basic_string_view<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 (const std::format_error& e) {
-    LIBCPP_ASSERT(e.what() == what);
-    return;
-  }
-  assert(false);
-#else
-  (void)what;
-  (void)fmt;
-  (void)sizeof...(args);
-#endif
+auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, const Args&...) {
+  // After P2216 most exceptions thrown by std::format_to_n become ill-formed.
+  // Therefore this tests does nothing.
+  // A basic ill-formed test is done in format_to_n.locale.verify.cpp
+  // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
 };
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.verify.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.verify.cpp
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+// 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: no-localization
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// Basic test to validate ill-formed code is properly detected.
+
+// <format>
+
+// template<class Out, class... Args>
+//   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
+//                                       const locale& loc, format-string<Args...> fmt,
+//                                       const Args&... args);
+// template<class Out, class... Args>
+//   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
+//                                       const locale& loc, wformat-string<Args...> fmt,
+//                                       const Args&... args);
+
+#include <format>
+#include <locale>
+
+#include "test_macros.h"
+
+extern char* out;
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+extern wchar_t* wout;
+#endif
+
+// clang-format off
+
+void f() {
+  std::format_to_n(out, 42, std::locale(), "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, std::locale(), "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, std::locale(), "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format_to_n(out, 42, std::locale(), "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, std::locale(), "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, std::locale(), "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, std::locale(), "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, std::locale(), "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, std::locale(), "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, std::locale(), "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  std::format_to_n(wout, 42, std::locale(), L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, std::locale(), L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, std::locale(), L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format_to_n(wout, 42, std::locale(), L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, std::locale(), L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, std::locale(), L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, std::locale(), L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, std::locale(), L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, std::locale(), L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, std::locale(), L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+#endif
+}
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
--- 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
@@ -16,10 +16,10 @@
 
 // template<class Out, class... Args>
 //   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
-//                                       string_view fmt, const Args&... args);
+//                                       format-string<Args...> fmt, const Args&... args);
 // template<class Out, class... Args>
 //   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
-//                                       wstring_view fmt, const Args&... args);
+//                                       wformat-string<Args...> fmt, const Args&... args);
 
 #include <format>
 #include <algorithm>
@@ -91,23 +91,11 @@
   }
 };
 
-auto test_exception = []<class CharT, class... Args>(std::string_view what, std::basic_string_view<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 (const std::format_error& e) {
-    LIBCPP_ASSERT(e.what() == what);
-    return;
-  }
-  assert(false);
-#else
-  (void)what;
-  (void)fmt;
-  (void)sizeof...(args);
-#endif
+auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, const Args&...) {
+  // After P2216 most exceptions thrown by std::format_to_n become ill-formed.
+  // Therefore this tests does nothing.
+  // A basic ill-formed test is done in format_to_n.verify.cpp
+  // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
 };
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.verify.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.verify.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.verify.cpp
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+// 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-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// Basic test to validate ill-formed code is properly detected.
+
+// <format>
+
+// template<class Out, class... Args>
+//   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
+//                                       format-string<Args...> fmt, const Args&... args);
+// template<class Out, class... Args>
+//   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
+//                                       wformat-string<Args...> fmt, const Args&... args);
+
+#include <format>
+
+#include "test_macros.h"
+
+extern char* out;
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+extern wchar_t* wout;
+#endif
+
+// clang-format off
+
+void f() {
+  std::format_to_n(out, 42, "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format_to_n(out, 42, "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(out, 42, "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  std::format_to_n(wout, 42, L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::format_to_n(wout, 42, L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::format_to_n(wout, 42, L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+#endif
+}
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
--- 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
@@ -17,10 +17,10 @@
 
 // template<class... Args>
 //   size_t formatted_size(const locale& loc,
-//                         string_view fmt, const Args&... args);
+//                         format-string<Args...> fmt, const Args&... args);
 // template<class... Args>
 //   size_t formatted_size(const locale& loc,
-//                         wstring_view fmt, const Args&... args);
+//                         wformat-string<Args...> fmt, const Args&... args);
 
 #include <format>
 #include <cassert>
@@ -36,22 +36,11 @@
   assert(size == expected.size());
 };
 
-auto test_exception = []<class CharT, class... Args>(std::string_view what, std::basic_string_view<CharT> fmt,
-                                                     const Args&... args) {
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  try {
-    std::formatted_size(std::locale(), fmt, args...);
-    assert(false);
-  } catch (const std::format_error& e) {
-    LIBCPP_ASSERT(e.what() == what);
-    return;
-  }
-  assert(false);
-#else
-  (void)what;
-  (void)fmt;
-  (void)sizeof...(args);
-#endif
+auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, const Args&...) {
+  // After P2216 most exceptions thrown by std::formatted_siz3 become ill-formed.
+  // Therefore this tests does nothing.
+  // A basic ill-formed test is done in formatted_size.locale.verify.cpp
+  // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
 };
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.verify.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.verify.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.verify.cpp
@@ -0,0 +1,94 @@
+//===----------------------------------------------------------------------===//
+// 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: no-localization
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// Basic test to validate ill-formed code is properly detected.
+
+// <format>
+
+// template<class... Args>
+//   size_t formatted_size(const locale& loc,
+//                         format-string<Args...> fmt, const Args&... args);
+// template<class... Args>
+//   size_t formatted_size(const locale& loc,
+//                         wformat-string<Args...> fmt, const Args&... args);
+
+#include <format>
+#include <locale>
+
+#include "test_macros.h"
+
+// clang-format off
+
+void f() {
+  std::formatted_size(std::locale(), "{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), "}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), "{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::formatted_size(std::locale(), "{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), "{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), "{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), "{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), "{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), "{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), "{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  std::formatted_size(std::locale(), L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::formatted_size(std::locale(), L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(std::locale(), L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+#endif
+}
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
--- a/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp
@@ -15,9 +15,9 @@
 // <format>
 
 // template<class... Args>
-//   size_t formatted_size(string_view fmt, const Args&... args);
+//   size_t formatted_size(format-string<Args...> fmt, const Args&... args);
 // template<class... Args>
-//   size_t formatted_size(wstring_view fmt, const Args&... args);
+//   size_t formatted_size(wformat-string<Args...> fmt, const Args&... args);
 
 #include <format>
 #include <cassert>
@@ -33,22 +33,11 @@
   assert(size == expected.size());
 };
 
-auto test_exception = []<class CharT, class... Args>(std::string_view what, std::basic_string_view<CharT> fmt,
-                                                     const Args&... args) {
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  try {
-    std::formatted_size(fmt, args...);
-    assert(false);
-  } catch (const std::format_error& e) {
-    LIBCPP_ASSERT(e.what() == what);
-    return;
-  }
-  assert(false);
-#else
-  (void)what;
-  (void)fmt;
-  (void)sizeof...(args);
-#endif
+auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, const Args&...) {
+  // After P2216 most exceptions thrown by std::formatted_siz3 become ill-formed.
+  // Therefore this tests does nothing.
+  // A basic ill-formed test is done in formatted_size.verify.cpp
+  // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
 };
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.verify.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.verify.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.verify.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-has-no-incomplete-format
+// TODO FMT Evaluate gcc-11 status
+// UNSUPPORTED: gcc-11
+
+// Basic test to validate ill-formed code is properly detected.
+
+// <format>
+
+// template<class... Args>
+//   size_t formatted_size(format-string<Args...> fmt, const Args&... args);
+// template<class... Args>
+//   size_t formatted_size(wformat-string<Args...> fmt, const Args&... args);
+
+#include <format>
+
+#include "test_macros.h"
+
+// clang-format off
+
+void f() {
+  std::formatted_size("{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size("}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size("{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::formatted_size("{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size("{:-}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size("{:#}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size("{:L}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size("{0:{0}}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size("{:.42d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size("{:d}", "Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  std::formatted_size(L"{"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(L"}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(L"{}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{read of dereferenced null pointer is not allowed in a constant expression}}
+
+  std::formatted_size(L"{0}"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(L"{:-}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(L"{:#}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(L"{:L}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(L"{0:{0}}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(L"{:.42d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+
+  std::formatted_size(L"{:d}", L"Forty-two"); // expected-error-re{{call to consteval function '{{.*}}' is not a constant expression}}
+  // expected-note@*:* {{non-constexpr function '__throw_format_error' cannot be used in a constant expression}}
+#endif
+}