[libcxx-commits] [libcxx] [RFC][libc++] Improves feature-test marcros. (PR #88630)

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Sat Apr 13 10:56:53 PDT 2024


https://github.com/mordante created https://github.com/llvm/llvm-project/pull/88630

The original feature-test macro script was written when feature-test macros were a new feature. Since that time they have become wide spread in both the language and the library. The current design has a huge draw-back; there is only one flag to determine whether a feature-test macro is implemented. This means when for a feature-test macro __cpp_lib_foo all C++20 papers are implemented, but none of the C++23 papers. This is not visible. The same when multiple papers update the same macro to the same version. At the moment this information is added as comment in the source, but not visible on the html page.

The headers and the guards are not duplicated per version. These values tend to remain the same between language versions. (Adding the macro to more headers than required is not an issue; we already always include the header version.)

Another thing that is missing is the information which papers need still to be implemented to set the macro. Recently during updating the status after a WG21 plenary I've added this as comment. This is now shown on the html page.

This update status page is intended to track the feature-test macro stage. This is not intended to be an alternative paper/LWG issue status tracker; not all papers add or modify a feature-test macro.

The intention is to only add the additional information for newer standards and not to retroactively add all entries; this information is available at
https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros.

The script is copied from the original and only a few entries have been converted to the new style; just to show some examples.

Note the patch only changes the rst output, adapting the other outputs would be trivial. These outputs should remain unchanged.

Note the code itself can use more polishing.

>From 5e115d80283d01cf5e063178bc97e2369b695d24 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Mon, 8 Apr 2024 21:46:06 +0200
Subject: [PATCH] [RFC][libc++] Improves feature-test marcros.

The original feature-test macro script was written when feature-test
macros were a new feature. Since that time they have become wide spread in
both the language and the library. The current design has a huge
draw-back; there is only one flag to determine whether a feature-test
macro is implemented. This means when for a feature-test macro
__cpp_lib_foo all C++20 papers are implemented, but none of the C++23
papers. This is not visible. The same when multiple papers update the same
macro to the same version. At the moment this information is added as
comment in the source, but not visible on the html page.

The headers and the guards are not duplicated per version. These values
tend to remain the same between language versions. (Adding the macro to
more headers than required is not an issue; we already always include the
header version.)

Another thing that is missing is the information which papers need still
to be implemented to set the macro. Recently during updating the status
after a WG21 plenary I've added this as comment. This is now shown on the
html page.

This update status page is intended to track the feature-test macro stage.
This is not intended to be an alternative paper/LWG issue status tracker;
not all papers add or modify a feature-test macro.

The intention is to only add the additional information for newer
standards and not to retroactively add all entries; this information is
available at
https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros.

The script is copied from the original and only a few entries have been
converted to the new style; just to show some examples.

Note the patch only changes the rst output, adapting the other outputs
would be trivial. These outputs should remain unchanged.

Note the code itself can use more polishing.
---
 libcxx/docs/FeatureTestMacroTable.rst         | 477 +---------
 libcxx/utils/CMakeLists.txt                   |   6 +-
 ...nerate_feature_test_macro_components_v2.py | 825 ++++++++++++++++++
 3 files changed, 867 insertions(+), 441 deletions(-)
 create mode 100644 libcxx/utils/generate_feature_test_macro_components_v2.py

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 3197d2cd1b271c..f4e39c96457785 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -11,6 +11,9 @@ Overview
 ========
 
 This file documents the feature test macros currently supported by libc++.
+For older language version not all details are available. This information can
+be found at the `isoccp
+<https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros>`__.
 
 .. _feature-status:
 
@@ -21,449 +24,43 @@ Status
     :name: feature-status-table
     :widths: auto
 
-    ========================================================== =================
-    Macro Name                                                 Value
-    ========================================================== =================
+    ======================= ================= ========= === ===============================================================================================================
+    Macro Name              Status            Value         Paper
+    ======================= ================= ========= === ===============================================================================================================
     **C++14**
-    ----------------------------------------------------------------------------
-    ``__cpp_lib_chrono_udls``                                  ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_complex_udls``                                 ``201309L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_exchange_function``                            ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_generic_associative_lookup``                   ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_integer_sequence``                             ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_integral_constant_callable``                   ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_final``                                     ``201402L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_null_pointer``                              ``201309L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_make_reverse_iterator``                        ``201402L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_make_unique``                                  ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_null_iterators``                               ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_quoted_string_io``                             ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_result_of_sfinae``                             ``201210L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_robust_nonmodifying_seq_ops``                  ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_shared_timed_mutex``                           ``201402L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_string_udls``                                  ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_transformation_trait_aliases``                 ``201304L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_transparent_operators``                        ``201210L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_tuple_element_t``                              ``201402L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_tuples_by_type``                               ``201304L``
-    ---------------------------------------------------------- -----------------
+    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
     **C++17**
-    ----------------------------------------------------------------------------
-    ``__cpp_lib_addressof_constexpr``                          ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_allocator_traits_is_always_equal``             ``201411L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_any``                                          ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_apply``                                        ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_array_constexpr``                              ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_as_const``                                     ``201510L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_is_always_lock_free``                   ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_bool_constant``                                ``201505L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_boyer_moore_searcher``                         ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_byte``                                         ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_chrono``                                       ``201611L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_clamp``                                        ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_enable_shared_from_this``                      ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_execution``                                    *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_filesystem``                                   ``201703L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_gcd_lcm``                                      ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_hardware_interference_size``                   ``201703L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_has_unique_object_representations``            ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_hypot``                                        ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_incomplete_container_elements``                ``201505L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_invoke``                                       ``201411L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_aggregate``                                 ``201703L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_invocable``                                 ``201703L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_swappable``                                 ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_launder``                                      ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_logical_traits``                               ``201510L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_make_from_tuple``                              ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_map_try_emplace``                              ``201411L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_math_special_functions``                       *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_memory_resource``                              ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_node_extract``                                 ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_nonmember_container_access``                   ``201411L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_not_fn``                                       ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_optional``                                     ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_parallel_algorithm``                           *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_raw_memory_algorithms``                        ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_sample``                                       ``201603L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_scoped_lock``                                  ``201703L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_shared_mutex``                                 ``201505L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_shared_ptr_arrays``                            ``201611L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_shared_ptr_weak_type``                         ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_string_view``                                  ``201606L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_to_chars``                                     *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_transparent_operators``                        ``201510L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_type_trait_variable_templates``                ``201510L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_uncaught_exceptions``                          ``201411L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_unordered_map_try_emplace``                    ``201411L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_variant``                                      ``202102L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_void_t``                                       ``201411L``
-    ---------------------------------------------------------- -----------------
+    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+    ``__cpp_lib_any``       *201606L*         201606L   ✅
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
+    ``__cpp_lib_variant``   *202102L*         202102L   ✅   ``std::visit`` for classes derived from ``std::variant``
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
     **C++20**
-    ----------------------------------------------------------------------------
-    ``__cpp_lib_array_constexpr``                              ``201811L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_assume_aligned``                               ``201811L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_flag_test``                             ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_float``                                 *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_lock_free_type_aliases``                ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_ref``                                   *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_shared_ptr``                            *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_value_initialization``                  ``201911L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_wait``                                  ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_barrier``                                      ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_bind_front``                                   ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_bit_cast``                                     ``201806L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_bitops``                                       ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_bounded_array_traits``                         ``201902L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_char8_t``                                      ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_concepts``                                     ``202002L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_algorithms``                         ``201806L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_complex``                            ``201711L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_dynamic_alloc``                      ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_functional``                         ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_iterator``                           ``201811L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_memory``                             ``201811L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_numeric``                            ``201911L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_string``                             ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_string_view``                        ``201811L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_tuple``                              ``201811L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_utility``                            ``201811L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_vector``                             ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_coroutine``                                    ``201902L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_destroying_delete``                            ``201806L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_endian``                                       ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_erase_if``                                     ``202002L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_execution``                                    *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_format``                                       *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_format_uchar``                                 ``202311L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_generic_unordered_lookup``                     ``201811L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_int_pow2``                                     ``202002L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_integer_comparison_functions``                 ``202002L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_interpolate``                                  ``201902L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_constant_evaluated``                        ``201811L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_layout_compatible``                         *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_nothrow_convertible``                       ``201806L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_pointer_interconvertible``                  *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_jthread``                                      ``201911L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_latch``                                        ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_list_remove_return_type``                      ``201806L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_math_constants``                               ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_move_iterator_concept``                        ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_polymorphic_allocator``                        ``201902L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges``                                       ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_remove_cvref``                                 ``201711L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_semaphore``                                    ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_shared_ptr_arrays``                            ``201707L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_shift``                                        ``201806L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_smart_ptr_for_overwrite``                      *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_source_location``                              ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_span``                                         ``202002L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ssize``                                        ``201902L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_starts_ends_with``                             ``201711L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_string_view``                                  ``201803L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_syncbuf``                                      ``201803L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_three_way_comparison``                         *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_to_address``                                   ``201711L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_to_array``                                     ``201907L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_type_identity``                                ``201806L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_unwrap_ref``                                   ``201811L``
-    ---------------------------------------------------------- -----------------
+    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+    ``__cpp_lib_barrier``   *201907L*         201907L   ✅
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
+    ``__cpp_lib_format``    *unimplemented*   201907L   ✅   `P0645R10 <https://wg21.link/P0645R10>`__ Text Formatting
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
+    * *                                       201907L   ❌   `P1361R2 <https://wg21.link/P1361R2>`__ Integration of chrono with text formatting
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
+    * *                                       202106L   ✅   `P2216R3 <https://wg21.link/P2216R3>`__ std::format improvements
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
+    * *                                       202110L   ❌   `P2372R3 <https://wg21.link/P2372R3>`__ Fixing locale handling in chrono formatters
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
+    * *                                       202110L   ✅   `P2418R2 <https://wg21.link/P2418R2>`__ FAdd support for std::generator-like types to std::format
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
+    ``__cpp_lib_variant``   *202102L*         202106L   ❌   Fully constexpr ``std::variant``
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
     **C++23**
-    ----------------------------------------------------------------------------
-    ``__cpp_lib_adaptor_iterator_pair_constructor``            ``202106L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_allocate_at_least``                            ``202302L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_associative_heterogeneous_erasure``            *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_bind_back``                                    ``202202L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_byteswap``                                     ``202110L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_bitset``                             ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_charconv``                           ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_cmath``                              *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_memory``                             ``202202L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_typeinfo``                           ``202106L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_expected``                                     ``202211L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_format_path``                                  *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_format_ranges``                                ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_formatters``                                   *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_forward_like``                                 ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_invoke_r``                                     ``202106L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ios_noreplace``                                ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_is_scoped_enum``                               ``202011L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_mdspan``                                       ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_move_only_function``                           *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_optional``                                     ``202110L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_out_ptr``                                      *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_print``                                        ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_as_const``                              *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_as_rvalue``                             ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_chunk``                                 *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_chunk_by``                              ``202202L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_contains``                              ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_iota``                                  *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_join_with``                             *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_repeat``                                ``202207L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_slide``                                 *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_starts_ends_with``                      ``202106L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_to_container``                          ``202202L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_zip``                                   *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_reference_from_temporary``                     *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_spanstream``                                   *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_stacktrace``                                   *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_stdatomic_h``                                  ``202011L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_string_contains``                              ``202011L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_string_resize_and_overwrite``                  ``202110L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_to_string``                                    *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_to_underlying``                                ``202102L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_tuple_like``                                   *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_unreachable``                                  ``202202L``
-    ---------------------------------------------------------- -----------------
+    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+    ``__cpp_lib_format``    *unimplemented*   202207L   ❌   `P2419R2 <https://wg21.link/P2419R2>`__ Clarify handling of encodings in localized formatting of chrono types
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
     **C++26**
-    ----------------------------------------------------------------------------
-    ``__cpp_lib_associative_heterogeneous_insertion``          *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_min_max``                               *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_bind_front``                                   ``202306L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_bitset``                                       ``202306L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constrained_equality``                         *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_copyable_function``                            *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_debugging``                                    *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_default_template_type_for_algorithm_values``   *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_freestanding_algorithm``                       *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_freestanding_array``                           *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_freestanding_cstring``                         *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_freestanding_expected``                        *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_freestanding_mdspan``                          *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_freestanding_optional``                        *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_freestanding_string_view``                     *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_freestanding_variant``                         *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_fstream_native_handle``                        ``202306L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_function_ref``                                 *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_generate_random``                              *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_hazard_pointer``                               *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_linalg``                                       *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_out_ptr``                                      *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_concat``                                *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ratio``                                        ``202306L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_rcu``                                          *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_reference_wrapper``                            *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_saturation_arithmetic``                        ``202311L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_smart_ptr_owner_equality``                     *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_span_at``                                      ``202311L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_span_initializer_list``                        ``202311L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_sstream_from_string_view``                     ``202306L``
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_submdspan``                                    *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_text_encoding``                                *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_to_chars``                                     *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_tuple_like``                                   *unimplemented*
-    ---------------------------------------------------------- -----------------
-    ``__cpp_lib_within_lifetime``                              *unimplemented*
-    ========================================================== =================
+    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+    ``__cpp_lib_format``    *unimplemented*   202306L   ✅   `P2637R3 <https://wg21.link/P2637R3>`__ Member Visit
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
+    * *                                       202311L   ✅   `P2918R2 <https://wg21.link/P2918R2>`__ Runtime format strings II
+    ----------------------- ----------------- --------- --- ---------------------------------------------------------------------------------------------------------------
+    ``__cpp_lib_variant``   *202102L*         202306L   ✅   Member visit
+    ======================= ================= ========= === ===============================================================================================================
 
diff --git a/libcxx/utils/CMakeLists.txt b/libcxx/utils/CMakeLists.txt
index 7a573535e1ef85..f8baeffb929ae2 100644
--- a/libcxx/utils/CMakeLists.txt
+++ b/libcxx/utils/CMakeLists.txt
@@ -2,6 +2,10 @@ add_custom_target(libcxx-generate-feature-test-macros
     COMMAND "${Python3_EXECUTABLE}" "${LIBCXX_SOURCE_DIR}/utils/generate_feature_test_macro_components.py"
     COMMENT "Generate the <version> header and tests for feature test macros.")
 
+add_custom_target(libcxx-generate-feature-test-macros-v2
+    COMMAND "${Python3_EXECUTABLE}" "${LIBCXX_SOURCE_DIR}/utils/generate_feature_test_macro_components_v2.py"
+    COMMENT "Generate the <version> header and tests for feature test macros.")
+
 add_custom_target(libcxx-generate-std-clang-module-header
   COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/generate_std_clang_module_header.py"
   COMMENT "Generate the <__std_clang_module> header")
@@ -62,7 +66,7 @@ add_custom_target(libcxx-generate-iwyu-mapping
     COMMENT "Generate the mapping file for include-what-you-use")
 
 add_custom_target(libcxx-generate-files
-    DEPENDS libcxx-generate-feature-test-macros
+    DEPENDS libcxx-generate-feature-test-macros-v2
             libcxx-generate-std-clang-module-header
             libcxx-generate-std-cppm-in-file
             libcxx-generate-std-compat-cppm-in-file
diff --git a/libcxx/utils/generate_feature_test_macro_components_v2.py b/libcxx/utils/generate_feature_test_macro_components_v2.py
new file mode 100644
index 00000000000000..3730b79e164300
--- /dev/null
+++ b/libcxx/utils/generate_feature_test_macro_components_v2.py
@@ -0,0 +1,825 @@
+#!/usr/bin/env python
+
+import os
+from builtins import range
+from functools import reduce
+
+
+def get_libcxx_paths():
+    utils_path = os.path.dirname(os.path.abspath(__file__))
+    script_name = os.path.basename(__file__)
+    assert os.path.exists(utils_path)
+    src_root = os.path.dirname(utils_path)
+    include_path = os.path.join(src_root, "include")
+    assert os.path.exists(include_path)
+    docs_path = os.path.join(src_root, "docs")
+    assert os.path.exists(docs_path)
+    macro_test_path = os.path.join(
+        src_root,
+        "test",
+        "std",
+        "language.support",
+        "support.limits",
+        "support.limits.general",
+    )
+    assert os.path.exists(macro_test_path)
+    assert os.path.exists(
+        os.path.join(macro_test_path, "version.version.compile.pass.cpp")
+    )
+    return script_name, src_root, include_path, docs_path, macro_test_path
+
+
+script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths()
+
+
+def has_header(h):
+    h_path = os.path.join(include_path, h)
+    return os.path.exists(h_path)
+
+
+def add_version_header(tc):
+    tc["headers"].append("version")
+    return tc
+
+
+# ================  ============================================================
+# Field             Description
+# ================  ============================================================
+# name              The name of the feature-test macro.
+# values            A dict whose keys are C++ versions and whose values are the
+#                   value of the feature-test macro for that C++ version.
+#                   (TODO: This isn't a very clean model for feature-test
+#                   macros affected by multiple papers.)
+# headers           An array with the headers that should provide the
+#                   feature-test macro.
+# test_suite_guard  An optional string field. When this field is provided,
+#                   `libcxx_guard` must also be provided. This field is used
+#                   only to generate the unit tests for the feature-test macros.
+#                   It can't depend on macros defined in <__config> because the
+#                   `test/std/` parts of the test suite are intended to be
+#                   portable to any C++ standard library implementation, not
+#                   just libc++. It may depend on
+#                    * macros defined by the compiler itself, or
+#                    * macros generated by CMake.
+#                   In some cases we add also depend on macros defined in <__availability>.
+# libcxx_guard      An optional string field. When this field is provided,
+#                   `test_suite_guard` must also be provided. This field is used
+#                   only to guard the feature-test macro in <version>. It may
+#                   be the same as `test_suite_guard`, or it may depend on
+#                   macros defined in <__config>.
+# unimplemented     An optional Boolean field with the value `True`. This field
+#                   is only used when a feature isn't fully implemented. Once
+#                   you've fully implemented the feature, you should remove
+#                   this field.
+# ================  ============================================================
+feature_test_macros = [
+    add_version_header(x)
+    for x in [
+        # Before
+        #        {
+        #            "name": "__cpp_lib_any",
+        #            "values": {"c++17": 201606},
+        #            "headers": ["any"],
+        #        },
+        {
+            "name": "__cpp_lib_any",
+            "values": {
+                "c++17": {
+                    201606: [
+                        {
+                            "implemented": True,
+                        },
+                    ],
+                },
+            },
+            "headers": ["any"],
+        },
+        # Before
+        #        {
+        #            "name": "__cpp_lib_barrier",
+        #            "values": {"c++20": 201907},
+        #            "headers": ["barrier"],
+        #            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
+        #            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
+        #        },
+        {
+            "name": "__cpp_lib_barrier",
+            "values": {
+                "c++20": {
+                    201907: [
+                        {
+                            "implemented": True,
+                        },
+                    ],
+                },
+            },
+            "headers": ["barrier"],
+            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
+            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
+        },
+        # Before
+        #        {
+        #            "name": "__cpp_lib_format",
+        #            "values": {
+        #                # "c++20": 201907 Not implemented P1361R2 Integration of chrono with text formatting
+        #                # "c++20": 202106 Fully implemented
+        #                # "c++20": 202110 Not implemented P2372R3 Fixing locale handling in chrono formatters
+        #                "c++20": 202106,
+        #                # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types
+        #                # "c++26": 202306, P2637R3 Member Visit (implemented)
+        #                # "c++26": 202311, P2918R2 Runtime format strings II (implemented)
+        #            },
+        #            # Note these three papers are adopted at the June 2023 meeting and have sequential numbering
+        #            # 202304 P2510R3 Formatting pointers (Implemented)
+        #            # 202305 P2757R3 Type-checking format args
+        #            # 202306 P2637R3 Member Visit
+        #            "headers": ["format"],
+        #            "unimplemented": True,
+        #        },
+        {
+            "name": "__cpp_lib_format",
+            "values": {
+                "c++20": {
+                    201907: [
+                        {
+                            "number": "P0645R10",
+                            "title": "Text Formatting",
+                            "implemented": True,
+                        },
+                        {
+                            "number": "P1361R2",
+                            "title": "Integration of chrono with text formatting",
+                            "implemented": False,
+                        },
+                    ],
+                    202106: [
+                        {
+                            "number": "P2216R3",
+                            "title": "std::format improvements",
+                            "implemented": True,
+                        }
+                    ],
+                    202110: [
+                        {
+                            "number": "P2372R3",
+                            "title": "Fixing locale handling in chrono formatters",
+                            "implemented": False,
+                        },
+                        {
+                            "number": "P2418R2",
+                            "title": "FAdd support for std::generator-like types to std::format",
+                            "implemented": True,
+                        },
+                    ],
+                },
+                "c++23": {
+                    202207: [
+                        {
+                            "number": "P2419R2",
+                            "title": "Clarify handling of encodings in localized formatting of chrono types",
+                            "implemented": False,
+                        },
+                    ],
+                },
+                "c++26": {
+                    202306: [
+                        {
+                            "number": "P2637R3",
+                            "title": "Member Visit",
+                            "implemented": True,
+                        },
+                    ],
+                    202311: [
+                        {
+                            "number": "P2918R2",
+                            "title": "Runtime format strings II",
+                            "implemented": True,
+                        },
+                    ],
+                },
+            },
+            "headers": ["format"],
+        },
+        #        Before
+        #        {
+        #            "name": "__cpp_lib_variant",
+        #            "values": {
+        #                "c++17": 202102,  # std::visit for classes derived from std::variant
+        #                # "c++20": 202106,  # Fully constexpr std::variant
+        #                # "c++26": 202306,  # Member visit (implemented)
+        #            },
+        #            "headers": ["variant"],
+        #        },
+        #        After
+        {
+            "name": "__cpp_lib_variant",
+            "values": {
+                "c++17": {
+                    202102: [
+                        {
+                            "number": "",
+                            "title": "``std::visit`` for classes derived from ``std::variant``",
+                            "implemented": True,
+                        },
+                    ],
+                },
+                "c++20": {
+                    202106: [
+                        {
+                            "number": "",
+                            "title": "Fully constexpr ``std::variant``",
+                            "implemented": False,
+                        },
+                    ],
+                },
+                "c++26": {
+                    202306: [
+                        {
+                            "number": "",
+                            "title": "Member visit",
+                            "implemented": True,
+                        }
+                    ],
+                },
+            },
+            "headers": ["variant"],
+        },
+    ]
+]
+
+assert feature_test_macros == sorted(feature_test_macros, key=lambda tc: tc["name"])
+for tc in feature_test_macros:
+    assert tc["headers"] == sorted(tc["headers"]), tc
+    assert ("libcxx_guard" in tc) == ("test_suite_guard" in tc), tc
+    valid_keys = [
+        "name",
+        "values",
+        "headers",
+        "libcxx_guard",
+        "test_suite_guard",
+        # "unimplemented",
+    ]
+    assert all(key in valid_keys for key in tc.keys()), tc
+
+
+# Map from each header to the Lit annotations that should be used for
+# tests that include that header.
+#
+# For example, when threads are not supported, any test that includes
+# <thread> should be marked as UNSUPPORTED, because including <thread>
+# is a hard error in that case.
+lit_markup = {
+    "barrier": ["UNSUPPORTED: no-threads"],
+    "filesystem": ["UNSUPPORTED: no-filesystem"],
+    "fstream": ["UNSUPPORTED: no-localization"],
+    "iomanip": ["UNSUPPORTED: no-localization"],
+    "ios": ["UNSUPPORTED: no-localization"],
+    "iostream": ["UNSUPPORTED: no-localization"],
+    "istream": ["UNSUPPORTED: no-localization"],
+    "latch": ["UNSUPPORTED: no-threads"],
+    "locale": ["UNSUPPORTED: no-localization"],
+    "mutex": ["UNSUPPORTED: no-threads"],
+    "ostream": ["UNSUPPORTED: no-localization"],
+    "print": ["UNSUPPORTED: no-filesystem"],
+    "regex": ["UNSUPPORTED: no-localization"],
+    "semaphore": ["UNSUPPORTED: no-threads"],
+    "shared_mutex": ["UNSUPPORTED: no-threads"],
+    "sstream": ["UNSUPPORTED: no-localization"],
+    "syncstream": ["UNSUPPORTED: no-localization"],
+    "stdatomic.h": ["UNSUPPORTED: no-threads"],
+    "stop_token": ["UNSUPPORTED: no-threads"],
+    "thread": ["UNSUPPORTED: no-threads"],
+}
+
+
+def get_std_dialects():
+    std_dialects = ["c++14", "c++17", "c++20", "c++23", "c++26"]
+    return list(std_dialects)
+
+
+feature_test_macros_status = dict()
+
+for tc in feature_test_macros:
+    #   name = tc['name']}``"
+    last = None
+    result = dict()
+    implemented = True
+    for std in get_std_dialects():
+        if std not in tc["values"].keys():
+            if last == None:
+                continue
+            else:
+                result[std] = last
+        else:
+            if last == None:
+                last = "unimplemented"
+            if implemented:
+                for value in tc["values"][std]:
+                    for paper in list(tc["values"][std][value]):
+                        if not paper["implemented"]:
+                            implemented = False
+                            break
+                    if implemented:
+                        last = f"{value}L"
+                    else:
+                        break
+
+            result[std] = last
+    feature_test_macros_status[tc["name"]] = result
+
+# print(feature_test_macros_status)
+
+
+def get_first_std(d):
+    for s in get_std_dialects():
+        if s in d.keys():
+            return s
+    return None
+
+
+def get_last_std(d):
+    rev_dialects = get_std_dialects()
+    rev_dialects.reverse()
+    for s in rev_dialects:
+        if s in d.keys():
+            return s
+    return None
+
+
+def get_std_before(d, std):
+    std_dialects = get_std_dialects()
+    candidates = std_dialects[0 : std_dialects.index(std)]
+    candidates.reverse()
+    for cand in candidates:
+        if cand in d.keys():
+            return cand
+    return None
+
+
+def get_value_before(d, std):
+    new_std = get_std_before(d, std)
+    if new_std is None:
+        return None
+    return d[new_std]
+
+
+def get_for_std(d, std):
+    # This catches the C++11 case for which there should be no defined feature
+    # test macros.
+    std_dialects = get_std_dialects()
+    if std not in std_dialects:
+        return None
+    # Find the value for the newest C++ dialect between C++14 and std
+    std_list = list(std_dialects[0 : std_dialects.index(std) + 1])
+    std_list.reverse()
+    for s in std_list:
+        if s in d.keys():
+            return d[s]
+    return None
+
+
+def get_std_number(std):
+    return std.replace("c++", "")
+
+
+"""
+  Functions to produce the <version> header
+"""
+
+
+def produce_macros_definition_for_std(std):
+    result = ""
+    indent = 55
+    for tc in feature_test_macros:
+        if std not in tc["values"]:
+            continue
+        inner_indent = 1
+        if "test_suite_guard" in tc.keys():
+            result += "# if %s\n" % tc["libcxx_guard"]
+            inner_indent += 2
+        if get_value_before(tc["values"], std) is not None:
+            assert "test_suite_guard" not in tc.keys()
+            result += "# undef  %s\n" % tc["name"]
+        line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])
+        line += " " * (indent - len(line))
+        line += " %sL" % tc["values"][std]
+        if "unimplemented" in tc.keys():
+            line = "// " + line
+        result += line
+        result += "\n"
+        if "test_suite_guard" in tc.keys():
+            result += "# endif\n"
+    return result.strip()
+
+
+def produce_macros_definitions():
+    macro_definition_template = """#if _LIBCPP_STD_VER >= {std_number}
+{macro_definition}
+#endif"""
+
+    macros_definitions = []
+    for std in get_std_dialects():
+        macros_definitions.append(
+            macro_definition_template.format(
+                std_number=get_std_number(std),
+                macro_definition=produce_macros_definition_for_std(std),
+            )
+        )
+
+    return "\n\n".join(macros_definitions)
+
+
+def chunks(l, n):
+    """Yield successive n-sized chunks from l."""
+    for i in range(0, len(l), n):
+        yield l[i : i + n]
+
+
+def produce_version_synopsis():
+    indent = 56
+    header_indent = 56 + len("20XXYYL ")
+    result = ""
+
+    def indent_to(s, val):
+        if len(s) >= val:
+            return s
+        s += " " * (val - len(s))
+        return s
+
+    line = indent_to("Macro name", indent) + "Value"
+    line = indent_to(line, header_indent) + "Headers"
+    result += line + "\n"
+    for tc in feature_test_macros:
+        prev_defined_std = get_last_std(tc["values"])
+        line = "{name: <{indent}}{value}L ".format(
+            name=tc["name"], indent=indent, value=tc["values"][prev_defined_std]
+        )
+        headers = list(tc["headers"])
+        headers.remove("version")
+        for chunk in chunks(headers, 3):
+            line = indent_to(line, header_indent)
+            chunk = ["<%s>" % header for header in chunk]
+            line += " ".join(chunk)
+            result += line
+            result += "\n"
+            line = ""
+        while True:
+            prev_defined_std = get_std_before(tc["values"], prev_defined_std)
+            if prev_defined_std is None:
+                break
+            result += "%s%sL // %s\n" % (
+                indent_to("", indent),
+                tc["values"][prev_defined_std],
+                prev_defined_std.replace("c++", "C++"),
+            )
+    return result
+
+
+def produce_version_header():
+    template = """// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_VERSIONH
+#define _LIBCPP_VERSIONH
+
+/*
+  version synopsis
+
+{synopsis}
+
+*/
+
+#include <__availability>
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+// clang-format off
+
+{cxx_macros}
+
+// clang-format on
+
+#endif // _LIBCPP_VERSIONH
+"""
+
+    version_str = template.format(
+        synopsis=produce_version_synopsis().strip(),
+        cxx_macros=produce_macros_definitions(),
+    )
+    version_header_path = os.path.join(include_path, "version")
+    with open(version_header_path, "w", newline="\n") as f:
+        f.write(version_str)
+
+
+"""
+    Functions to produce test files
+"""
+
+test_types = {
+    "undefined": """
+# ifdef {name}
+#   error "{name} should not be defined before {std_first}"
+# endif
+""",
+    "test_suite_guard": """
+# if {test_suite_guard}
+#   ifndef {name}
+#     error "{name} should be defined in {std}"
+#   endif
+#   if {name} != {value}
+#     error "{name} should have the value {value} in {std}"
+#   endif
+# else
+#   ifdef {name}
+#     error "{name} should not be defined when the requirement '{test_suite_guard}' is not met!"
+#   endif
+# endif
+""",
+    "unimplemented": """
+# if !defined(_LIBCPP_VERSION)
+#   ifndef {name}
+#     error "{name} should be defined in {std}"
+#   endif
+#   if {name} != {value}
+#     error "{name} should have the value {value} in {std}"
+#   endif
+# else // _LIBCPP_VERSION
+#   ifdef {name}
+#     error "{name} should not be defined because it is unimplemented in libc++!"
+#   endif
+# endif
+""",
+    "defined": """
+# ifndef {name}
+#   error "{name} should be defined in {std}"
+# endif
+# if {name} != {value}
+#   error "{name} should have the value {value} in {std}"
+# endif
+""",
+}
+
+
+def generate_std_test(test_list, std):
+    result = ""
+    for tc in test_list:
+        val = get_for_std(tc["values"], std)
+        if val is not None:
+            val = "%sL" % val
+        if val is None:
+            result += test_types["undefined"].format(
+                name=tc["name"], std_first=get_first_std(tc["values"])
+            )
+        elif "unimplemented" in tc.keys():
+            result += test_types["unimplemented"].format(
+                name=tc["name"], value=val, std=std
+            )
+        elif "test_suite_guard" in tc.keys():
+            result += test_types["test_suite_guard"].format(
+                name=tc["name"],
+                value=val,
+                std=std,
+                test_suite_guard=tc["test_suite_guard"],
+            )
+        else:
+            result += test_types["defined"].format(name=tc["name"], value=val, std=std)
+    return result.strip()
+
+
+def generate_std_tests(test_list):
+    std_tests_template = """#if TEST_STD_VER < {first_std_number}
+
+{pre_std_test}
+
+{other_std_tests}
+
+#elif TEST_STD_VER > {penultimate_std_number}
+
+{last_std_test}
+
+#endif // TEST_STD_VER > {penultimate_std_number}"""
+
+    std_dialects = get_std_dialects()
+
+    other_std_tests = []
+    for std in std_dialects[:-1]:
+        other_std_tests.append("#elif TEST_STD_VER == " + get_std_number(std))
+        other_std_tests.append(generate_std_test(test_list, std))
+
+    std_tests = std_tests_template.format(
+        first_std_number=get_std_number(std_dialects[0]),
+        pre_std_test=generate_std_test(test_list, "c++11"),
+        other_std_tests="\n\n".join(other_std_tests),
+        penultimate_std_number=get_std_number(std_dialects[-2]),
+        last_std_test=generate_std_test(test_list, std_dialects[-1]),
+    )
+
+    return std_tests
+
+
+def generate_synopsis(test_list):
+    max_name_len = max([len(tc["name"]) for tc in test_list])
+    indent = max_name_len + 8
+
+    def mk_line(prefix, suffix):
+        return "{prefix: <{max_len}}{suffix}\n".format(
+            prefix=prefix, suffix=suffix, max_len=indent
+        )
+
+    result = ""
+    result += mk_line("/*  Constant", "Value")
+    for tc in test_list:
+        prefix = "    %s" % tc["name"]
+        for std in [s for s in get_std_dialects() if s in tc["values"].keys()]:
+            result += mk_line(
+                prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++"))
+            )
+            prefix = ""
+    result += "*/"
+    return result
+
+
+def produce_tests():
+    headers = set([h for tc in feature_test_macros for h in tc["headers"]])
+    for h in headers:
+        test_list = [tc for tc in feature_test_macros if h in tc["headers"]]
+        if not has_header(h):
+            for tc in test_list:
+                assert "unimplemented" in tc.keys()
+            continue
+        markup = "\n".join("// " + tag for tag in lit_markup.get(h, []))
+        test_body = """//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// WARNING: This test was generated by {script_name}
+// and should not be edited manually.
+//
+// clang-format off
+{markup}
+// <{header}>
+
+// Test the feature test macros defined by <{header}>
+
+{synopsis}
+
+#include <{header}>
+#include "test_macros.h"
+
+{cxx_tests}
+
+""".format(
+            script_name=script_name,
+            header=h,
+            markup=("\n{}\n".format(markup) if markup else ""),
+            synopsis=generate_synopsis(test_list),
+            cxx_tests=generate_std_tests(test_list),
+        )
+        test_name = "{header}.version.compile.pass.cpp".format(header=h)
+        out_path = os.path.join(macro_test_path, test_name)
+        with open(out_path, "w", newline="\n") as f:
+            f.write(test_body)
+
+
+"""
+    Produce documentation for the feature test macros
+"""
+
+
+def make_widths(grid):
+    widths = []
+    for i in range(0, len(grid[0])):
+        cell_width = 2 + max(
+            reduce(lambda x, y: x + y, [[len(row[i])] for row in grid], [])
+        )
+        widths += [cell_width]
+    return widths
+
+
+def create_table(grid, indent):
+    indent_str = " " * indent
+    col_widths = make_widths(grid)
+    result = [indent_str + add_divider(col_widths, 2)]
+    header_flag = 2
+    for row_i in range(0, len(grid)):
+        row = grid[row_i]
+        line = indent_str + " ".join(
+            [pad_cell(row[i], col_widths[i]) for i in range(0, len(row))]
+        )
+        result.append(line.rstrip())
+        if row_i == len(grid) - 1:
+            header_flag = 2
+        if row[0].startswith("**"):
+            header_flag += 1
+        separator = indent_str + add_divider(col_widths, header_flag)
+        result.append(separator.rstrip())
+        header_flag = 0
+    return "\n".join(result)
+
+
+def add_divider(widths, header_flag):
+    if header_flag == 3:
+        return "=".join(["=" * w for w in widths])
+    if header_flag == 2:
+        return " ".join(["=" * w for w in widths])
+    if header_flag == 1:
+        return "-".join(["-" * w for w in widths])
+    else:
+        return " ".join(["-" * w for w in widths])
+
+
+def pad_cell(s, length, left_align=True):
+    padding = (length - len(s)) * " "
+    return s + padding
+
+
+def get_status_table():
+    table = [["Macro Name", "Status", "Value", "", "Paper"]]
+    for std in get_std_dialects():
+        table += [["**" + std.replace("c++", "C++") + "**", "", "", "", ""]]
+        for tc in feature_test_macros:
+            if std not in tc["values"].keys():
+                continue
+            ftm = f"``{tc['name']}``"
+            result = f"*{feature_test_macros_status[tc['name']][std]}*"
+            for value in tc["values"][std]:
+                ftm_value = f"{value}L"
+                for paper in list(tc["values"][std][value]):
+                    number = "" if not "number" in paper.keys() else paper["number"]
+                    title = "" if not "title" in paper.keys() else paper["title"]
+                    implemented = paper["implemented"]
+                    table += [
+                        [
+                            ftm,
+                            result,
+                            ftm_value,
+                            "✅" if implemented else "❌",
+                            f"`{number} <https://wg21.link/{number}>`__ {title}"
+                            if number
+                            else f"{title}",
+                        ]
+                    ]
+                    ftm = "* *"
+                    result = ""
+    return table
+
+
+def produce_docs():
+    doc_str = """.. _FeatureTestMacroTable:
+
+==========================
+Feature Test Macro Support
+==========================
+
+.. contents::
+   :local:
+
+Overview
+========
+
+This file documents the feature test macros currently supported by libc++.
+For older language version not all details are available. This information can
+be found at the `isoccp
+<https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros>`__.
+
+.. _feature-status:
+
+Status
+======
+
+.. table:: Current Status
+    :name: feature-status-table
+    :widths: auto
+
+{status_tables}
+
+""".format(
+        status_tables=create_table(get_status_table(), 4)
+    )
+
+    table_doc_path = os.path.join(docs_path, "FeatureTestMacroTable.rst")
+    with open(table_doc_path, "w", newline="\n") as f:
+        f.write(doc_str)
+
+
+def main():
+    # produce_version_header()
+    # produce_tests()
+    produce_docs()
+
+
+if __name__ == "__main__":
+    main()



More information about the libcxx-commits mailing list