brintos

brintos / llvm-project-archived public Read only

0
0
Text · 85.9 KiB · 0802f86 Raw
2635 lines · python
1#!/usr/bin/env python2 3import os4from builtins import range5from dataclasses import dataclass6from functools import reduce7from typing import (8    Any,9    Dict,10    List,  # Needed for python 3.8 compatibility.11    NewType,12    Optional,13    Set,14)15import functools16import json17from libcxx.header_information import headers_not_available18 19 20def get_libcxx_paths():21    utils_path = os.path.dirname(os.path.abspath(__file__))22    script_name = os.path.basename(__file__)23    assert os.path.exists(utils_path)24    src_root = os.path.dirname(utils_path)25    include_path = os.path.join(src_root, "include")26    assert os.path.exists(include_path)27    docs_path = os.path.join(src_root, "docs")28    assert os.path.exists(docs_path)29    macro_test_path = os.path.join(30        src_root,31        "test",32        "std",33        "language.support",34        "support.limits",35        "support.limits.general",36    )37    assert os.path.exists(macro_test_path)38    assert os.path.exists(39        os.path.join(macro_test_path, "version.version.compile.pass.cpp")40    )41    return script_name, src_root, include_path, docs_path, macro_test_path42 43 44script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths()45 46 47def has_header(h):48    h_path = os.path.join(include_path, h)49    return os.path.exists(h_path)50 51 52def add_version_header(tc):53    tc["headers"].append("version")54    return tc55 56 57# ================  ============================================================58# Field             Description59# ================  ============================================================60# name              The name of the feature-test macro.61# values            A dict whose keys are C++ versions and whose values are the62#                   value of the feature-test macro for that C++ version.63#                   (TODO: This isn't a very clean model for feature-test64#                   macros affected by multiple papers.)65# headers           An array with the headers that should provide the66#                   feature-test macro.67# test_suite_guard  An optional string field. When this field is provided,68#                   `libcxx_guard` must also be provided. This field is used69#                   only to generate the unit tests for the feature-test macros.70#                   It can't depend on macros defined in <__config> because the71#                   `test/std/` parts of the test suite are intended to be72#                   portable to any C++ standard library implementation, not73#                   just libc++. It may depend on74#                    * macros defined by the compiler itself, or75#                    * macros generated by CMake.76#                   In some cases we add also depend on macros defined in77#                   <__configuration/availability.h>.78# libcxx_guard      An optional string field. When this field is provided,79#                   `test_suite_guard` must also be provided. This field is used80#                   only to guard the feature-test macro in <version>. It may81#                   be the same as `test_suite_guard`, or it may depend on82#                   macros defined in <__config>.83# unimplemented     An optional Boolean field with the value `True`. This field84#                   is only used when a feature isn't fully implemented. Once85#                   you've fully implemented the feature, you should remove86#                   this field.87# ================  ============================================================88feature_test_macros = [89    add_version_header(x)90    for x in [91        {92            "name": "__cpp_lib_adaptor_iterator_pair_constructor",93            "values": {"c++23": 202106},94            "headers": ["queue", "stack"],95        },96        {97            "name": "__cpp_lib_addressof_constexpr",98            "values": {"c++17": 201603},99            "headers": ["memory"],100        },101        {102            "name": "__cpp_lib_aligned_accessor",103            "values": {"c++26": 202411},104            "headers": ["mdspan"],105        },106        {107            "name": "__cpp_lib_allocate_at_least",108            "values": {109                # Note LWG3887 Version macro for allocate_at_least110                "c++23": 202302,  # P2652R2 Disallow User Specialization of allocator_traits111            },112            "headers": ["memory"],113        },114        {115            "name": "__cpp_lib_allocator_traits_is_always_equal",116            "values": {"c++17": 201411},117            "headers": [118                "deque",119                "forward_list",120                "list",121                "map",122                "memory",123                "scoped_allocator",124                "set",125                "string",126                "unordered_map",127                "unordered_set",128                "vector",129            ],130        },131        {132            "name": "__cpp_lib_any",133            "values": {"c++17": 201606},134            "headers": ["any"],135        },136        {137            "name": "__cpp_lib_apply",138            "values": {"c++17": 201603},139            "headers": ["tuple"],140        },141        {142            "name": "__cpp_lib_array_constexpr",143            "values": {"c++17": 201603, "c++20": 201811},144            "headers": ["array", "iterator"],145        },146        {147            "name": "__cpp_lib_as_const",148            "values": {"c++17": 201510},149            "headers": ["utility"],150        },151        {152            "name": "__cpp_lib_associative_heterogeneous_erasure",153            "values": {"c++23": 202110},154            "headers": ["map", "set", "unordered_map", "unordered_set"],155            "unimplemented": True,156        },157        {158            "name": "__cpp_lib_associative_heterogeneous_insertion",159            "values": {160                "c++26": 202306  # P2363R5 Extending associative containers with the remaining heterogeneous overloads161            },162            "headers": ["map", "set", "unordered_map", "unordered_set"],163            "unimplemented": True,164        },165        {166            "name": "__cpp_lib_assume_aligned",167            "values": {"c++20": 201811},168            "headers": ["memory"],169        },170        {171            "name": "__cpp_lib_atomic_flag_test",172            "values": {"c++20": 201907},173            "headers": ["atomic"],174        },175        {176            "name": "__cpp_lib_atomic_float",177            "values": {"c++20": 201711},178            "headers": ["atomic"],179        },180        {181            "name": "__cpp_lib_atomic_is_always_lock_free",182            "values": {"c++17": 201603},183            "headers": ["atomic"],184        },185        {186            "name": "__cpp_lib_atomic_lock_free_type_aliases",187            "values": {"c++20": 201907},188            "headers": ["atomic"],189        },190        {191            "name": "__cpp_lib_atomic_min_max",192            "values": {"c++26": 202403}, # P0493R5: Atomic minimum/maximum193            "headers": ["atomic"],194            "unimplemented": True,195        },196        {197            "name": "__cpp_lib_atomic_ref",198            "values": {199                "c++20": 201806,200                "c++26": 202411,  # P2835R7: Expose std::atomic_ref 's object address201            },202            "headers": ["atomic"],203        },204        {205            "name": "__cpp_lib_atomic_shared_ptr",206            "values": {"c++20": 201711},207            "headers": ["atomic"],208            "unimplemented": True,209        },210        {211            "name": "__cpp_lib_atomic_value_initialization",212            "values": {"c++20": 201911},213            "headers": ["atomic", "memory"],214        },215        {216            "name": "__cpp_lib_atomic_wait",217            "values": {"c++20": 201907},218            "headers": ["atomic"],219        },220        {221            "name": "__cpp_lib_barrier",222            "values": {"c++20": 201907},223            "headers": ["barrier"],224            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS",225            "libcxx_guard": "_LIBCPP_HAS_THREADS",226        },227        {228            "name": "__cpp_lib_bind_back",229            "values": {230                "c++23": 202202,231                # "c++26": 202306,  # P2714R1 Bind front and back to NTTP callables232            },233            "headers": ["functional"],234        },235        {236            "name": "__cpp_lib_bind_front",237            "values": {238                "c++20": 201907,239                "c++26": 202306,  # P2714R1 Bind front and back to NTTP callables240            },241            "headers": ["functional"],242        },243        {244            "name": "__cpp_lib_bit_cast",245            "values": {"c++20": 201806},246            "headers": ["bit"],247        },248        {249            "name": "__cpp_lib_bitops",250            "values": {"c++20": 201907},251            "headers": ["bit"],252        },253        {254            "name": "__cpp_lib_bitset",255            "values": {"c++26": 202306},  # P2697R1 Interfacing bitset with string_view256            "headers": ["bitset"],257        },258        {259            "name": "__cpp_lib_bool_constant",260            "values": {"c++17": 201505},261            "headers": ["type_traits"],262        },263        {264            "name": "__cpp_lib_bounded_array_traits",265            "values": {"c++20": 201902},266            "headers": ["type_traits"],267        },268        {269            "name": "__cpp_lib_boyer_moore_searcher",270            "values": {"c++17": 201603},271            "headers": ["functional"],272        },273        {274            "name": "__cpp_lib_byte",275            "values": {"c++17": 201603},276            "headers": ["cstddef"],277        },278        {279            "name": "__cpp_lib_byteswap",280            "values": {"c++23": 202110},281            "headers": ["bit"],282        },283        {284            "name": "__cpp_lib_char8_t",285            "values": {"c++20": 201907},286            "headers": [287                "atomic",288                "filesystem",289                "istream",290                "limits",291                "locale",292                "ostream",293                "string",294                "string_view",295            ],296            "test_suite_guard": "defined(__cpp_char8_t)",297            "libcxx_guard": "_LIBCPP_HAS_CHAR8_T",298        },299        {300            "name": "__cpp_lib_chrono",301            "values": {302                "c++17": 201611,303                # "c++26": 202306, # P2592R3 Hashing support for std::chrono value classes304            },305            "headers": ["chrono"],306        },307        {308            "name": "__cpp_lib_chrono_udls",309            "values": {"c++14": 201304},310            "headers": ["chrono"],311        },312        {313            "name": "__cpp_lib_clamp",314            "values": {"c++17": 201603},315            "headers": ["algorithm"],316        },317        {318            "name": "__cpp_lib_common_reference",319            "values": {"c++20": 202302},320            "headers": ["type_traits"],321        },322        {323            "name": "__cpp_lib_common_reference_wrapper",324            "values": {"c++20": 202302},325            "headers": ["functional"],326        },327        {328            "name": "__cpp_lib_complex_udls",329            "values": {"c++14": 201309},330            "headers": ["complex"],331        },332        {333            "name": "__cpp_lib_concepts",334            "values": {"c++20": 202002},335            "headers": ["concepts"],336        },337        {338            "name": "__cpp_lib_constexpr_algorithms",339            "values": {340                "c++20": 201806,341                "c++26": 202306,342            },343            "headers": ["algorithm", "utility"],344        },345        {346            "name": "__cpp_lib_constexpr_bitset",347            "values": {"c++23": 202207},348            "headers": ["bitset"],349        },350        {351            "name": "__cpp_lib_constexpr_charconv",352            "values": {"c++23": 202207},353            "headers": ["charconv"],354        },355        {356            "name": "__cpp_lib_constexpr_cmath",357            "values": {"c++23": 202202},358            "headers": ["cmath", "cstdlib"],359            "unimplemented": True,360        },361        {362            "name": "__cpp_lib_constexpr_complex",363            "values": {"c++20": 201711},364            "headers": ["complex"],365        },366        {367            "name": "__cpp_lib_constexpr_dynamic_alloc",368            "values": {"c++20": 201907},369            "headers": ["memory"],370        },371        {372            "name": "__cpp_lib_constexpr_flat_map",373            "values": {"c++26": 202502},374            "headers": ["flat_map"],375        },376        {377            "name": "__cpp_lib_constexpr_flat_set",378            "values": {"c++26": 202502},379            "headers": ["flat_set"],380        },381        {382            "name": "__cpp_lib_constexpr_forward_list",383            "values": {"c++26": 202502},384            "headers": ["forward_list"],385        },386        {387            "name": "__cpp_lib_constexpr_functional",388            "values": {"c++20": 201907},389            "headers": ["functional"],390        },391        {392            "name": "__cpp_lib_constexpr_iterator",393            "values": {"c++20": 201811},394            "headers": ["iterator"],395        },396        {397            "name": "__cpp_lib_constexpr_list",398            "values": {"c++26": 202502},399            "headers": ["list"],400        },401        {402            "name": "__cpp_lib_constexpr_memory",403            "values": {"c++20": 201811, "c++23": 202202},404            "headers": ["memory"],405        },406        {407            "name": "__cpp_lib_constexpr_new",408            "values": {"c++26": 202406},  # P2747R2 constexpr placement new409            "headers": ["new"],410            "test_suite_guard": "!defined(_LIBCPP_ABI_VCRUNTIME)",411            "libcxx_guard": "!defined(_LIBCPP_ABI_VCRUNTIME)",412        },413        {414            "name": "__cpp_lib_constexpr_numeric",415            "values": {"c++20": 201911},416            "headers": ["numeric"],417        },418        {419            "name": "__cpp_lib_constexpr_queue",420            "values": {"c++26": 202502},421            "headers": ["queue"],422        },423        {424            "name": "__cpp_lib_constexpr_string",425            "values": {"c++20": 201907},426            "headers": ["string"],427        },428        {429            "name": "__cpp_lib_constexpr_string_view",430            "values": {"c++20": 201811},431            "headers": ["string_view"],432        },433        {434            "name": "__cpp_lib_constexpr_tuple",435            "values": {"c++20": 201811},436            "headers": ["tuple"],437        },438        {439            "name": "__cpp_lib_constexpr_typeinfo",440            "values": {"c++23": 202106},441            "headers": ["typeinfo"],442        },443        {444            "name": "__cpp_lib_constexpr_utility",445            "values": {"c++20": 201811},446            "headers": ["utility"],447        },448        {449            "name": "__cpp_lib_constexpr_vector",450            "values": {"c++20": 201907},451            "headers": ["vector"],452        },453        {454            "name": "__cpp_lib_constrained_equality",455            "values": {456                "c++26": 202411,  # P3379R0: Constrain std::expected equality operators457            },458            "headers": ["expected", "optional", "tuple", "utility", "variant"],459        },460        {461            "name": "__cpp_lib_containers_ranges",462            "values": {"c++23": 202202},463            "headers": [464                "deque",465                "forward_list",466                "list",467                "map",468                "queue",469                "set",470                "stack",471                "string",472                "unordered_map",473                "unordered_set",474                "vector",475            ],476        },477        {478            "name": "__cpp_lib_copyable_function",479            "values": {"c++26": 202306},  # P2548R6 copyable_function480            "headers": ["functional"],481            "unimplemented": True,482        },483        {484            "name": "__cpp_lib_coroutine",485            "values": {"c++20": 201902},486            "headers": ["coroutine"],487        },488        {489            "name": "__cpp_lib_debugging",490            "values": {491                "c++26": 202311, # P2546R5 Debugging Support492                # "c++26": 202403, # P2810R4: is_debugger_present is_replaceable493            },494            "headers": ["debugging"],495            "unimplemented": True,496        },497        {498            "name": "__cpp_lib_default_template_type_for_algorithm_values",499            "values": {"c++26": 202403}, # P2248R8: Enabling list-initialization for algorithms500            "headers": ["algorithm", "deque", "forward_list", "list", "ranges", "string", "vector"],501            "unimplemented": True,502        },503        {504            "name": "__cpp_lib_destroying_delete",505            "values": {"c++20": 201806},506            "headers": ["new"],507            "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",508            "libcxx_guard": "_LIBCPP_STD_VER >= 20 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",509        },510        {511            "name": "__cpp_lib_enable_shared_from_this",512            "values": {"c++17": 201603},513            "headers": ["memory"],514        },515        {516            "name": "__cpp_lib_endian",517            "values": {"c++20": 201907},518            "headers": ["bit"],519        },520        {521            "name": "__cpp_lib_erase_if",522            "values": {"c++20": 202002},523            "headers": [524                "deque",525                "forward_list",526                "list",527                "map",528                "set",529                "string",530                "unordered_map",531                "unordered_set",532                "vector",533            ],534        },535        {536            "name": "__cpp_lib_exchange_function",537            "values": {"c++14": 201304},538            "headers": ["utility"],539        },540        {541            "name": "__cpp_lib_execution",542            "values": {"c++17": 201603, "c++20": 201902},543            "headers": ["execution"],544            "unimplemented": True,545        },546        {547            "name": "__cpp_lib_expected",548            "values": {"c++23": 202211},549            "headers": ["expected"],550        },551        {552            "name": "__cpp_lib_filesystem",553            "values": {"c++17": 201703},554            "headers": ["filesystem"],555            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM",556            "libcxx_guard": "_LIBCPP_HAS_FILESYSTEM",557        },558        {559            "name": "__cpp_lib_flat_map",560            "values": {"c++23": 202207},561            "headers": ["flat_map"],562        },563        {564            "name": "__cpp_lib_flat_set",565            "values": {"c++23": 202207},566            "headers": ["flat_set"],567        },568        {569            "name": "__cpp_lib_format",570            "values": {571                "c++20": 202110,572                # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types573                # "c++26": 202306, P2637R3 Member Visit (implemented)574                # "c++26": 202311, P2918R2 Runtime format strings II (implemented)575            },576            # Note these three papers are adopted at the June 2023 meeting and have sequential numbering577            # 202304 P2510R3 Formatting pointers (Implemented)578            # 202305 P2757R3 Type-checking format args579            # 202306 P2637R3 Member Visit580            "headers": ["format"],581            # Trying to use `std::format` where to_chars floating-point is not582            # available causes compilation errors, even with non floating-point types.583            # https://llvm.org/PR125353584            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT",585            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT",586        },587        {588            "name": "__cpp_lib_format_path",589            "values": {"c++26": 202403},  # P2845R8: Formatting of std::filesystem::path590            "headers": ["filesystem"],591            "unimplemented": True,592        },593        {594            "name": "__cpp_lib_format_ranges",595            "values": {"c++23": 202207},596            "headers": ["format"],597        },598        {599            "name": "__cpp_lib_format_uchar",600            "values": {601                "c++20": 202311  # DR P2909R4 Fix formatting of code units as integers602            },603            "headers": [604                "format"  # TODO verify this entry since the paper was underspecified.605            ],606        },607        {608            "name": "__cpp_lib_formatters",609            "values": {"c++23": 202302},610            "headers": ["stacktrace", "thread"],611            "unimplemented": True,612        },613        {614            "name": "__cpp_lib_forward_like",615            "values": {"c++23": 202207},616            "headers": ["utility"],617        },618        {619            "name": "__cpp_lib_freestanding_algorithm",620            "values": {621                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes622            },623            "headers": ["algorithm"],624            "unimplemented": True,625        },626        {627            "name": "__cpp_lib_freestanding_array",628            "values": {629                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes630            },631            "headers": ["array"],632            "unimplemented": True,633        },634        {635            "name": "__cpp_lib_freestanding_cstring",636            "values": {637                "c++26": 202306  # P2338R4 Freestanding Library: Character primitives and the C library638                #        202311  # P2407R5 Freestanding Library: Partial Classes639            },640            "headers": ["cstring"],641            "unimplemented": True,642        },643        {644            "name": "__cpp_lib_freestanding_expected",645            "values": {646                "c++26": 202311  # P2833R2 Freestanding Library: inout expected span647            },648            "headers": ["expected"],649            "unimplemented": True,650        },651        {652            "name": "__cpp_lib_freestanding_mdspan",653            "values": {654                "c++26": 202311  # P2833R2 Freestanding Library: inout expected span655            },656            "headers": ["mdspan"],657            "unimplemented": True,658        },659        {660            "name": "__cpp_lib_freestanding_optional",661            "values": {662                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes663            },664            "headers": ["optional"],665            "unimplemented": True,666        },667        {668            "name": "__cpp_lib_freestanding_string_view",669            "values": {670                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes671            },672            "headers": ["string_view"],673            "unimplemented": True,674        },675        {676            "name": "__cpp_lib_freestanding_variant",677            "values": {678                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes679            },680            "headers": ["variant"],681            "unimplemented": True,682        },683        {684            "name": "__cpp_lib_fstream_native_handle",685            "values": {"c++26": 202306},  # P1759R6 Native handles and file streams686            "headers": ["fstream"],687            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION)",688            "libcxx_guard": "_LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION",689        },690        {691            "name": "__cpp_lib_function_ref",692            "values": {693                "c++26": 202306  # P0792R14 function_ref: a type-erased callable reference694            },695            "headers": ["functional"],696            "unimplemented": True,697        },698        {699            "name": "__cpp_lib_gcd_lcm",700            "values": {"c++17": 201606},701            "headers": ["numeric"],702        },703        {704            "name": "__cpp_lib_generate_random",705            "values": {"c++26": 202403}, # P1068R11: Vector API for random number generation706            "headers": ["random"],707            "unimplemented": True,708        },709        {710            "name": "__cpp_lib_generic_associative_lookup",711            "values": {"c++14": 201304},712            "headers": ["map", "set"],713        },714        {715            "name": "__cpp_lib_generic_unordered_lookup",716            "values": {"c++20": 201811},717            "headers": ["unordered_map", "unordered_set"],718        },719        {720            "name": "__cpp_lib_hardware_interference_size",721            "values": {"c++17": 201703},722            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE))",723            "libcxx_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)",724            "headers": ["new"],725        },726        {727            "name": "__cpp_lib_has_unique_object_representations",728            "values": {"c++17": 201606},729            "headers": ["type_traits"],730        },731        {732            "name": "__cpp_lib_hazard_pointer",733            "values": {"c++26": 202306},  # P2530R3 Hazard Pointers for C++26734            "headers": [735                "hazard_pointer"  # TODO verify this entry since the paper was underspecified.736            ],737            "unimplemented": True,738        },739        {740            "name": "__cpp_lib_hypot",741            "values": {"c++17": 201603},742            "headers": ["cmath"],743        },744        {745            "name": "__cpp_lib_incomplete_container_elements",746            "values": {"c++17": 201505},747            "headers": ["forward_list", "list", "vector"],748        },749        {750            "name": "__cpp_lib_inplace_vector",751            "values": {"c++26": 202406},  # P0843R14 inplace_vector752            "headers": ["inplace_vector"],753            "unimplemented": True,754        },755        {756            "name": "__cpp_lib_int_pow2",757            "values": {"c++20": 202002},758            "headers": ["bit"],759        },760        {761            "name": "__cpp_lib_integer_comparison_functions",762            "values": {"c++20": 202002},763            "headers": ["utility"],764        },765        {766            "name": "__cpp_lib_integer_sequence",767            "values": {"c++14": 201304},768            "headers": ["utility"],769        },770        {771            "name": "__cpp_lib_integral_constant_callable",772            "values": {"c++14": 201304},773            "headers": ["type_traits"],774        },775        {776            "name": "__cpp_lib_interpolate",777            "values": {"c++20": 201902},778            "headers": ["cmath", "numeric"],779        },780        {781            "name": "__cpp_lib_invoke",782            "values": {"c++17": 201411},783            "headers": ["functional"],784        },785        {786            "name": "__cpp_lib_invoke_r",787            "values": {"c++23": 202106},788            "headers": ["functional"],789        },790        {791            "name": "__cpp_lib_ios_noreplace",792            "values": {"c++23": 202207},793            "headers": ["ios"],794        },795        {796            "name": "__cpp_lib_is_aggregate",797            "values": {"c++17": 201703},798            "headers": ["type_traits"],799        },800        {801            "name": "__cpp_lib_is_constant_evaluated",802            "values": {"c++20": 201811},803            "headers": ["type_traits"],804        },805        {806            "name": "__cpp_lib_is_final",807            "values": {"c++14": 201402},808            "headers": ["type_traits"],809        },810        {811            "name": "__cpp_lib_is_implicit_lifetime",812            "values": {"c++23": 202302},813            "headers": ["type_traits"],814            "test_suite_guard": "__has_builtin(__builtin_is_implicit_lifetime)",815            "libcxx_guard": "__has_builtin(__builtin_is_implicit_lifetime)",816        },817        {818            "name": "__cpp_lib_is_invocable",819            "values": {"c++17": 201703},820            "headers": ["type_traits"],821        },822        {823            "name": "__cpp_lib_is_layout_compatible",824            "values": {"c++20": 201907},825            "headers": ["type_traits"],826            "unimplemented": True,827        },828        {829            "name": "__cpp_lib_is_nothrow_convertible",830            "values": {"c++20": 201806},831            "headers": ["type_traits"],832        },833        {834            "name": "__cpp_lib_is_null_pointer",835            "values": {"c++14": 201309},836            "headers": ["type_traits"],837        },838        {839            "name": "__cpp_lib_is_pointer_interconvertible",840            "values": {"c++20": 201907},841            "headers": ["type_traits"],842            "unimplemented": True,843        },844        {845            "name": "__cpp_lib_is_scoped_enum",846            "values": {"c++23": 202011},847            "headers": ["type_traits"],848        },849        {850            "name": "__cpp_lib_is_sufficiently_aligned",851            "values": {"c++26": 202411},852            "headers": ["memory"],853        },854        {855            "name": "__cpp_lib_is_swappable",856            "values": {"c++17": 201603},857            "headers": ["type_traits"],858        },859        {860            "name": "__cpp_lib_is_virtual_base_of",861            "values": {862                "c++26": 202406  # P2985R0 A type trait for detecting virtual base classes863            },864            "headers": ["type_traits"],865            "test_suite_guard": "__has_builtin(__builtin_is_virtual_base_of)",866            "libcxx_guard": "__has_builtin(__builtin_is_virtual_base_of)",867        },868        {869            "name": "__cpp_lib_is_within_lifetime",870            # Note this name was changed from "__cpp_lib_within_lifetime" when the paper was adopted871            # https://github.com/cplusplus/draft/commit/0facada4cadd97e1ba15bfaea76a804f1dc5c309872            "values": {873                "c++26": 202306  # P2641R4 Checking if a union alternative is active874            },875            "headers": ["type_traits"],876            "test_suite_guard": "__has_builtin(__builtin_is_within_lifetime)",877            "libcxx_guard": "__has_builtin(__builtin_is_within_lifetime)",878        },879        {880            "name": "__cpp_lib_jthread",881            "values": {"c++20": 201911},882            "headers": ["stop_token", "thread"],883            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS",884            "libcxx_guard": "_LIBCPP_HAS_THREADS",885        },886        {887            "name": "__cpp_lib_latch",888            "values": {"c++20": 201907},889            "headers": ["latch"],890            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS",891            "libcxx_guard": "_LIBCPP_HAS_THREADS",892        },893        {894            "name": "__cpp_lib_launder",895            "values": {"c++17": 201606},896            "headers": ["new"],897        },898        {899            "name": "__cpp_lib_linalg",900            "values": {901                "c++26": 202311  # P1673 A free function linear algebra interface based on the BLAS902            },903            "headers": ["linalg"],904            "unimplemented": True,905        },906        {907            "name": "__cpp_lib_list_remove_return_type",908            "values": {"c++20": 201806},909            "headers": ["forward_list", "list"],910        },911        {912            "name": "__cpp_lib_logical_traits",913            "values": {"c++17": 201510},914            "headers": ["type_traits"],915        },916        {917            "name": "__cpp_lib_make_from_tuple",918            "values": {"c++17": 201606},919            "headers": ["tuple"],920        },921        {922            "name": "__cpp_lib_make_reverse_iterator",923            "values": {"c++14": 201402},924            "headers": ["iterator"],925        },926        {927            "name": "__cpp_lib_make_unique",928            "values": {"c++14": 201304},929            "headers": ["memory"],930        },931        {932            "name": "__cpp_lib_map_try_emplace",933            "values": {"c++17": 201411},934            "headers": ["map"],935        },936        {937            "name": "__cpp_lib_math_constants",938            "values": {"c++20": 201907},939            "headers": ["numbers"],940        },941        {942            "name": "__cpp_lib_math_special_functions",943            "values": {"c++17": 201603},944            "headers": ["cmath"],945            "unimplemented": True,946        },947        {948            "name": "__cpp_lib_mdspan",949            "values": {950                "c++23": 202207,951                "c++26": 202406,  # P2389R2 dextents Index Type Parameter952            },953            "headers": ["mdspan"],954        },955        {956            "name": "__cpp_lib_memory_resource",957            "values": {"c++17": 201603},958            "headers": ["memory_resource"],959            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",960            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",961        },962        {963            "name": "__cpp_lib_modules",964            "values": {"c++23": 202207},965            "headers": [],966        },967        {968            "name": "__cpp_lib_move_iterator_concept",969            "values": {"c++20": 202207},970            "headers": ["iterator"],971        },972        {973            "name": "__cpp_lib_move_only_function",974            "values": {"c++23": 202110},975            "headers": ["functional"],976            "unimplemented": True,977        },978        {979            "name": "__cpp_lib_node_extract",980            "values": {"c++17": 201606},981            "headers": ["map", "set", "unordered_map", "unordered_set"],982        },983        {984            "name": "__cpp_lib_nonmember_container_access",985            "values": {"c++17": 201411},986            "headers": [987                "array",988                "deque",989                "forward_list",990                "iterator",991                "list",992                "map",993                "regex",994                "set",995                "string",996                "unordered_map",997                "unordered_set",998                "vector",999            ],1000        },1001        {1002            "name": "__cpp_lib_not_fn",1003            "values": {1004                "c++17": 201603,1005                "c++26": 202306,  # P2714R1 Bind front and back to NTTP callables1006            },1007            "headers": ["functional"],1008        },1009        {1010            "name": "__cpp_lib_null_iterators",1011            "values": {"c++14": 201304},1012            "headers": ["iterator"],1013        },1014        {1015            "name": "__cpp_lib_optional",1016            "values": {1017                "c++17": 201606,1018                "c++20": 202106,  # P2231R1 Missing constexpr in std::optional and std::variant1019                "c++23": 202110,  # P0798R8 Monadic operations for std::optional + LWG3621 Remove feature-test macro __cpp_lib_monadic_optional1020                "c++26": 202506,  # P2988R12: std::optional<T&>1021            },1022            "headers": ["optional"],1023        },1024        {1025            "name": "__cpp_lib_optional_range_support",1026            "values": {"c++26": 202406},  # P3168R2 Give std::optional Range Support1027            "headers": ["optional"],1028        },1029        {1030            "name": "__cpp_lib_out_ptr",1031            "values": {1032                "c++23": 202106,1033                "c++26": 202311,  # P2833R2 Freestanding Library: inout expected span1034            },1035            "headers": ["memory"],1036        },1037        {1038            "name": "__cpp_lib_parallel_algorithm",1039            "values": {"c++17": 201603},1040            "headers": ["algorithm", "numeric"],1041            "unimplemented": True,1042        },1043        {1044            "name": "__cpp_lib_philox_engine",1045            "values": {1046                "c++26": 2024061047            },  # P2075R6 Philox as an extension of the C++ RNG engines1048            # Note the paper mentions 202310L as value, which differs from the typical procedure.1049            "headers": ["random"],1050            "unimplemented": True,1051        },1052        {1053            "name": "__cpp_lib_polymorphic_allocator",1054            "values": {"c++20": 201902},1055            "headers": ["memory_resource"],1056            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",1057            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",1058        },1059        {1060            "name": "__cpp_lib_print",1061            "values": {1062                "c++23": 202207,1063                # "c++26": 202403, # P3107R5: Permit an efficient implementation of std::print1064                # "c++26": 202406, # P3235R3 std::print more types faster with less memory1065            },1066            "headers": ["ostream", "print"],1067            # Trying to use `std::print` where to_chars floating-point is not1068            # available causes compilation errors, even with non floating-point types.1069            # https://llvm.org/PR1253531070            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT",1071            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT",1072        },1073        {1074            "name": "__cpp_lib_quoted_string_io",1075            "values": {"c++14": 201304},1076            "headers": ["iomanip"],1077            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_LOCALIZATION",1078            "libcxx_guard": "_LIBCPP_HAS_LOCALIZATION",1079        },1080        {1081            "name": "__cpp_lib_ranges",1082            "values": {1083                "c++20": 202110,  # P2415R2 What is a view?1084                "c++23": 202406,  # P2997R1 Removing the common reference requirement from the indirectly invocable concepts (implemented as a DR against C++20)1085            },1086            "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],1087        },1088        {1089            "name": "__cpp_lib_ranges_as_const",1090            "values": {1091                "c++23": 202207  # P2278R4 cbegin should always return a constant iterator1092                #        202311  # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility1093            },1094            "headers": ["ranges"],1095            "unimplemented": True,1096        },1097        {1098            "name": "__cpp_lib_ranges_as_rvalue",1099            "values": {"c++23": 202207},1100            "headers": ["ranges"],1101        },1102        {1103            "name": "__cpp_lib_ranges_chunk",1104            "values": {"c++23": 202202},1105            "headers": ["ranges"],1106            "unimplemented": True,1107        },1108        {1109            "name": "__cpp_lib_ranges_chunk_by",1110            "values": {"c++23": 202202},1111            "headers": ["ranges"],1112        },1113        {1114            "name": "__cpp_lib_ranges_concat",1115            "values": {"c++26": 202403}, # P2542R8: views::concat1116            "headers": ["ranges"],1117            "unimplemented": True,1118        },1119        {1120            "name": "__cpp_lib_ranges_contains",1121            "values": {"c++23": 202207},1122            "headers": ["algorithm"],1123        },1124        {1125            "name": "__cpp_lib_ranges_find_last",1126            "values": {"c++23": 202207},1127            "headers": ["algorithm"],1128        },1129        {1130            "name": "__cpp_lib_ranges_indices",1131            "values": {"c++26": 202506},1132            "headers": ["ranges"],1133        },1134        {1135            "name": "__cpp_lib_ranges_iota",1136            "values": {"c++23": 202202},1137            "headers": ["numeric"],1138        },1139        {1140            "name": "__cpp_lib_ranges_join_with",1141            "values": {"c++23": 202202},1142            "headers": ["ranges"],1143        },1144        {1145            "name": "__cpp_lib_ranges_repeat",1146            "values": {"c++23": 202207},1147            "headers": ["ranges"],1148        },1149        {1150            "name": "__cpp_lib_ranges_slide",1151            "values": {"c++23": 202202},1152            "headers": ["ranges"],1153            "unimplemented": True,1154        },1155        {1156            "name": "__cpp_lib_ranges_starts_ends_with",1157            "values": {"c++23": 202106},1158            "headers": ["algorithm"],1159        },1160        {1161            "name": "__cpp_lib_ranges_to_container",1162            "values": {"c++23": 202202},1163            "headers": ["ranges"],1164        },1165        {1166            "name": "__cpp_lib_ranges_zip",1167            "values": {"c++23": 202110},1168            "headers": ["ranges", "tuple", "utility"],1169            "unimplemented": True,1170        },1171        {1172            "name": "__cpp_lib_ratio",1173            "values": {"c++26": 202306},  # P2734R0 Adding the new SI prefixes1174            "headers": ["ratio"],1175        },1176        {1177            "name": "__cpp_lib_raw_memory_algorithms",1178            "values": {"c++17": 201606},1179            "headers": ["memory"],1180        },1181        {1182            "name": "__cpp_lib_rcu",1183            "values": {"c++26": 202306},  # P2545R4 Read-Copy Update (RCU)1184            "headers": [1185                "rcu"  # TODO verify this entry since the paper was underspecified.1186            ],1187            "unimplemented": True,1188        },1189        {1190            "name": "__cpp_lib_reference_from_temporary",1191            "values": {"c++23": 202202},1192            "headers": ["type_traits"],1193            "unimplemented": True,1194        },1195        {1196            "name": "__cpp_lib_reference_wrapper",1197            "values": {"c++26": 202403}, # P2944R3: Comparisons for reference_wrapper1198            "headers": ["functional"],1199        },1200        {1201            "name": "__cpp_lib_remove_cvref",1202            "values": {"c++20": 201711},1203            "headers": ["type_traits"],1204        },1205        {1206            "name": "__cpp_lib_result_of_sfinae",1207            "values": {"c++14": 201210},1208            "headers": ["functional", "type_traits"],1209        },1210        {1211            "name": "__cpp_lib_robust_nonmodifying_seq_ops",1212            "values": {"c++14": 201304},1213            "headers": ["algorithm"],1214        },1215        {1216            "name": "__cpp_lib_sample",1217            "values": {"c++17": 201603},1218            "headers": ["algorithm"],1219        },1220        {1221            "name": "__cpp_lib_saturation_arithmetic",1222            "values": {"c++26": 202311},  # P0543R3 Saturation arithmetic1223            "headers": ["numeric"],1224        },1225        {1226            "name": "__cpp_lib_scoped_lock",1227            "values": {"c++17": 201703},1228            "headers": ["mutex"],1229            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS",1230            "libcxx_guard": "_LIBCPP_HAS_THREADS",1231        },1232        {1233            "name": "__cpp_lib_semaphore",1234            "values": {"c++20": 201907},1235            "headers": ["semaphore"],1236            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS",1237            "libcxx_guard": "_LIBCPP_HAS_THREADS",1238        },1239        {1240            "name": "__cpp_lib_senders",1241            "values": {"c++26": 202406},  # P2300R10 std::execution1242            "headers": ["execution"],1243            "unimplemented": True,1244        },1245        {1246            "name": "__cpp_lib_shared_mutex",1247            "values": {"c++17": 201505},1248            "headers": ["shared_mutex"],1249            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS",1250            "libcxx_guard": "_LIBCPP_HAS_THREADS",1251        },1252        {1253            "name": "__cpp_lib_shared_ptr_arrays",1254            "values": {"c++17": 201611, "c++20": 201707},1255            "headers": ["memory"],1256        },1257        {1258            "name": "__cpp_lib_shared_ptr_weak_type",1259            "values": {"c++17": 201606},1260            "headers": ["memory"],1261        },1262        {1263            "name": "__cpp_lib_shared_timed_mutex",1264            "values": {"c++14": 201402},1265            "headers": ["shared_mutex"],1266            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS",1267            "libcxx_guard": "_LIBCPP_HAS_THREADS",1268        },1269        {1270            "name": "__cpp_lib_shift",1271            "values": {"c++20": 201806},1272            "headers": ["algorithm"],1273        },1274        {1275            "name": "__cpp_lib_smart_ptr_for_overwrite",1276            "values": {"c++20": 202002},1277            "headers": ["memory"],1278        },1279        {1280            "name": "__cpp_lib_smart_ptr_owner_equality",1281            "values": {1282                "c++26": 202306  # P1901R2 Enabling the Use of weak_ptr as Keys in Unordered Associative Containers1283            },1284            "headers": ["memory"],1285            "unimplemented": True,1286        },1287        {1288            "name": "__cpp_lib_source_location",1289            "values": {"c++20": 201907},1290            "headers": ["source_location"],1291        },1292        {1293            "name": "__cpp_lib_span",1294            "values": {1295                "c++20": 202002,1296                # "c++26": 202311,  # P2821R5 span.at()1297                #          202311   # P2833R2 Freestanding Library: inout expected span1298            },1299            "headers": ["span"],1300        },1301        {1302            "name": "__cpp_lib_span_at",1303            "values": {"c++26": 202311},  # P2821R3 span.at()1304            "headers": ["span"],1305        },1306        {1307            "name": "__cpp_lib_span_initializer_list",1308            "values": {"c++26": 202311},  # P2447R6 std::span over an initializer list1309            "headers": ["span"],1310        },1311        {1312            "name": "__cpp_lib_spanstream",1313            "values": {"c++23": 202106},1314            "headers": ["spanstream"],1315            "unimplemented": True,1316        },1317        {1318            "name": "__cpp_lib_ssize",1319            "values": {"c++20": 201902},1320            "headers": ["iterator"],1321        },1322        {1323            "name": "__cpp_lib_sstream_from_string_view",1324            "values": {1325                "c++26": 202306  # P2495R3 Interfacing stringstreams with string_view1326            },1327            "headers": ["sstream"],1328        },1329        {1330            "name": "__cpp_lib_stacktrace",1331            "values": {"c++23": 202011},1332            "headers": ["stacktrace"],1333            "unimplemented": True,1334        },1335        {1336            "name": "__cpp_lib_starts_ends_with",1337            "values": {"c++20": 201711},1338            "headers": ["string", "string_view"],1339        },1340        {1341            "name": "__cpp_lib_stdatomic_h",1342            "values": {"c++23": 202011},1343            "headers": ["stdatomic.h"],1344        },1345        {1346            "name": "__cpp_lib_string_contains",1347            "values": {"c++23": 202011},1348            "headers": ["string", "string_view"],1349        },1350        {1351            "name": "__cpp_lib_string_resize_and_overwrite",1352            "values": {"c++23": 202110},1353            "headers": ["string"],1354        },1355        {1356            "name": "__cpp_lib_string_subview",1357            "values": {"c++26": 202506},1358            "headers": ["string", "string_view"],1359        },1360        {1361            "name": "__cpp_lib_string_udls",1362            "values": {"c++14": 201304},1363            "headers": ["string"],1364        },1365        {1366            "name": "__cpp_lib_string_view",1367            "values": {1368                "c++17": 201606,1369                "c++20": 201803,1370                "c++26": 202403,  # P2591R5: Concatenation of strings and string views1371            },1372            "headers": ["string", "string_view"],1373        },1374        {1375            "name": "__cpp_lib_submdspan",1376            "values": {1377                "c++26": 202306, # P2630R4: submdspan1378                # "c++26": 202403, # P2642R6: Padded mdspan layouts1379            },1380            "headers": ["mdspan"],1381            "unimplemented": True,1382        },1383        {1384            "name": "__cpp_lib_syncbuf",1385            "values": {"c++20": 201803},1386            "headers": ["syncstream"],1387            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM",1388            "libcxx_guard": "_LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM",1389        },1390        {1391            "name": "__cpp_lib_text_encoding",1392            "values": {1393                "c++26": 202306  # P1885R12 Naming Text Encodings to Demystify Them1394            },1395            "headers": ["text_encoding"],1396            "unimplemented": True,1397        },1398        {1399            "name": "__cpp_lib_three_way_comparison",1400            "values": {"c++20": 201907},1401            "headers": ["compare"],1402        },1403        {1404            "name": "__cpp_lib_to_address",1405            "values": {"c++20": 201711},1406            "headers": ["memory"],1407        },1408        {1409            "name": "__cpp_lib_to_array",1410            "values": {"c++20": 201907},1411            "headers": ["array"],1412        },1413        {1414            "name": "__cpp_lib_to_chars",1415            "values": {1416                "c++17": 201611,1417                "c++26": 202306,  # P2497R0 Testing for success or failure of <charconv> functions1418            },1419            "headers": ["charconv"],1420            "unimplemented": True,1421        },1422        {1423            "name": "__cpp_lib_to_string",1424            "values": {"c++26": 202306},  # P2587R3 to_string or not to_string1425            "headers": ["string"],1426            "unimplemented": True,1427        },1428        {1429            "name": "__cpp_lib_to_underlying",1430            "values": {"c++23": 202102},1431            "headers": ["utility"],1432        },1433        {1434            "name": "__cpp_lib_transformation_trait_aliases",1435            "values": {"c++14": 201304},1436            "headers": ["type_traits"],1437        },1438        {1439            "name": "__cpp_lib_transparent_operators",1440            "values": {"c++14": 201210, "c++17": 201510},1441            "headers": ["functional", "memory"],1442        },1443        {1444            "name": "__cpp_lib_tuple_element_t",1445            "values": {"c++14": 201402},1446            "headers": ["tuple"],1447        },1448        {1449            "name": "__cpp_lib_tuple_like",1450            "values": {1451                "c++23": 202207,  # P2165R4 Compatibility between tuple, pair and tuple-like objects1452                "c++26": 202311,  # P2819R2 Add tuple protocol to complex (implemented)1453            },1454            "headers": ["map", "tuple", "unordered_map", "utility"],1455            "unimplemented": True,1456        },1457        {1458            "name": "__cpp_lib_tuples_by_type",1459            "values": {"c++14": 201304},1460            "headers": ["tuple", "utility"],1461        },1462        {1463            "name": "__cpp_lib_type_identity",1464            "values": {"c++20": 201806},1465            "headers": ["type_traits"],1466        },1467        {1468            "name": "__cpp_lib_type_trait_variable_templates",1469            "values": {"c++17": 201510},1470            "headers": ["type_traits"],1471        },1472        {1473            "name": "__cpp_lib_uncaught_exceptions",1474            "values": {"c++17": 201411},1475            "headers": ["exception"],1476        },1477        {1478            "name": "__cpp_lib_unordered_map_try_emplace",1479            "values": {"c++17": 201411},1480            "headers": ["unordered_map"],1481        },1482        {1483            "name": "__cpp_lib_unreachable",1484            "values": {"c++23": 202202},1485            "headers": ["utility"],1486        },1487        {1488            "name": "__cpp_lib_unwrap_ref",1489            "values": {"c++20": 201811},1490            "headers": ["functional"],1491        },1492        {1493            "name": "__cpp_lib_variant",1494            "values": {1495                "c++17": 202102,  # std::visit for classes derived from std::variant1496                "c++20": 202106,  # P2231R1 Missing constexpr in std::optional and std::variant1497                "c++26": 202306,  # P2637R3 Member visit1498            },1499            "headers": ["variant"],1500        },1501        {1502            "name": "__cpp_lib_void_t",1503            "values": {"c++17": 201411},1504            "headers": ["type_traits"],1505        },1506    ]1507]1508 1509assert feature_test_macros == sorted(feature_test_macros, key=lambda tc: tc["name"])1510for tc in feature_test_macros:1511    assert tc["headers"] == sorted(tc["headers"]), tc1512    assert ("libcxx_guard" in tc) == ("test_suite_guard" in tc), tc1513    valid_keys = ["name", "values", "headers", "libcxx_guard", "test_suite_guard", "unimplemented"]1514    assert all(key in valid_keys for key in tc.keys()), tc1515 1516# Map from each header to the Lit annotations that should be used for1517# tests that include that header.1518#1519# For example, when threads are not supported, any test that includes1520# <thread> should be marked as UNSUPPORTED, because including <thread>1521# is a hard error in that case.1522lit_markup = {1523    "barrier": ["UNSUPPORTED: no-threads"],1524    "filesystem": ["UNSUPPORTED: no-filesystem"],1525    "fstream": ["UNSUPPORTED: no-localization"],1526    "iomanip": ["UNSUPPORTED: no-localization"],1527    "ios": ["UNSUPPORTED: no-localization"],1528    "iostream": ["UNSUPPORTED: no-localization"],1529    "istream": ["UNSUPPORTED: no-localization"],1530    "latch": ["UNSUPPORTED: no-threads"],1531    "locale": ["UNSUPPORTED: no-localization"],1532    "mutex": ["UNSUPPORTED: no-threads"],1533    "ostream": ["UNSUPPORTED: no-localization"],1534    "print": ["UNSUPPORTED: no-filesystem"],1535    "regex": ["UNSUPPORTED: no-localization"],1536    "semaphore": ["UNSUPPORTED: no-threads"],1537    "shared_mutex": ["UNSUPPORTED: no-threads"],1538    "sstream": ["UNSUPPORTED: no-localization"],1539    "syncstream": ["UNSUPPORTED: no-localization"],1540    "stdatomic.h": ["UNSUPPORTED: no-threads"],1541    "stop_token": ["UNSUPPORTED: no-threads"],1542    "thread": ["UNSUPPORTED: no-threads"],1543}1544 1545 1546def get_std_dialects():1547    std_dialects = ["c++14", "c++17", "c++20", "c++23", "c++26"]1548    return list(std_dialects)1549 1550 1551def get_first_std(d):1552    for s in get_std_dialects():1553        if s in d.keys():1554            return s1555    return None1556 1557 1558def get_last_std(d):1559    rev_dialects = get_std_dialects()1560    rev_dialects.reverse()1561    for s in rev_dialects:1562        if s in d.keys():1563            return s1564    return None1565 1566 1567def get_std_before(d, std):1568    std_dialects = get_std_dialects()1569    candidates = std_dialects[0 : std_dialects.index(std)]1570    candidates.reverse()1571    for cand in candidates:1572        if cand in d.keys():1573            return cand1574    return None1575 1576 1577def get_value_before(d, std):1578    new_std = get_std_before(d, std)1579    if new_std is None:1580        return None1581    return d[new_std]1582 1583 1584def get_for_std(d, std):1585    # This catches the C++11 case for which there should be no defined feature1586    # test macros.1587    std_dialects = get_std_dialects()1588    if std not in std_dialects:1589        return None1590    # Find the value for the newest C++ dialect between C++14 and std1591    std_list = list(std_dialects[0 : std_dialects.index(std) + 1])1592    std_list.reverse()1593    for s in std_list:1594        if s in d.keys():1595            return d[s]1596    return None1597 1598 1599def get_std_number(std):1600    return std.replace("c++", "")1601 1602 1603"""1604  Functions to produce the <version> header1605"""1606 1607 1608def produce_macros_definition_for_std(std):1609    result = ""1610    indent = 551611    for tc in feature_test_macros:1612        if std not in tc["values"]:1613            continue1614        inner_indent = 11615        if "test_suite_guard" in tc.keys():1616            result += "# if %s\n" % tc["libcxx_guard"]1617            inner_indent += 21618        if get_value_before(tc["values"], std) is not None:1619            assert "test_suite_guard" not in tc.keys()1620            result += "# undef  %s\n" % tc["name"]1621        line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])1622        line += " " * (indent - len(line))1623        line += " %sL" % tc["values"][std]1624        if "unimplemented" in tc.keys():1625            line = "// " + line1626        result += line1627        result += "\n"1628        if "test_suite_guard" in tc.keys():1629            result += "# endif\n"1630    return result.strip()1631 1632 1633def produce_macros_definitions():1634    macro_definition_template = """#if _LIBCPP_STD_VER >= {std_number}1635{macro_definition}1636#endif"""1637 1638    macros_definitions = []1639    for std in get_std_dialects():1640        macros_definitions.append(1641            macro_definition_template.format(1642                std_number=get_std_number(std),1643                macro_definition=produce_macros_definition_for_std(std),1644            )1645        )1646 1647    return "\n\n".join(macros_definitions)1648 1649 1650def chunks(l, n):1651    """Yield successive n-sized chunks from l."""1652    for i in range(0, len(l), n):1653        yield l[i : i + n]1654 1655 1656def produce_version_synopsis():1657    indent = 561658    header_indent = 56 + len("20XXYYL ")1659    result = ""1660 1661    def indent_to(s, val):1662        if len(s) >= val:1663            return s1664        s += " " * (val - len(s))1665        return s1666 1667    line = indent_to("Macro name", indent) + "Value"1668    line = indent_to(line, header_indent) + "Headers"1669    result += line + "\n"1670    for tc in feature_test_macros:1671        prev_defined_std = get_last_std(tc["values"])1672        line = "{name: <{indent}}{value}L ".format(1673            name=tc["name"], indent=indent, value=tc["values"][prev_defined_std]1674        )1675        headers = list(tc["headers"])1676        headers.remove("version")1677        for chunk in chunks(headers, 3):1678            line = indent_to(line, header_indent)1679            chunk = ["<%s>" % header for header in chunk]1680            line += " ".join(chunk)1681            result += line1682            result += "\n"1683            line = ""1684        while True:1685            prev_defined_std = get_std_before(tc["values"], prev_defined_std)1686            if prev_defined_std is None:1687                break1688            result += "%s%sL // %s\n" % (1689                indent_to("", indent),1690                tc["values"][prev_defined_std],1691                prev_defined_std.replace("c++", "C++"),1692            )1693    return result1694 1695 1696def produce_version_header():1697    template = """// -*- C++ -*-1698//===----------------------------------------------------------------------===//1699//1700// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.1701// See https://llvm.org/LICENSE.txt for license information.1702// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception1703//1704//===----------------------------------------------------------------------===//1705 1706#ifndef _LIBCPP_VERSIONH1707#define _LIBCPP_VERSIONH1708 1709/*1710  version synopsis1711 1712{synopsis}1713 1714*/1715 1716#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)1717#  include <__cxx03/version>1718#else1719#  include <__config>1720 1721#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)1722#    pragma GCC system_header1723#  endif1724 1725// clang-format off1726 1727{cxx_macros}1728 1729#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)1730 1731// clang-format on1732 1733#endif // _LIBCPP_VERSIONH1734"""1735 1736    version_str = template.format(1737        synopsis=produce_version_synopsis().strip(),1738        cxx_macros=produce_macros_definitions(),1739    )1740    version_header_path = os.path.join(include_path, "version")1741    with open(version_header_path, "w", newline="\n") as f:1742        f.write(version_str)1743 1744 1745"""1746    Functions to produce test files1747"""1748 1749test_types = {1750    "undefined": """1751#  ifdef {name}1752#    error "{name} should not be defined before {std_first}"1753#  endif1754""",1755    "test_suite_guard": """1756#  if {test_suite_guard}1757#    ifndef {name}1758#      error "{name} should be defined in {std}"1759#    endif1760#    if {name} != {value}1761#      error "{name} should have the value {value} in {std}"1762#    endif1763#  else1764#    ifdef {name}1765#      error "{name} should not be defined when the requirement '{test_suite_guard}' is not met!"1766#    endif1767#  endif1768""",1769    "unimplemented": """1770#  if !defined(_LIBCPP_VERSION)1771#    ifndef {name}1772#      error "{name} should be defined in {std}"1773#    endif1774#    if {name} != {value}1775#      error "{name} should have the value {value} in {std}"1776#    endif1777#  else1778#    ifdef {name}1779#      error "{name} should not be defined because it is unimplemented in libc++!"1780#    endif1781#  endif1782""",1783    "defined": """1784#  ifndef {name}1785#    error "{name} should be defined in {std}"1786#  endif1787#  if {name} != {value}1788#    error "{name} should have the value {value} in {std}"1789#  endif1790""",1791}1792 1793 1794def generate_std_test(test_list, std):1795    result = ""1796    for tc in test_list:1797        val = get_for_std(tc["values"], std)1798        if val is not None:1799            val = "%sL" % val1800        if val is None:1801            result += test_types["undefined"].format(1802                name=tc["name"], std_first=get_first_std(tc["values"])1803            )1804        elif "unimplemented" in tc.keys():1805            result += test_types["unimplemented"].format(1806                name=tc["name"], value=val, std=std1807            )1808        elif "test_suite_guard" in tc.keys():1809            result += test_types["test_suite_guard"].format(1810                name=tc["name"],1811                value=val,1812                std=std,1813                test_suite_guard=tc["test_suite_guard"],1814            )1815        else:1816            result += test_types["defined"].format(name=tc["name"], value=val, std=std)1817    return result.strip()1818 1819 1820def generate_std_tests(test_list):1821    std_tests_template = """#if TEST_STD_VER < {first_std_number}1822 1823{pre_std_test}1824 1825{other_std_tests}1826 1827#elif TEST_STD_VER > {penultimate_std_number}1828 1829{last_std_test}1830 1831#endif // TEST_STD_VER > {penultimate_std_number}"""1832 1833    std_dialects = get_std_dialects()1834 1835    other_std_tests = []1836    for std in std_dialects[:-1]:1837        other_std_tests.append("#elif TEST_STD_VER == " + get_std_number(std))1838        other_std_tests.append(generate_std_test(test_list, std))1839 1840    std_tests = std_tests_template.format(1841        first_std_number=get_std_number(std_dialects[0]),1842        pre_std_test=generate_std_test(test_list, "c++11"),1843        other_std_tests="\n\n".join(other_std_tests),1844        penultimate_std_number=get_std_number(std_dialects[-2]),1845        last_std_test=generate_std_test(test_list, std_dialects[-1]),1846    )1847 1848    return std_tests1849 1850 1851def generate_synopsis(test_list):1852    max_name_len = max([len(tc["name"]) for tc in test_list])1853    indent = max_name_len + 81854 1855    def mk_line(prefix, suffix):1856        return "{prefix: <{max_len}}{suffix}\n".format(1857            prefix=prefix, suffix=suffix, max_len=indent1858        )1859 1860    result = ""1861    result += mk_line("/*  Constant", "Value")1862    for tc in test_list:1863        prefix = "    %s" % tc["name"]1864        for std in [s for s in get_std_dialects() if s in tc["values"].keys()]:1865            result += mk_line(1866                prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++"))1867            )1868            prefix = ""1869    result += "*/"1870    return result1871 1872 1873def produce_tests():1874    headers = set([h for tc in feature_test_macros for h in tc["headers"]])1875    for h in headers:1876        test_list = [tc for tc in feature_test_macros if h in tc["headers"]]1877        if not has_header(h):1878            for tc in test_list:1879                assert "unimplemented" in tc.keys()1880            continue1881        markup = "\n".join("// " + tag for tag in lit_markup.get(h, []))1882        test_body = """//===----------------------------------------------------------------------===//1883//1884// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.1885// See https://llvm.org/LICENSE.txt for license information.1886// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception1887//1888//===----------------------------------------------------------------------===//1889 1890// WARNING: This test was generated by {script_name}1891// and should not be edited manually.1892{markup}1893// <{header}>1894 1895// Test the feature test macros defined by <{header}>1896 1897// clang-format off1898 1899#include <{header}>1900#include "test_macros.h"1901 1902{cxx_tests}1903 1904// clang-format on1905""".format(1906            script_name=script_name,1907            header=h,1908            markup=("\n{}\n".format(markup) if markup else ""),1909            cxx_tests=generate_std_tests(test_list),1910        )1911        test_name = "{header}.version.compile.pass.cpp".format(header=h)1912        out_path = os.path.join(macro_test_path, test_name)1913        with open(out_path, "w", newline="\n") as f:1914            f.write(test_body)1915 1916 1917"""1918    Produce documentation for the feature test macros1919"""1920 1921 1922def make_widths(grid):1923    widths = []1924    for i in range(0, len(grid[0])):1925        cell_width = 2 + max(1926            reduce(lambda x, y: x + y, [[len(row[i])] for row in grid], [])1927        )1928        widths += [cell_width]1929    return widths1930 1931 1932def create_table(grid, indent):1933    indent_str = " " * indent1934    col_widths = make_widths(grid)1935    result = [indent_str + add_divider(col_widths, 2)]1936    header_flag = 21937    for row_i in range(0, len(grid)):1938        row = grid[row_i]1939        line = indent_str + " ".join(1940            [pad_cell(row[i], col_widths[i]) for i in range(0, len(row))]1941        )1942        result.append(line.rstrip())1943        if row_i == len(grid) - 1:1944            header_flag = 21945        if row[0].startswith("**"):1946            header_flag += 11947        separator = indent_str + add_divider(col_widths, header_flag)1948        result.append(separator.rstrip())1949        header_flag = 01950    return "\n".join(result)1951 1952 1953def add_divider(widths, header_flag):1954    if header_flag == 3:1955        return "=".join(["=" * w for w in widths])1956    if header_flag == 2:1957        return " ".join(["=" * w for w in widths])1958    if header_flag == 1:1959        return "-".join(["-" * w for w in widths])1960    else:1961        return " ".join(["-" * w for w in widths])1962 1963 1964def pad_cell(s, length, left_align=True):1965    padding = (length - len(s)) * " "1966    return s + padding1967 1968 1969def get_status_table():1970    table = [["Macro Name", "Value"]]1971    for std in get_std_dialects():1972        table += [["**" + std.replace("c++", "C++") + "**", ""]]1973        for tc in feature_test_macros:1974            if std not in tc["values"].keys():1975                continue1976            value = "``%sL``" % tc["values"][std]1977            if "unimplemented" in tc.keys():1978                value = "*unimplemented*"1979            table += [["``%s``" % tc["name"], value]]1980    return table1981 1982 1983def produce_docs():1984    doc_str = """.. _FeatureTestMacroTable:1985 1986==========================1987Feature Test Macro Support1988==========================1989 1990.. contents::1991   :local:1992 1993Overview1994========1995 1996This file documents the feature test macros currently supported by libc++.1997 1998.. _feature-status:1999 2000Status2001======2002 2003.. table:: Current Status2004    :name: feature-status-table2005    :widths: auto2006 2007{status_tables}2008 2009""".format(2010        status_tables=create_table(get_status_table(), 4)2011    )2012 2013    table_doc_path = os.path.join(docs_path, "FeatureTestMacroTable.rst")2014    with open(table_doc_path, "w", newline="\n") as f:2015        f.write(doc_str)2016 2017 2018Std = NewType("Std", str)  # Standard version number2019Ftm = NewType("Ftm", str)  # The name of a feature test macro2020Value = NewType("Value", str)  # The value of a feature test macro including the L suffix2021 2022@dataclass2023class Metadata:2024    headers: List[str] = None2025    available_since: Std = None2026    test_suite_guard: str = None2027    libcxx_guard: str = None2028 2029 2030@dataclass2031class VersionHeader:2032    value: Value = None2033    implemented: bool = None2034    need_undef: bool = None2035    condition: str = None2036 2037 2038@dataclass2039class FtmHeaderTest:2040    value: Value = None2041    implemented: bool = None2042    condition: str = None2043 2044def get_ftms(2045    data, std_dialects: List[Std], use_implemented_status: bool2046) -> Dict[Ftm, Dict[Std, Optional[Value]]]:2047    """Impementation for FeatureTestMacros.(standard|implemented)_ftms()."""2048    result = dict()2049    for feature in data:2050        last = None2051        entry = dict()2052        implemented = True2053        for std in std_dialects:2054            if std not in feature["values"].keys():2055                if last == None:2056                    continue2057                else:2058                    entry[std] = last2059            else:2060                if implemented:2061                    values = feature["values"][std]2062                    assert len(values) > 0, f"{feature['name']}[{std}] has no entries"2063                    for value in values:2064                        papers = list(values[value])2065                        assert (2066                            len(papers) > 02067                        ), f"{feature['name']}[{std}][{value}] has no entries"2068                        for paper in papers:2069                            if use_implemented_status and not paper["implemented"]:2070                                implemented = False2071                                break2072                        if implemented:2073                            last = f"{value}L"2074                        else:2075                            break2076 2077                if last:2078                    entry[std] = last2079        result[feature["name"]] = entry2080 2081    return result2082 2083 2084def generate_version_header_dialect_block(data: Dict[Ftm, VersionHeader]) -> str:2085    """Generates the contents of the version header for a dialect.2086 2087    This generates the contents of a2088      #if  _LIBCPP_STD_VER >= XY2089      #endif // _LIBCPP_STD_VER >= XY2090    block.2091    """2092    result = ""2093    for element in data:2094        for ftm, entry in element.items():2095            if not entry.implemented:2096                # When a FTM is not implemented don't add the guards2097                # or undefine the (possibly) defined macro.2098                result += f"// define {ftm} {entry.value}\n"2099            else:2100                need_undef = entry.need_undef2101                if entry.condition:2102                    result += f"#  if {entry.condition}\n"2103                    if entry.need_undef:2104                        result += f"#    undef {ftm}\n"2105                    result += f"#    define {ftm} {entry.value}\n"2106                    result += f"#  endif\n"2107                else:2108                    if entry.need_undef:2109                        result += f"#  undef {ftm}\n"2110                    result += f"#  define {ftm} {entry.value}\n"2111 2112    return result2113 2114 2115def generate_version_header_implementation(2116    data: Dict[Std, Dict[Ftm, VersionHeader]]2117) -> str:2118    """Generates the body of the version header."""2119 2120    template = """#if _LIBCPP_STD_VER >= {dialect}2121{feature_test_macros}#endif // _LIBCPP_STD_VER >= {dialect}"""2122 2123    result = []2124    for std, ftms in data.items():2125        result.append(2126            template.format(2127                dialect=std,2128                feature_test_macros=generate_version_header_dialect_block(ftms),2129            )2130        )2131 2132    return "\n\n".join(result)2133 2134#2135# The templates used to create a FTM test file2136#2137 2138 2139ftm_header_test_file_contents = """//===----------------------------------------------------------------------===//2140//2141// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.2142// See https://llvm.org/LICENSE.txt for license information.2143// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception2144//2145//===----------------------------------------------------------------------===//2146 2147// WARNING: This test was generated by {script_name}2148// and should not be edited manually.2149 2150{lit_markup}// <{header}>2151 2152// Test the feature test macros defined by <{header}>2153 2154// clang-format off2155 2156{include}2157#include "test_macros.h"2158{data}2159 2160// clang-format on2161 2162"""2163 2164 2165ftm_header_test_file_include_unconditional = """\2166#include <{header}>\2167"""2168 2169# On Windows the Windows SDK is on the include path, that means the MSVC STL2170# headers can be found as well, tricking __has_include into thinking that2171# libc++ provides the header. This means the test is also not executed when2172# using this test with MSVC and MSVC STL.2173ftm_header_test_file_include_conditional = """\2174#if !defined(_WIN32) && __has_include(<{header}>)2175#  include <{header}>2176#endif\2177"""2178 2179ftm_header_test_file_dialect_block = """2180#{pp_if} TEST_STD_VER {operator} {dialect}2181{tests}\2182"""2183 2184class FeatureTestMacros:2185    """Provides all feature-test macro (FTM) output components.2186 2187    The class has several generators to use the feature-test macros in libc++:2188    - FTM status page2189    - The version header and its tests2190 2191    This class is not intended to duplicate2192    https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros2193    SD-FeatureTest: Feature-Test Macros and Policies2194 2195    Historically libc++ did not list all papers affecting a FTM, the new data2196    structure is able to do that. However there is no intention to add the2197    historical data. After papers have been implemented this information can be2198    removed. For example, __cpp_lib_format's value 201907 requires 3 papers,2199    once implemented it can be reduced to 1 paper and remove the paper number2200    and title. This would reduce the size of the data.2201 2202    The input data is stored in the following JSON format:2203    [ # A list with multiple feature-test macro entries.2204      {2205        # required2206        # The name of the feature test macro. These names should be unique and2207        # sorted in the list.2208        "name": "__cpp_lib_any",2209 2210        # required2211        # A map with the value of the FTM based on the language standard. Only2212        # the versions in which the value of the FTM changes are listed. For2213        # example, this macro's value does not change in C++20 so it does not2214        # list C++20. If it changes in C++26, it will have entries for C++17 and2215        # C++26.2216        "values": {2217 2218          # required2219          # The language standard, also named dialect in this class.2220          "c++17": {2221 2222            # required2223            # The value of the feature test macro. This contains an array with2224            # one or more papers that need to be implemented before this value2225            # is considered implemented.2226            "201606": [2227              {2228                # optional2229                # Contains the paper number that is part of the FTM version.2230                "number": "P0220R1",2231 2232                # optional2233                # Contains the title of the paper that is part of the FTM2234                # version.2235                "title": "Adopt Library Fundamentals V1 TS Components for C++17"2236 2237                # required2238                # The implementation status of the paper.2239                "implemented": true2240              }2241            ]2242          }2243        },2244 2245        # required2246        # A sorted list of headers that should provide the FTM. The header2247        # <version> is automatically added to this list. This list could be2248        # empty. For example, __cpp_lib_modules is only present in version.2249        # Requiring the field makes it easier to detect accidental omission.2250        "headers": [2251          "any"2252        ],2253 2254        # optional, required when libcxx_guard is present2255        # This field is used only to generate the unit tests for the2256        # feature-test macros. It can't depend on macros defined in <__config>2257        # because the `test/std/` parts of the test suite are intended to be2258        # portable to any C++ standard library implementation, not just libc++.2259        # It may depend on2260        # * macros defined by the compiler itself, or2261        # * macros generated by CMake.2262        # In some cases we add also depend on macros defined in2263        # <__availability>.2264        "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR"2265 2266        # optional, required when test_suite_guard is present2267        # This field is used only to guard the feature-test macro in2268        # <version>. It may be the same as `test_suite_guard`, or it may2269        # depend on macros defined in <__config>.2270        "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR"2271      },2272    ]2273    """2274 2275    # The JSON data structure.2276    __data = None2277    # The headers not available in libc++.2278    #2279    # This could be detected based on FTM status, however that gives some odd2280    # results. For example, at the moment __cpp_lib_constexpr_cmath is not2281    # implemented, which flags `<cstdlib>` as not implemented. The availability2282    # of headers is maintained for the C++ Standard Library modules.2283    __unavailable_headers = None2284 2285    def __init__(self, filename: str, unavailable_headers: List[str]):2286        """Initializes the class with the JSON data in the file 'filename'."""2287        with open(filename) as f:2288            self.__data = json.load(f)2289 2290        self.__unavailable_headers = set(unavailable_headers)2291 2292    @functools.cached_property2293    def std_dialects(self) -> List[Std]:2294        """Returns the C++ dialects avaiable.2295 2296        The available dialects are based on the 'c++xy' keys found the 'values'2297        entries in '__data'. So when WG21 starts to feature-test macros for a2298        future C++ Standard this dialect will automatically be available.2299 2300        The return value is a sorted list with the C++ dialects used. Since FTM2301        were added in C++14 the list will not contain C++03 or C++11.2302        """2303        dialects = set()2304        for feature in self.__data:2305            keys = feature["values"].keys()2306            assert len(keys) > 0, "'values' is empty"2307            dialects |= keys2308 2309        return sorted(list(dialects))2310 2311    @functools.cached_property2312    def standard_ftms(self) -> Dict[Ftm, Dict[Std, Optional[Value]]]:2313        """Returns the FTM versions per dialect in the Standard.2314 2315        This function does not use the 'implemented' flag. The output contains2316        the versions used in the Standard. When a FTM in libc++ is not2317        implemented according to the Standard to output may opt to show the2318        expected value.2319        """2320        return get_ftms(self.__data, self.std_dialects, False)2321 2322    @functools.cached_property2323    def standard_library_headers(self) -> Set[str]:2324        """Returns a list of headers that contain at least one FTM."""2325 2326        result = set()2327        for value in self.ftm_metadata.values():2328            for header in value.headers:2329                result.add(header)2330 2331        return list(result)2332 2333    @functools.cached_property2334    def implemented_ftms(self) -> Dict[Ftm, Dict[Std, Optional[Value]]]:2335        """Returns the FTM versions per dialect implemented in libc++.2336 2337        Unlike `get_std_dialect_versions` this function uses the 'implemented'2338        flag. This returns the actual implementation status in libc++.2339        """2340 2341        return get_ftms(self.__data, self.std_dialects, True)2342 2343 2344    def is_implemented(self, ftm: Ftm, std: Std) -> bool:2345        """Has the FTM `ftm` been implemented in the dialect `std`?"""2346 2347        # When a paper for C++20 has not been implemented in libc++, then there will be no2348        # FTM entry in implemented_ftms for C++23 and later. Similarly, a paper like <format>2349        # has no entry in standard_ftms for e.g. C++11.2350        if not std in self.implemented_ftms[ftm].keys() or not std in self.standard_ftms[ftm].keys():2351            return False2352 2353        return self.implemented_ftms[ftm][std] == self.standard_ftms[ftm][std]2354 2355    @functools.cached_property2356    def ftm_metadata(self) -> Dict[Ftm, Metadata]:2357        """Returns the metadata of the FTMs defined in the Standard.2358 2359        The metadata does not depend on the C++ dialect used.2360        """2361        result = dict()2362        for feature in self.__data:2363            result[feature["name"]] = Metadata(2364                feature["headers"],2365                list(feature["values"])[0],2366                feature.get("test_suite_guard", None),2367                feature.get("libcxx_guard", None),2368            )2369 2370        return result2371 2372    @property2373    def version_header_implementation(self) -> Dict[Std, Dict[Ftm, VersionHeader]]:2374        """Generates the body of the version header."""2375        result = dict()2376        for std in self.std_dialects:2377            result[get_std_number(std)] = list()2378 2379        for ftm, values in self.standard_ftms.items():2380            last_value = None2381            last_entry = None2382            for std, value in values.items():2383                # When a newer Standard does not change the value of the macro2384                # there is no need to redefine it with the same value.2385                if last_value and value == last_value:2386                    continue2387                last_value = value2388 2389                implemented = self.is_implemented(ftm, std)2390                entry = VersionHeader(2391                    value,2392                    implemented,2393                    last_entry is not None and last_entry.implemented and implemented,2394                    self.ftm_metadata[ftm].libcxx_guard,2395                )2396 2397                last_entry = entry2398                result[get_std_number(std)].append(dict({ftm: entry}))2399 2400        return result2401 2402    @property2403    def version_header(self) -> str:2404        """Generates the version header."""2405        template = """// -*- C++ -*-2406//===----------------------------------------------------------------------===//2407//2408// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.2409// See https://llvm.org/LICENSE.txt for license information.2410// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception2411//2412//===----------------------------------------------------------------------===//2413 2414#ifndef _LIBCPP_VERSIONH2415#define _LIBCPP_VERSIONH2416 2417#include <__config>2418 2419#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)2420#  pragma GCC system_header2421#endif2422 2423{feature_test_macros}2424 2425#endif // _LIBCPP_VERSIONH2426"""2427        return template.format(2428            feature_test_macros=generate_version_header_implementation(2429                self.version_header_implementation2430            )2431        )2432 2433    def header_ftm_data(self, header: str) -> Dict[Std, List[Dict[Ftm, FtmHeaderTest]]]:2434        """Generates the FTM information for a `header`."""2435 2436        result = dict()2437        for std in self.std_dialects:2438            result[get_std_number(std)] = list()2439 2440        for ftm, values in self.standard_ftms.items():2441            if not header in self.ftm_metadata[ftm].headers:2442                continue2443 2444            last_value = None2445            last_entry = None2446 2447            for std in self.std_dialects:2448                if not std in values.keys():2449                    result[get_std_number(std)].append({ftm: None})2450                    continue2451 2452                result[get_std_number(std)].append(2453                        {2454                            ftm: FtmHeaderTest(2455                                values[std],2456                                self.is_implemented(ftm, std),2457                                self.ftm_metadata[ftm].test_suite_guard,2458                            )2459                        }2460                )2461 2462        return result2463 2464 2465    def generate_ftm_test(self, std: Std, ftm: Ftm, value: FtmHeaderTest) -> str:2466        """Adds a single `ftm` test for C++ `std` based on the status information in `value`.2467 2468        When std == None this test is generating the TEST_STD_VER < MIN. Where2469        MIN is the minimum version that has a FTM defined. (In the real data2470        this is 14, since FTM have been introduced in C++14.)2471        """2472 2473        ftm_unavailable_in_dialect = """2474#  ifdef {ftm}2475#    error "{ftm} should not be defined before {dialect}"2476#  endif2477"""2478 2479        ftm_not_implemented = """2480#  if !defined(_LIBCPP_VERSION)2481#    ifndef {ftm}2482#      error "{ftm} should be defined in {dialect}"2483#    endif2484#    if {ftm} != {value}2485#      error "{ftm} should have the value {value} in {dialect}"2486#    endif2487#  else2488#    ifdef {ftm}2489#      error "{ftm} should not be defined because it is unimplemented in libc++!"2490#    endif2491#  endif2492"""2493 2494        ftm_conditionally_implemented = """2495#  if {condition}2496#    ifndef {ftm}2497#      error "{ftm} should be defined in {dialect}"2498#    endif2499#    if {ftm} != {value}2500#      error "{ftm} should have the value {value} in {dialect}"2501#    endif2502#  else2503#    ifdef {ftm}2504#      error "{ftm} should not be defined when the requirement '{condition}' is not met!"2505#    endif2506#  endif2507"""2508 2509        ftm_implemented = """2510#  ifndef {ftm}2511#    error "{ftm} should be defined in {dialect}"2512#  endif2513#  if {ftm} != {value}2514#    error "{ftm} should have the value {value} in {dialect}"2515#  endif2516"""2517 2518        if std == None or value == None:2519            return ftm_unavailable_in_dialect.format(2520                ftm=ftm, dialect=self.ftm_metadata[ftm].available_since2521            )2522 2523        if not value.implemented:2524            return ftm_not_implemented.format(2525                ftm=ftm, value=value.value, dialect=std2526            )2527 2528        if self.ftm_metadata[ftm].test_suite_guard:2529            return ftm_conditionally_implemented.format(2530                ftm=ftm,2531                value=value.value,2532                dialect=std,2533                condition=self.ftm_metadata[ftm].test_suite_guard,2534            )2535 2536        return ftm_implemented.format(ftm=ftm, value=value.value, dialect=std)2537 2538    def generate_header_test_dialect(2539        self, std: Std, data: List[Dict[Ftm, FtmHeaderTest]]2540    ) -> str:2541        """Returns the body a single `std` for the FTM test of a `header`."""2542        return "".join(2543            self.generate_ftm_test(std, ftm, value)2544            for element in data2545            for ftm, value in element.items()2546        )2547 2548    def generate_lit_markup(self, header:str) -> str:2549        if not header in lit_markup.keys():2550            return ""2551 2552        return "\n".join(f"// {markup}" for markup in lit_markup[header]) + "\n\n"2553 2554    def generate_header_test_file(self, header: str) -> str:2555        """Returns the body for the FTM test of a `header`."""2556 2557        # FTM block before the first Standard that introduced them.2558        # This test the macros are not available before this version.2559        data = ftm_header_test_file_dialect_block.format(2560                pp_if="if",2561                operator="<",2562                dialect=get_std_number(self.std_dialects[0]),2563                tests=self.generate_header_test_dialect(2564                    None, next(iter(self.header_ftm_data(header).values()))2565                ),2566            )2567 2568        # FTM for all Standards that have FTM defined.2569        # Note in libc++ the TEST_STD_VER contains 99 for the Standard2570        # in development, therefore the last entry uses a different #elif.2571        data += "".join(2572                ftm_header_test_file_dialect_block.format(2573                    pp_if="elif",2574                    operator="==" if std != get_std_number(self.std_dialects[-1]) else ">",2575                    dialect=std2576                    if std != get_std_number(self.std_dialects[-1])2577                    else get_std_number(self.std_dialects[-2]),2578                    tests=self.generate_header_test_dialect(f"c++{std}", values),2579                )2580                for std, values in self.header_ftm_data(header).items()2581            )2582 2583        # The final #endif for the last #elif block.2584        data += f"\n#endif // TEST_STD_VER > {get_std_number(self.std_dialects[-2])}"2585 2586        # Generate the test for the requested header.2587        return ftm_header_test_file_contents.format(2588            script_name=script_name,2589            lit_markup=self.generate_lit_markup(header),2590            header=header,2591            include=(2592                ftm_header_test_file_include_conditional.format(header=header)2593                if header in self.__unavailable_headers2594                else ftm_header_test_file_include_unconditional.format(header=header)2595            ),2596            data=data2597        )2598 2599    def generate_header_test_directory(self, path: os.path) -> None:2600        """Generates all FTM tests in the directory `path`."""2601 2602        if not os.path.exists(path):2603            os.makedirs(path)2604 2605        for header in self.standard_library_headers:2606            with open(2607                os.path.join(path, f"{header}.version.compile.pass.cpp"),2608                "w",2609                newline="\n",2610            ) as f:2611                f.write(self.generate_header_test_file(header))2612 2613 2614def main():2615    produce_version_header()2616    produce_tests()2617    produce_docs()2618 2619    # Example how to use the new generator to generate the output.2620    if False:2621        ftm = FeatureTestMacros(2622            os.path.join(2623                source_root, "test", "libcxx", "feature_test_macro", "test_data.json"2624            ), headers_not_available2625        )2626        version_header_path = os.path.join(include_path, "version")2627        with open(version_header_path, "w", newline="\n") as f:2628            f.write(ftm.version_header)2629 2630        ftm.generate_header_test_directory(macro_test_path)2631 2632 2633if __name__ == "__main__":2634    main()2635