[llvm-branch-commits] [libcxx] 1324903 - [libc++][format] Exposes basic-format-string

Tom Stellard via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Aug 10 18:06:13 PDT 2022


Author: Mark de Wever
Date: 2022-08-10T17:52:20-07:00
New Revision: 13249036b774e4e5dc346d1f1a348f4ba201537a

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

LOG: [libc++][format] Exposes basic-format-string

This paper was accepted during the last plenary and is intended to be
backported to LLVM 15. When backporting the release notes in the branch
should be updated too.

Note the feature-test macro isn't updated since this will change; three
papers have updated the same macro in the same plenary.

Implements:
- P2508R1 Exposing std::basic-format-string

Reviewed By: ldionne, #libc

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

(cherry picked from commit f712775dafdb221fdf73f38819fa9e618aec6b67)

Added: 
    libcxx/test/std/utilities/format/format.fmt.string/ctor.verify.cpp
    libcxx/test/std/utilities/format/format.fmt.string/get.pass.cpp
    libcxx/test/std/utilities/format/format.fmt.string/types.compile.pass.cpp

Modified: 
    libcxx/docs/ReleaseNotes.rst
    libcxx/docs/Status/Cxx2bPapers.csv
    libcxx/docs/Status/FormatIssues.csv
    libcxx/include/format
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index c717ea2682b54..6acde0db864bf 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -63,6 +63,7 @@ Implemented Papers
 - P2418R2 - Add support for ``std::generator``-like types to ``std::format``
 - LWG3659 - Consider ``ATOMIC_FLAG_INIT`` undeprecation
 - P1423R3 - ``char8_t`` backward compatibility remediation
+- P2508R1 - Exposing ``std::basic-format-string``
 
 - Marked the following papers as "Complete" (note that some of those might have
   been implemented in a previous release but not marked as such):

diff  --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv
index 4c5dd10db0684..27ff57c92150f 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -81,7 +81,7 @@
 "`P2494R2 <https://wg21.link/P2494R2>`__","LWG","Relaxing range adaptors to allow for move only types","July 2022","",""
 "`P2499R0 <https://wg21.link/P2499R0>`__","LWG","``string_view`` range constructor should be ``explicit``","July 2022","",""
 "`P2502R2 <https://wg21.link/P2502R2>`__","LWG","``std::generator``: Synchronous Coroutine Generator for Ranges","July 2022","",""
-"`P2508R1 <https://wg21.link/P2508R1>`__","LWG","Exposing ``std::basic-format-string``","July 2022","",""
+"`P2508R1 <https://wg21.link/P2508R1>`__","LWG","Exposing ``std::basic-format-string``","July 2022","|Complete|","15.0"
 "`P2513R4 <https://wg21.link/P2513R4>`__","LWG","``char8_t`` Compatibility and Portability Fixes","July 2022","",""
 "`P2517R1 <https://wg21.link/P2517R1>`__","LWG","Add a conditional ``noexcept`` specification to ``std::apply``","July 2022","",""
 "`P2520R0 <https://wg21.link/P2520R0>`__","LWG","``move_iterator`` should be a random access iterator","July 2022","",""

diff  --git a/libcxx/docs/Status/FormatIssues.csv b/libcxx/docs/Status/FormatIssues.csv
index 3f7304520c9e9..c3bdf169e82b1 100644
--- a/libcxx/docs/Status/FormatIssues.csv
+++ b/libcxx/docs/Status/FormatIssues.csv
@@ -5,6 +5,7 @@ Number,Name,Assignee,Patch,Status,First released version
 `P1868 <https://wg21.link/P1868>`_,"width: clarifying units of width and precision in std::format (Implements the unicode support.)",Mark de Wever,"`D103413 <https://reviews.llvm.org/D103413>`__ `D103425 <https://reviews.llvm.org/D103425>`__ `D103670 <https://reviews.llvm.org/D103670>`__",|Complete|,Clang 14
 `P2216 <https://wg21.link/P2216>`_,"std::format improvements",Mark de Wever,,|Complete|,Clang 15
 `P2418 <https://wg21.link/P2418>`__,"Add support for ``std::generator``-like types to ``std::format``",Mark de Wever,`D127570 <https://reviews.llvm.org/D127570>`__,|Complete|, Clang 15
+`P2508R1 <https://wg21.link/P2508R1>`__,"Exposing ``std::basic-format-string``","C++23","Mark de Wever","|Complete|",Clang 15
 
 `P1361 <https://wg21.link/P1361>`_,"Integration of chrono with text formatting",Mark de Wever,,|In Progress|,
 `P2372 <https://wg21.link/P2372>`__,"Fixing locale handling in chrono formatters",Mark de Wever,,|In Progress|,

diff  --git a/libcxx/include/format b/libcxx/include/format
index d2ec8fc233634..6b14570bc6272 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -23,16 +23,23 @@ namespace std {
   using format_args = basic_format_args<format_context>;
   using wformat_args = basic_format_args<wformat_context>;
 
-  // [format.fmt.string], class template basic-format-string
+  // [format.fmt.string], class template basic_format_string
   template<class charT, class... Args>
-    struct basic-format-string;                       // exposition only
+    struct basic_format_string {                                // since C++23, exposition only before C++23
+    private:
+      basic_string_view<charT> str;                             // exposition only
 
+    public:
+      template<class T> consteval basic_format_string(const T& s);
+
+      constexpr basic_string_view<charT> get() const noexcept { return str; }
+    };
   template<class... Args>
-    using format-string =                             // exposition only
-      basic-format-string<char, type_identity_t<Args>...>;
+    using format_string =                                       // since C++23, exposition only before C++23
+      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>...>;
+    using wformat_string =                                      // since C++23, exposition only before C++23
+      basic_format_string<wchar_t, type_identity_t<Args>...>;
 
   // [format.functions], formatting functions
   template<class... Args>
@@ -233,7 +240,7 @@ private:
 };
 
 // Dummy format_context only providing the parts used during constant
-// validation of the basic-format-string.
+// validation of the basic_format_string.
 template <class _CharT>
 struct _LIBCPP_TEMPLATE_VIS __compile_time_basic_format_context {
 public:
@@ -468,17 +475,21 @@ __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
 } // namespace __format
 
 template <class _CharT, class... _Args>
-struct _LIBCPP_TEMPLATE_VIS __basic_format_string {
-  basic_string_view<_CharT> __str_;
-
+struct _LIBCPP_TEMPLATE_VIS basic_format_string {
   template <class _Tp>
     requires convertible_to<const _Tp&, basic_string_view<_CharT>>
-  consteval __basic_format_string(const _Tp& __str) : __str_{__str} {
+  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(), sizeof...(_Args)});
   }
 
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT constexpr basic_string_view<_CharT> get() const noexcept {
+    return __str_;
+  }
+
 private:
+  basic_string_view<_CharT> __str_;
+
   using _Context = __format::__compile_time_basic_format_context<_CharT>;
 
   static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{
@@ -510,11 +521,11 @@ private:
 };
 
 template <class... _Args>
-using __format_string_t = __basic_format_string<char, type_identity_t<_Args>...>;
+using format_string = basic_format_string<char, type_identity_t<_Args>...>;
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <class... _Args>
-using __wformat_string_t = __basic_format_string<wchar_t, type_identity_t<_Args>...>;
+using wformat_string = basic_format_string<wchar_t, type_identity_t<_Args>...>;
 #endif
 
 template <class _OutIt, class _CharT, class _FormatOutIt>
@@ -555,16 +566,16 @@ vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {
 
 template <output_iterator<const char&> _OutIt, class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-format_to(_OutIt __out_it, __format_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.__str_,
+format_to(_OutIt __out_it, format_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(),
                            _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, __wformat_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.__str_,
+format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(),
                            _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -586,16 +597,16 @@ vformat(wstring_view __fmt, wformat_args __args) {
 #endif
 
 template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(__format_string_t<_Args...> __fmt,
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(format_string<_Args...> __fmt,
                                                                                       _Args&&... __args) {
-  return _VSTD::vformat(__fmt.__str_, _VSTD::make_format_args(__args...));
+  return _VSTD::vformat(__fmt.get(), _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(__wformat_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::vformat(__fmt.__str_, _VSTD::make_wformat_args(__args...));
+format(wformat_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::vformat(__fmt.get(), _VSTD::make_wformat_args(__args...));
 }
 #endif
 
@@ -611,16 +622,16 @@ _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it,
 
 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_
diff erence_t<_OutIt> __n, __format_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, __fmt.__str_, _VSTD::make_format_args(__args...));
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, format_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_format_args(__args...));
 }
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 template <output_iterator<const wchar_t&> _OutIt, class... _Args>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, __wformat_string_t<_Args...> __fmt,
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, wformat_string<_Args...> __fmt,
             _Args&&... __args) {
-  return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, __fmt.__str_, _VSTD::make_wformat_args(__args...));
+  return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_wformat_args(__args...));
 }
 #endif
 
@@ -634,15 +645,15 @@ _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt,
 
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(__format_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::__vformatted_size(__fmt.__str_, basic_format_args{_VSTD::make_format_args(__args...)});
+formatted_size(format_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::__vformatted_size(__fmt.get(), 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(__wformat_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::__vformatted_size(__fmt.__str_, basic_format_args{_VSTD::make_wformat_args(__args...)});
+formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
 }
 #endif
 
@@ -686,16 +697,16 @@ _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt v
 
 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, __format_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.__str_,
+format_to(_OutIt __out_it, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(),
                            _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, __wformat_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.__str_,
+format_to(_OutIt __out_it, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(),
                            _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -720,17 +731,17 @@ vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
 
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(locale __loc,
-                                                                                      __format_string_t<_Args...> __fmt,
+                                                                                      format_string<_Args...> __fmt,
                                                                                       _Args&&... __args) {
-  return _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_,
+  return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
                         _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, __wformat_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::vformat(_VSTD::move(__loc), __fmt.__str_,
+format(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
                         _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -748,18 +759,18 @@ _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it,
 
 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_
diff erence_t<_OutIt> __n, locale __loc, __format_string_t<_Args...> __fmt,
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc, format_string<_Args...> __fmt,
             _Args&&... __args) {
-  return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.__str_,
+  return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(),
                                                _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_
diff erence_t<_OutIt> __n, locale __loc, __wformat_string_t<_Args...> __fmt,
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc, wformat_string<_Args...> __fmt,
             _Args&&... __args) {
-  return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.__str_,
+  return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(),
                                                 _VSTD::make_wformat_args(__args...));
 }
 #endif
@@ -775,15 +786,15 @@ _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_
 
 template <class... _Args>
 _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(locale __loc, __format_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.__str_, basic_format_args{_VSTD::make_format_args(__args...)});
+formatted_size(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), 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, __wformat_string_t<_Args...> __fmt, _Args&&... __args) {
-  return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.__str_, basic_format_args{_VSTD::make_wformat_args(__args...)});
+formatted_size(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
+  return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
 }
 #endif
 

diff  --git a/libcxx/test/std/utilities/format/format.fmt.string/ctor.verify.cpp b/libcxx/test/std/utilities/format/format.fmt.string/ctor.verify.cpp
new file mode 100644
index 0000000000000..8f5404daaf396
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.fmt.string/ctor.verify.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// libc++ supports basic_format_string in C++20 as an extension
+// UNSUPPORTED: !stdlib=libc++ && c++20
+
+// <format>
+
+// template<class charT, class... Args>
+// class basic_format_string<charT, type_identity_t<Args>...>
+//
+// template<class T> consteval basic_format_string(const T& s);
+//
+// This constructor does the compile-time format string validation for the
+// std::format* functions.
+
+#include <format>
+
+#include <string_view>
+
+#include "test_macros.h"
+
+void run() {
+  (void)std::basic_format_string<char>{"foo"};
+  (void)std::basic_format_string<char>{"{}"}; // expected-error-re {{call to consteval function{{.*}}is not a constant expression}}
+  (void)std::basic_format_string<char, int>{"{0:{0}P}"}; // expected-error-re {{call to consteval function{{.*}}is not a constant expression}}
+  (void)std::basic_format_string<char, int>{"{0:{0}}"};
+  (void)std::basic_format_string<char, float>{"{0:{0}}"}; // expected-error-re {{call to consteval function{{.*}}is not a constant expression}}
+  (void)std::basic_format_string<char, int>{"{.3}"}; // expected-error-re {{call to consteval function{{.*}}is not a constant expression}}
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  (void)std::basic_format_string<wchar_t>{L"foo"};
+  (void)std::basic_format_string<wchar_t>{L"{}"}; // expected-error-re {{call to consteval function{{.*}}is not a constant expression}}
+  (void)std::basic_format_string<wchar_t, int>{L"{0:{0}P}"}; // expected-error-re {{call to consteval function{{.*}}is not a constant expression}}
+  (void)std::basic_format_string<wchar_t, int>{L"{0:{0}}"};
+  (void)std::basic_format_string<wchar_t, float>{L"{0:{0}}"}; // expected-error-re {{call to consteval function{{.*}}is not a constant expression}}
+  (void)std::basic_format_string<wchar_t, int>{L"{.3}"}; // expected-error-re {{call to consteval function{{.*}}is not a constant expression}}
+#endif
+}

diff  --git a/libcxx/test/std/utilities/format/format.fmt.string/get.pass.cpp b/libcxx/test/std/utilities/format/format.fmt.string/get.pass.cpp
new file mode 100644
index 0000000000000..bf7e2add0e8f5
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.fmt.string/get.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+
+// libc++ supports basic_format_string in C++20 as an extension
+// UNSUPPORTED: !stdlib=libc++ && c++20
+
+// <format>
+
+// template<class charT, class... Args>
+// class basic_format_string<charT, type_identity_t<Args>...>
+//
+// constexpr basic_string_view<charT> get() const noexcept { return str; }
+
+#include <format>
+
+#include <cassert>
+#include <concepts>
+#include <string_view>
+
+#include "test_macros.h"
+#include "make_string.h"
+
+#define CSTR(S) MAKE_CSTRING(CharT, S)
+#define SV(S) MAKE_STRING_VIEW(CharT, S)
+
+template <class CharT>
+constexpr bool test() {
+  assert((std::basic_format_string<CharT>{CSTR("foo")}.get() == SV("foo")));
+  assert((std::basic_format_string<CharT, int>{CSTR("{}")}.get() == SV("{}")));
+  assert((std::basic_format_string<CharT, int, float>{CSTR("{} {:01.23L}")}.get() == SV("{} {:01.23L}")));
+
+  // Embedded NUL character
+  assert((std::basic_format_string<CharT, void*, double>{SV("{}\0{}")}.get() == SV("{}\0{}")));
+  return true;
+}
+
+int main(int, char**) {
+  test<char>();
+  static_assert(test<char>());
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  static_assert(test<wchar_t>());
+#endif
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/format/format.fmt.string/types.compile.pass.cpp b/libcxx/test/std/utilities/format/format.fmt.string/types.compile.pass.cpp
new file mode 100644
index 0000000000000..3ebd2bfc4fbd5
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.fmt.string/types.compile.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-has-no-incomplete-format
+
+// libc++ supports basic_format_string in C++20 as an extension
+// UNSUPPORTED: !stdlib=libc++ && c++20
+
+// <format>
+
+//  template<class... Args>
+//    using format_string =
+//      basic_format_string<char, type_identity_t<Args>...>;
+//  template<class... Args>
+//    using wformat_string =
+//      basic_format_string<wchar_t, type_identity_t<Args>...>;
+
+#include <format>
+
+#include <concepts>
+
+#include "test_macros.h"
+
+static_assert(std::same_as<std::format_string<>, std::basic_format_string<char>>);
+static_assert(std::same_as<std::format_string<int>, std::basic_format_string<char, int>>);
+static_assert(std::same_as<std::format_string<int, float>, std::basic_format_string<char, int, float>>);
+static_assert(std::same_as<std::format_string<int, float, void*>, std::basic_format_string<char, int, float, void*>>);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::same_as<std::wformat_string<>, std::basic_format_string<wchar_t>>);
+static_assert(std::same_as<std::wformat_string<int>, std::basic_format_string<wchar_t, int>>);
+static_assert(std::same_as<std::wformat_string<int, float>, std::basic_format_string<wchar_t, int, float>>);
+static_assert(
+    std::same_as<std::wformat_string<int, float, void*>, std::basic_format_string<wchar_t, int, float, void*>>);
+#endif

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 6b8db98242f29..f9bfa13cc2991 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -309,6 +309,11 @@ def add_version_header(tc):
     "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem)"
   }, {
     "name": "__cpp_lib_format",
+    # P2508, P2286, and P2419 were accepted in the same plenary and modify this
+    # feature-test macro. We expect to see an LWG issue soon. For now keep the
+    # value as is.
+    # TODO FMT Set P2508's feature-test macro.
+    #"values": { "c++20": 202106, "c++23": 202207" },
     "values": { "c++20": 202106 },
     "headers": ["format"],
     "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)",


        


More information about the llvm-branch-commits mailing list