xref: /llvm-project/libcxx/utils/generate_feature_test_macro_components.py (revision def50f701f6a2c1e0550bb341fd8b64bed299e72)
1#!/usr/bin/env python
2
3import os
4from builtins import range
5from functools import reduce
6from typing import Any, Dict, List  # Needed for python 3.8 compatibility.
7import functools
8import json
9
10
11def get_libcxx_paths():
12    utils_path = os.path.dirname(os.path.abspath(__file__))
13    script_name = os.path.basename(__file__)
14    assert os.path.exists(utils_path)
15    src_root = os.path.dirname(utils_path)
16    include_path = os.path.join(src_root, "include")
17    assert os.path.exists(include_path)
18    docs_path = os.path.join(src_root, "docs")
19    assert os.path.exists(docs_path)
20    macro_test_path = os.path.join(
21        src_root,
22        "test",
23        "std",
24        "language.support",
25        "support.limits",
26        "support.limits.general",
27    )
28    assert os.path.exists(macro_test_path)
29    assert os.path.exists(
30        os.path.join(macro_test_path, "version.version.compile.pass.cpp")
31    )
32    return script_name, src_root, include_path, docs_path, macro_test_path
33
34
35script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths()
36
37
38def has_header(h):
39    h_path = os.path.join(include_path, h)
40    return os.path.exists(h_path)
41
42
43def add_version_header(tc):
44    tc["headers"].append("version")
45    return tc
46
47
48# ================  ============================================================
49# Field             Description
50# ================  ============================================================
51# name              The name of the feature-test macro.
52# values            A dict whose keys are C++ versions and whose values are the
53#                   value of the feature-test macro for that C++ version.
54#                   (TODO: This isn't a very clean model for feature-test
55#                   macros affected by multiple papers.)
56# headers           An array with the headers that should provide the
57#                   feature-test macro.
58# test_suite_guard  An optional string field. When this field is provided,
59#                   `libcxx_guard` must also be provided. This field is used
60#                   only to generate the unit tests for the feature-test macros.
61#                   It can't depend on macros defined in <__config> because the
62#                   `test/std/` parts of the test suite are intended to be
63#                   portable to any C++ standard library implementation, not
64#                   just libc++. It may depend on
65#                    * macros defined by the compiler itself, or
66#                    * macros generated by CMake.
67#                   In some cases we add also depend on macros defined in
68#                   <__configuration/availability.h>.
69# libcxx_guard      An optional string field. When this field is provided,
70#                   `test_suite_guard` must also be provided. This field is used
71#                   only to guard the feature-test macro in <version>. It may
72#                   be the same as `test_suite_guard`, or it may depend on
73#                   macros defined in <__config>.
74# unimplemented     An optional Boolean field with the value `True`. This field
75#                   is only used when a feature isn't fully implemented. Once
76#                   you've fully implemented the feature, you should remove
77#                   this field.
78# ================  ============================================================
79feature_test_macros = [
80    add_version_header(x)
81    for x in [
82        {
83            "name": "__cpp_lib_adaptor_iterator_pair_constructor",
84            "values": {"c++23": 202106},
85            "headers": ["queue", "stack"],
86        },
87        {
88            "name": "__cpp_lib_addressof_constexpr",
89            "values": {"c++17": 201603},
90            "headers": ["memory"],
91        },
92        {
93            "name": "__cpp_lib_allocate_at_least",
94            "values": {
95                # Note LWG3887 Version macro for allocate_at_least
96                "c++23": 202302,  # P2652R2 Disallow User Specialization of allocator_traits
97            },
98            "headers": ["memory"],
99        },
100        {
101            "name": "__cpp_lib_allocator_traits_is_always_equal",
102            "values": {"c++17": 201411},
103            "headers": [
104                "deque",
105                "forward_list",
106                "list",
107                "map",
108                "memory",
109                "scoped_allocator",
110                "set",
111                "string",
112                "unordered_map",
113                "unordered_set",
114                "vector",
115            ],
116        },
117        {
118            "name": "__cpp_lib_any",
119            "values": {"c++17": 201606},
120            "headers": ["any"],
121        },
122        {
123            "name": "__cpp_lib_apply",
124            "values": {"c++17": 201603},
125            "headers": ["tuple"],
126        },
127        {
128            "name": "__cpp_lib_array_constexpr",
129            "values": {"c++17": 201603, "c++20": 201811},
130            "headers": ["array", "iterator"],
131        },
132        {
133            "name": "__cpp_lib_as_const",
134            "values": {"c++17": 201510},
135            "headers": ["utility"],
136        },
137        {
138            "name": "__cpp_lib_associative_heterogeneous_erasure",
139            "values": {"c++23": 202110},
140            "headers": ["map", "set", "unordered_map", "unordered_set"],
141            "unimplemented": True,
142        },
143        {
144            "name": "__cpp_lib_associative_heterogeneous_insertion",
145            "values": {
146                "c++26": 202306  # P2363R5 Extending associative containers with the remaining heterogeneous overloads
147            },
148            "headers": ["map", "set", "unordered_map", "unordered_set"],
149            "unimplemented": True,
150        },
151        {
152            "name": "__cpp_lib_assume_aligned",
153            "values": {"c++20": 201811},
154            "headers": ["memory"],
155        },
156        {
157            "name": "__cpp_lib_atomic_flag_test",
158            "values": {"c++20": 201907},
159            "headers": ["atomic"],
160        },
161        {
162            "name": "__cpp_lib_atomic_float",
163            "values": {"c++20": 201711},
164            "headers": ["atomic"],
165            "unimplemented": True,
166        },
167        {
168            "name": "__cpp_lib_atomic_is_always_lock_free",
169            "values": {"c++17": 201603},
170            "headers": ["atomic"],
171        },
172        {
173            "name": "__cpp_lib_atomic_lock_free_type_aliases",
174            "values": {"c++20": 201907},
175            "headers": ["atomic"],
176        },
177        {
178            "name": "__cpp_lib_atomic_min_max",
179            "values": {"c++26": 202403}, # P0493R5: Atomic minimum/maximum
180            "headers": ["atomic"],
181            "unimplemented": True,
182        },
183        {
184            "name": "__cpp_lib_atomic_ref",
185            "values": {"c++20": 201806},
186            "headers": ["atomic"],
187        },
188        {
189            "name": "__cpp_lib_atomic_shared_ptr",
190            "values": {"c++20": 201711},
191            "headers": ["atomic"],
192            "unimplemented": True,
193        },
194        {
195            "name": "__cpp_lib_atomic_value_initialization",
196            "values": {"c++20": 201911},
197            "headers": ["atomic", "memory"],
198        },
199        {
200            "name": "__cpp_lib_atomic_wait",
201            "values": {"c++20": 201907},
202            "headers": ["atomic"],
203            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC",
204            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_SYNC",
205        },
206        {
207            "name": "__cpp_lib_barrier",
208            "values": {"c++20": 201907},
209            "headers": ["barrier"],
210            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
211            "libcxx_guard": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
212        },
213        {
214            "name": "__cpp_lib_bind_back",
215            "values": {
216                "c++23": 202202,
217                # "c++26": 202306,  # P2714R1 Bind front and back to NTTP callables
218            },
219            "headers": ["functional"],
220        },
221        {
222            "name": "__cpp_lib_bind_front",
223            "values": {
224                "c++20": 201907,
225                "c++26": 202306,  # P2714R1 Bind front and back to NTTP callables
226            },
227            "headers": ["functional"],
228        },
229        {
230            "name": "__cpp_lib_bit_cast",
231            "values": {"c++20": 201806},
232            "headers": ["bit"],
233        },
234        {
235            "name": "__cpp_lib_bitops",
236            "values": {"c++20": 201907},
237            "headers": ["bit"],
238        },
239        {
240            "name": "__cpp_lib_bitset",
241            "values": {"c++26": 202306},  # P2697R1 Interfacing bitset with string_view
242            "headers": ["bitset"],
243        },
244        {
245            "name": "__cpp_lib_bool_constant",
246            "values": {"c++17": 201505},
247            "headers": ["type_traits"],
248        },
249        {
250            "name": "__cpp_lib_bounded_array_traits",
251            "values": {"c++20": 201902},
252            "headers": ["type_traits"],
253        },
254        {
255            "name": "__cpp_lib_boyer_moore_searcher",
256            "values": {"c++17": 201603},
257            "headers": ["functional"],
258        },
259        {
260            "name": "__cpp_lib_byte",
261            "values": {"c++17": 201603},
262            "headers": ["cstddef"],
263        },
264        {
265            "name": "__cpp_lib_byteswap",
266            "values": {"c++23": 202110},
267            "headers": ["bit"],
268        },
269        {
270            "name": "__cpp_lib_char8_t",
271            "values": {"c++20": 201907},
272            "headers": [
273                "atomic",
274                "filesystem",
275                "istream",
276                "limits",
277                "locale",
278                "ostream",
279                "string",
280                "string_view",
281            ],
282            "test_suite_guard": "defined(__cpp_char8_t)",
283            "libcxx_guard": "_LIBCPP_HAS_CHAR8_T",
284        },
285        {
286            "name": "__cpp_lib_chrono",
287            "values": {
288                "c++17": 201611,
289                # "c++26": 202306, # P2592R3 Hashing support for std::chrono value classes
290            },
291            "headers": ["chrono"],
292        },
293        {
294            "name": "__cpp_lib_chrono_udls",
295            "values": {"c++14": 201304},
296            "headers": ["chrono"],
297        },
298        {
299            "name": "__cpp_lib_clamp",
300            "values": {"c++17": 201603},
301            "headers": ["algorithm"],
302        },
303        {
304            "name": "__cpp_lib_complex_udls",
305            "values": {"c++14": 201309},
306            "headers": ["complex"],
307        },
308        {
309            "name": "__cpp_lib_concepts",
310            "values": {"c++20": 202002},
311            "headers": ["concepts"],
312        },
313        {
314            "name": "__cpp_lib_constexpr_algorithms",
315            "values": {
316                "c++20": 201806,
317                # "c++26": 202306, # P2562R1 constexpr Stable Sorting
318            },
319            "headers": ["algorithm", "utility"],
320        },
321        {
322            "name": "__cpp_lib_constexpr_bitset",
323            "values": {"c++23": 202207},
324            "headers": ["bitset"],
325        },
326        {
327            "name": "__cpp_lib_constexpr_charconv",
328            "values": {"c++23": 202207},
329            "headers": ["charconv"],
330        },
331        {
332            "name": "__cpp_lib_constexpr_cmath",
333            "values": {"c++23": 202202},
334            "headers": ["cmath", "cstdlib"],
335            "unimplemented": True,
336        },
337        {
338            "name": "__cpp_lib_constexpr_complex",
339            "values": {"c++20": 201711},
340            "headers": ["complex"],
341        },
342        {
343            "name": "__cpp_lib_constexpr_dynamic_alloc",
344            "values": {"c++20": 201907},
345            "headers": ["memory"],
346        },
347        {
348            "name": "__cpp_lib_constexpr_functional",
349            "values": {"c++20": 201907},
350            "headers": ["functional"],
351        },
352        {
353            "name": "__cpp_lib_constexpr_iterator",
354            "values": {"c++20": 201811},
355            "headers": ["iterator"],
356        },
357        {
358            "name": "__cpp_lib_constexpr_memory",
359            "values": {"c++20": 201811, "c++23": 202202},
360            "headers": ["memory"],
361        },
362        {
363            "name": "__cpp_lib_constexpr_new",
364            "values": {"c++26": 202406},  # P2747R2 constexpr placement new
365            "headers": ["new"],
366            "test_suite_guard": "!defined(_LIBCPP_ABI_VCRUNTIME)",
367            "libcxx_guard": "!defined(_LIBCPP_ABI_VCRUNTIME)",
368        },
369        {
370            "name": "__cpp_lib_constexpr_numeric",
371            "values": {"c++20": 201911},
372            "headers": ["numeric"],
373        },
374        {
375            "name": "__cpp_lib_constexpr_string",
376            "values": {"c++20": 201907},
377            "headers": ["string"],
378        },
379        {
380            "name": "__cpp_lib_constexpr_string_view",
381            "values": {"c++20": 201811},
382            "headers": ["string_view"],
383        },
384        {
385            "name": "__cpp_lib_constexpr_tuple",
386            "values": {"c++20": 201811},
387            "headers": ["tuple"],
388        },
389        {
390            "name": "__cpp_lib_constexpr_typeinfo",
391            "values": {"c++23": 202106},
392            "headers": ["typeinfo"],
393        },
394        {
395            "name": "__cpp_lib_constexpr_utility",
396            "values": {"c++20": 201811},
397            "headers": ["utility"],
398        },
399        {
400            "name": "__cpp_lib_constexpr_vector",
401            "values": {"c++20": 201907},
402            "headers": ["vector"],
403        },
404        {
405            "name": "__cpp_lib_constrained_equality",
406            "values": {"c++26": 202403}, # P2944R3: Comparisons for reference_wrapper
407            "headers": ["optional", "tuple", "utility", "variant"],
408            "unimplemented": True,
409        },
410        {
411            "name": "__cpp_lib_containers_ranges",
412            "values": {"c++23": 202202},
413            "headers": [
414                "deque",
415                "forward_list",
416                "list",
417                "map",
418                "queue",
419                "set",
420                "stack",
421                "string",
422                "unordered_map",
423                "unordered_set",
424                "vector",
425            ],
426        },
427        {
428            "name": "__cpp_lib_copyable_function",
429            "values": {"c++26": 202306},  # P2548R6 copyable_function
430            "headers": ["functional"],
431            "unimplemented": True,
432        },
433        {
434            "name": "__cpp_lib_coroutine",
435            "values": {"c++20": 201902},
436            "headers": ["coroutine"],
437        },
438        {
439            "name": "__cpp_lib_debugging",
440            "values": {
441                "c++26": 202311, # P2546R5 Debugging Support
442                # "c++26": 202403, # P2810R4: is_debugger_present is_replaceable
443            },
444            "headers": ["debugging"],
445            "unimplemented": True,
446        },
447        {
448            "name": "__cpp_lib_default_template_type_for_algorithm_values",
449            "values": {"c++26": 202403}, # P2248R8: Enabling list-initialization for algorithms
450            "headers": ["algorithm", "deque", "forward_list", "list", "ranges", "string", "vector"],
451            "unimplemented": True,
452        },
453        {
454            "name": "__cpp_lib_destroying_delete",
455            "values": {"c++20": 201806},
456            "headers": ["new"],
457            "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
458            "libcxx_guard": "_LIBCPP_STD_VER >= 20 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
459        },
460        {
461            "name": "__cpp_lib_enable_shared_from_this",
462            "values": {"c++17": 201603},
463            "headers": ["memory"],
464        },
465        {
466            "name": "__cpp_lib_endian",
467            "values": {"c++20": 201907},
468            "headers": ["bit"],
469        },
470        {
471            "name": "__cpp_lib_erase_if",
472            "values": {"c++20": 202002},
473            "headers": [
474                "deque",
475                "forward_list",
476                "list",
477                "map",
478                "set",
479                "string",
480                "unordered_map",
481                "unordered_set",
482                "vector",
483            ],
484        },
485        {
486            "name": "__cpp_lib_exchange_function",
487            "values": {"c++14": 201304},
488            "headers": ["utility"],
489        },
490        {
491            "name": "__cpp_lib_execution",
492            "values": {"c++17": 201603, "c++20": 201902},
493            "headers": ["execution"],
494            "unimplemented": True,
495        },
496        {
497            "name": "__cpp_lib_expected",
498            "values": {"c++23": 202211},
499            "headers": ["expected"],
500        },
501        {
502            "name": "__cpp_lib_filesystem",
503            "values": {"c++17": 201703},
504            "headers": ["filesystem"],
505            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)",
506            "libcxx_guard": "_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY",
507        },
508        {
509            "name": "__cpp_lib_flat_map",
510            "values": {"c++23": 202207},
511            "headers": ["flat_map"],
512        },
513        {
514            "name": "__cpp_lib_flat_set",
515            "values": {"c++23": 202207},
516            "headers": ["flat_set"],
517            "unimplemented": True,
518        },
519        {
520            "name": "__cpp_lib_format",
521            "values": {
522                "c++20": 202110,
523                # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types
524                # "c++26": 202306, P2637R3 Member Visit (implemented)
525                # "c++26": 202311, P2918R2 Runtime format strings II (implemented)
526            },
527            # Note these three papers are adopted at the June 2023 meeting and have sequential numbering
528            # 202304 P2510R3 Formatting pointers (Implemented)
529            # 202305 P2757R3 Type-checking format args
530            # 202306 P2637R3 Member Visit
531            "headers": ["format"],
532        },
533        {
534            "name": "__cpp_lib_format_path",
535            "values": {"c++26": 202403},  # P2845R8: Formatting of std::filesystem::path
536            "headers": ["filesystem"],
537            "unimplemented": True,
538        },
539        {
540            "name": "__cpp_lib_format_ranges",
541            "values": {"c++23": 202207},
542            "headers": ["format"],
543        },
544        {
545            "name": "__cpp_lib_format_uchar",
546            "values": {
547                "c++20": 202311  # DR P2909R4 Fix formatting of code units as integers
548            },
549            "headers": [
550                "format"  # TODO verify this entry since the paper was underspecified.
551            ],
552        },
553        {
554            "name": "__cpp_lib_formatters",
555            "values": {"c++23": 202302},
556            "headers": ["stacktrace", "thread"],
557            "unimplemented": True,
558        },
559        {
560            "name": "__cpp_lib_forward_like",
561            "values": {"c++23": 202207},
562            "headers": ["utility"],
563        },
564        {
565            "name": "__cpp_lib_freestanding_algorithm",
566            "values": {
567                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
568            },
569            "headers": ["algorithm"],
570            "unimplemented": True,
571        },
572        {
573            "name": "__cpp_lib_freestanding_array",
574            "values": {
575                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
576            },
577            "headers": ["array"],
578            "unimplemented": True,
579        },
580        {
581            "name": "__cpp_lib_freestanding_cstring",
582            "values": {
583                "c++26": 202306  # P2338R4 Freestanding Library: Character primitives and the C library
584                #        202311  # P2407R5 Freestanding Library: Partial Classes
585            },
586            "headers": ["cstring"],
587            "unimplemented": True,
588        },
589        {
590            "name": "__cpp_lib_freestanding_expected",
591            "values": {
592                "c++26": 202311  # P2833R2 Freestanding Library: inout expected span
593            },
594            "headers": ["expected"],
595            "unimplemented": True,
596        },
597        {
598            "name": "__cpp_lib_freestanding_mdspan",
599            "values": {
600                "c++26": 202311  # P2833R2 Freestanding Library: inout expected span
601            },
602            "headers": ["mdspan"],
603            "unimplemented": True,
604        },
605        {
606            "name": "__cpp_lib_freestanding_optional",
607            "values": {
608                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
609            },
610            "headers": ["optional"],
611            "unimplemented": True,
612        },
613        {
614            "name": "__cpp_lib_freestanding_string_view",
615            "values": {
616                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
617            },
618            "headers": ["string_view"],
619            "unimplemented": True,
620        },
621        {
622            "name": "__cpp_lib_freestanding_variant",
623            "values": {
624                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
625            },
626            "headers": ["variant"],
627            "unimplemented": True,
628        },
629        {
630            "name": "__cpp_lib_fstream_native_handle",
631            "values": {"c++26": 202306},  # P1759R6 Native handles and file streams
632            "headers": ["fstream"],
633            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION)",
634            "libcxx_guard": "_LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION",
635        },
636        {
637            "name": "__cpp_lib_function_ref",
638            "values": {
639                "c++26": 202306  # P0792R14 function_ref: a type-erased callable reference
640            },
641            "headers": ["functional"],
642            "unimplemented": True,
643        },
644        {
645            "name": "__cpp_lib_gcd_lcm",
646            "values": {"c++17": 201606},
647            "headers": ["numeric"],
648        },
649        {
650            "name": "__cpp_lib_generate_random",
651            "values": {"c++26": 202403}, # P1068R11: Vector API for random number generation
652            "headers": ["random"],
653            "unimplemented": True,
654        },
655        {
656            "name": "__cpp_lib_generic_associative_lookup",
657            "values": {"c++14": 201304},
658            "headers": ["map", "set"],
659        },
660        {
661            "name": "__cpp_lib_generic_unordered_lookup",
662            "values": {"c++20": 201811},
663            "headers": ["unordered_map", "unordered_set"],
664        },
665        {
666            "name": "__cpp_lib_hardware_interference_size",
667            "values": {"c++17": 201703},
668            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE))",
669            "libcxx_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)",
670            "headers": ["new"],
671        },
672        {
673            "name": "__cpp_lib_has_unique_object_representations",
674            "values": {"c++17": 201606},
675            "headers": ["type_traits"],
676        },
677        {
678            "name": "__cpp_lib_hazard_pointer",
679            "values": {"c++26": 202306},  # P2530R3 Hazard Pointers for C++26
680            "headers": [
681                "hazard_pointer"  # TODO verify this entry since the paper was underspecified.
682            ],
683            "unimplemented": True,
684        },
685        {
686            "name": "__cpp_lib_hypot",
687            "values": {"c++17": 201603},
688            "headers": ["cmath"],
689        },
690        {
691            "name": "__cpp_lib_incomplete_container_elements",
692            "values": {"c++17": 201505},
693            "headers": ["forward_list", "list", "vector"],
694        },
695        {
696            "name": "__cpp_lib_inplace_vector",
697            "values": {"c++26": 202406},  # P0843R14 inplace_vector
698            "headers": ["inplace_vector"],
699            "unimplemented": True,
700        },
701        {
702            "name": "__cpp_lib_int_pow2",
703            "values": {"c++20": 202002},
704            "headers": ["bit"],
705        },
706        {
707            "name": "__cpp_lib_integer_comparison_functions",
708            "values": {"c++20": 202002},
709            "headers": ["utility"],
710        },
711        {
712            "name": "__cpp_lib_integer_sequence",
713            "values": {"c++14": 201304},
714            "headers": ["utility"],
715        },
716        {
717            "name": "__cpp_lib_integral_constant_callable",
718            "values": {"c++14": 201304},
719            "headers": ["type_traits"],
720        },
721        {
722            "name": "__cpp_lib_interpolate",
723            "values": {"c++20": 201902},
724            "headers": ["cmath", "numeric"],
725        },
726        {
727            "name": "__cpp_lib_invoke",
728            "values": {"c++17": 201411},
729            "headers": ["functional"],
730        },
731        {
732            "name": "__cpp_lib_invoke_r",
733            "values": {"c++23": 202106},
734            "headers": ["functional"],
735        },
736        {
737            "name": "__cpp_lib_ios_noreplace",
738            "values": {"c++23": 202207},
739            "headers": ["ios"],
740        },
741        {
742            "name": "__cpp_lib_is_aggregate",
743            "values": {"c++17": 201703},
744            "headers": ["type_traits"],
745        },
746        {
747            "name": "__cpp_lib_is_constant_evaluated",
748            "values": {"c++20": 201811},
749            "headers": ["type_traits"],
750        },
751        {
752            "name": "__cpp_lib_is_final",
753            "values": {"c++14": 201402},
754            "headers": ["type_traits"],
755        },
756        {
757            "name": "__cpp_lib_is_implicit_lifetime",
758            "values": {"c++23": 202302},
759            "headers": ["type_traits"],
760            "test_suite_guard": "__has_builtin(__builtin_is_implicit_lifetime)",
761            "libcxx_guard": "__has_builtin(__builtin_is_implicit_lifetime)",
762        },
763        {
764            "name": "__cpp_lib_is_invocable",
765            "values": {"c++17": 201703},
766            "headers": ["type_traits"],
767        },
768        {
769            "name": "__cpp_lib_is_layout_compatible",
770            "values": {"c++20": 201907},
771            "headers": ["type_traits"],
772            "unimplemented": True,
773        },
774        {
775            "name": "__cpp_lib_is_nothrow_convertible",
776            "values": {"c++20": 201806},
777            "headers": ["type_traits"],
778        },
779        {
780            "name": "__cpp_lib_is_null_pointer",
781            "values": {"c++14": 201309},
782            "headers": ["type_traits"],
783        },
784        {
785            "name": "__cpp_lib_is_pointer_interconvertible",
786            "values": {"c++20": 201907},
787            "headers": ["type_traits"],
788            "unimplemented": True,
789        },
790        {
791            "name": "__cpp_lib_is_scoped_enum",
792            "values": {"c++23": 202011},
793            "headers": ["type_traits"],
794        },
795        {
796            "name": "__cpp_lib_is_swappable",
797            "values": {"c++17": 201603},
798            "headers": ["type_traits"],
799        },
800        {
801            "name": "__cpp_lib_is_virtual_base_of",
802            "values": {
803                "c++26": 202406  # P2985R0 A type trait for detecting virtual base classes
804            },
805            "headers": ["type_traits"],
806            "test_suite_guard": "__has_builtin(__builtin_is_virtual_base_of)",
807            "libcxx_guard": "__has_builtin(__builtin_is_virtual_base_of)",
808        },
809        {
810            "name": "__cpp_lib_is_within_lifetime",
811            # Note this name was changed from "__cpp_lib_within_lifetime" when the paper was adopted
812            # https://github.com/cplusplus/draft/commit/0facada4cadd97e1ba15bfaea76a804f1dc5c309
813            "values": {
814                "c++26": 202306  # P2641R4 Checking if a union alternative is active
815            },
816            "headers": ["type_traits"],
817            "unimplemented": True,
818        },
819        {
820            "name": "__cpp_lib_jthread",
821            "values": {"c++20": 201911},
822            "headers": ["stop_token", "thread"],
823            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
824            "libcxx_guard": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
825        },
826        {
827            "name": "__cpp_lib_latch",
828            "values": {"c++20": 201907},
829            "headers": ["latch"],
830            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
831            "libcxx_guard": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
832        },
833        {
834            "name": "__cpp_lib_launder",
835            "values": {"c++17": 201606},
836            "headers": ["new"],
837        },
838        {
839            "name": "__cpp_lib_linalg",
840            "values": {
841                "c++26": 202311  # P1673 A free function linear algebra interface based on the BLAS
842            },
843            "headers": ["linalg"],
844            "unimplemented": True,
845        },
846        {
847            "name": "__cpp_lib_list_remove_return_type",
848            "values": {"c++20": 201806},
849            "headers": ["forward_list", "list"],
850        },
851        {
852            "name": "__cpp_lib_logical_traits",
853            "values": {"c++17": 201510},
854            "headers": ["type_traits"],
855        },
856        {
857            "name": "__cpp_lib_make_from_tuple",
858            "values": {"c++17": 201606},
859            "headers": ["tuple"],
860        },
861        {
862            "name": "__cpp_lib_make_reverse_iterator",
863            "values": {"c++14": 201402},
864            "headers": ["iterator"],
865        },
866        {
867            "name": "__cpp_lib_make_unique",
868            "values": {"c++14": 201304},
869            "headers": ["memory"],
870        },
871        {
872            "name": "__cpp_lib_map_try_emplace",
873            "values": {"c++17": 201411},
874            "headers": ["map"],
875        },
876        {
877            "name": "__cpp_lib_math_constants",
878            "values": {"c++20": 201907},
879            "headers": ["numbers"],
880        },
881        {
882            "name": "__cpp_lib_math_special_functions",
883            "values": {"c++17": 201603},
884            "headers": ["cmath"],
885            "unimplemented": True,
886        },
887        {
888            "name": "__cpp_lib_mdspan",
889            "values": {
890                "c++23": 202207,
891                "c++26": 202406,  # P2389R2 dextents Index Type Parameter
892            },
893            "headers": ["mdspan"],
894        },
895        {
896            "name": "__cpp_lib_memory_resource",
897            "values": {"c++17": 201603},
898            "headers": ["memory_resource"],
899            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",
900            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",
901        },
902        {
903            "name": "__cpp_lib_modules",
904            "values": {"c++23": 202207},
905            "headers": [],
906        },
907        {
908            "name": "__cpp_lib_move_iterator_concept",
909            "values": {"c++20": 202207},
910            "headers": ["iterator"],
911        },
912        {
913            "name": "__cpp_lib_move_only_function",
914            "values": {"c++23": 202110},
915            "headers": ["functional"],
916            "unimplemented": True,
917        },
918        {
919            "name": "__cpp_lib_node_extract",
920            "values": {"c++17": 201606},
921            "headers": ["map", "set", "unordered_map", "unordered_set"],
922        },
923        {
924            "name": "__cpp_lib_nonmember_container_access",
925            "values": {"c++17": 201411},
926            "headers": [
927                "array",
928                "deque",
929                "forward_list",
930                "iterator",
931                "list",
932                "map",
933                "regex",
934                "set",
935                "string",
936                "unordered_map",
937                "unordered_set",
938                "vector",
939            ],
940        },
941        {
942            "name": "__cpp_lib_not_fn",
943            "values": {
944                "c++17": 201603,
945                "c++26": 202306,  # P2714R1 Bind front and back to NTTP callables
946            },
947            "headers": ["functional"],
948        },
949        {
950            "name": "__cpp_lib_null_iterators",
951            "values": {"c++14": 201304},
952            "headers": ["iterator"],
953        },
954        {
955            "name": "__cpp_lib_optional",
956            "values": {
957                "c++17": 201606,
958                "c++20": 202106,  # P2231R1 Missing constexpr in std::optional and std::variant
959                "c++23": 202110,  # P0798R8 Monadic operations for std::optional + LWG3621 Remove feature-test macro __cpp_lib_monadic_optional
960            },
961            "headers": ["optional"],
962        },
963        {
964            "name": "__cpp_lib_optional_range_support",
965            "values": {"c++26": 202406},  # P3168R2 Give std::optional Range Support
966            "headers": ["optional"],
967            "unimplemented": True,
968        },
969        {
970            "name": "__cpp_lib_out_ptr",
971            "values": {
972                "c++23": 202106,
973                "c++26": 202311,  # P2833R2 Freestanding Library: inout expected span
974            },
975            "headers": ["memory"],
976        },
977        {
978            "name": "__cpp_lib_parallel_algorithm",
979            "values": {"c++17": 201603},
980            "headers": ["algorithm", "numeric"],
981            "unimplemented": True,
982        },
983        {
984            "name": "__cpp_lib_philox_engine",
985            "values": {
986                "c++26": 202406
987            },  # P2075R6 Philox as an extension of the C++ RNG engines
988            # Note the paper mentions 202310L as value, which differs from the typical procedure.
989            "headers": ["random"],
990            "unimplemented": True,
991        },
992        {
993            "name": "__cpp_lib_polymorphic_allocator",
994            "values": {"c++20": 201902},
995            "headers": ["memory_resource"],
996            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",
997            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",
998        },
999        {
1000            "name": "__cpp_lib_print",
1001            "values": {
1002                "c++23": 202207,
1003                # "c++26": 202403, # P3107R5: Permit an efficient implementation of std::print
1004                # "c++26": 202406, # P3235R3 std::print more types faster with less memory
1005            },
1006            "headers": ["ostream", "print"],
1007        },
1008        {
1009            "name": "__cpp_lib_quoted_string_io",
1010            "values": {"c++14": 201304},
1011            "headers": ["iomanip"],
1012            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_LOCALIZATION",
1013            "libcxx_guard": "_LIBCPP_HAS_LOCALIZATION",
1014        },
1015        {
1016            "name": "__cpp_lib_ranges",
1017            "values": {
1018                "c++20": 202110,  # P2415R2 What is a view?
1019                "c++23": 202406,  # P2997R1 Removing the common reference requirement from the indirectly invocable concepts (implemented as a DR against C++20)
1020            },
1021            "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
1022        },
1023        {
1024            "name": "__cpp_lib_ranges_as_const",
1025            "values": {
1026                "c++23": 202207  # P2278R4 cbegin should always return a constant iterator
1027                #        202311  # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility
1028            },
1029            "headers": ["ranges"],
1030            "unimplemented": True,
1031        },
1032        {
1033            "name": "__cpp_lib_ranges_as_rvalue",
1034            "values": {"c++23": 202207},
1035            "headers": ["ranges"],
1036        },
1037        {
1038            "name": "__cpp_lib_ranges_chunk",
1039            "values": {"c++23": 202202},
1040            "headers": ["ranges"],
1041            "unimplemented": True,
1042        },
1043        {
1044            "name": "__cpp_lib_ranges_chunk_by",
1045            "values": {"c++23": 202202},
1046            "headers": ["ranges"],
1047        },
1048        {
1049            "name": "__cpp_lib_ranges_concat",
1050            "values": {"c++26": 202403}, # P2542R8: views::concat
1051            "headers": ["ranges"],
1052            "unimplemented": True,
1053        },
1054        {
1055            "name": "__cpp_lib_ranges_contains",
1056            "values": {"c++23": 202207},
1057            "headers": ["algorithm"],
1058        },
1059        {
1060            "name": "__cpp_lib_ranges_find_last",
1061            "values": {"c++23": 202207},
1062            "headers": ["algorithm"],
1063        },
1064        {
1065            "name": "__cpp_lib_ranges_iota",
1066            "values": {"c++23": 202202},
1067            "headers": ["numeric"],
1068            "unimplemented": True,
1069        },
1070        {
1071            "name": "__cpp_lib_ranges_join_with",
1072            "values": {"c++23": 202202},
1073            "headers": ["ranges"],
1074            "unimplemented": True,
1075        },
1076        {
1077            "name": "__cpp_lib_ranges_repeat",
1078            "values": {"c++23": 202207},
1079            "headers": ["ranges"],
1080        },
1081        {
1082            "name": "__cpp_lib_ranges_slide",
1083            "values": {"c++23": 202202},
1084            "headers": ["ranges"],
1085            "unimplemented": True,
1086        },
1087        {
1088            "name": "__cpp_lib_ranges_starts_ends_with",
1089            "values": {"c++23": 202106},
1090            "headers": ["algorithm"],
1091        },
1092        {
1093            "name": "__cpp_lib_ranges_to_container",
1094            "values": {"c++23": 202202},
1095            "headers": ["ranges"],
1096        },
1097        {
1098            "name": "__cpp_lib_ranges_zip",
1099            "values": {"c++23": 202110},
1100            "headers": ["ranges", "tuple", "utility"],
1101            "unimplemented": True,
1102        },
1103        {
1104            "name": "__cpp_lib_ratio",
1105            "values": {"c++26": 202306},  # P2734R0 Adding the new SI prefixes
1106            "headers": ["ratio"],
1107        },
1108        {
1109            "name": "__cpp_lib_raw_memory_algorithms",
1110            "values": {"c++17": 201606},
1111            "headers": ["memory"],
1112        },
1113        {
1114            "name": "__cpp_lib_rcu",
1115            "values": {"c++26": 202306},  # P2545R4 Read-Copy Update (RCU)
1116            "headers": [
1117                "rcu"  # TODO verify this entry since the paper was underspecified.
1118            ],
1119            "unimplemented": True,
1120        },
1121        {
1122            "name": "__cpp_lib_reference_from_temporary",
1123            "values": {"c++23": 202202},
1124            "headers": ["type_traits"],
1125            "unimplemented": True,
1126        },
1127        {
1128            "name": "__cpp_lib_reference_wrapper",
1129            "values": {"c++26": 202403}, # P2944R3: Comparisons for reference_wrapper
1130            "headers": ["functional"],
1131        },
1132        {
1133            "name": "__cpp_lib_remove_cvref",
1134            "values": {"c++20": 201711},
1135            "headers": ["type_traits"],
1136        },
1137        {
1138            "name": "__cpp_lib_result_of_sfinae",
1139            "values": {"c++14": 201210},
1140            "headers": ["functional", "type_traits"],
1141        },
1142        {
1143            "name": "__cpp_lib_robust_nonmodifying_seq_ops",
1144            "values": {"c++14": 201304},
1145            "headers": ["algorithm"],
1146        },
1147        {
1148            "name": "__cpp_lib_sample",
1149            "values": {"c++17": 201603},
1150            "headers": ["algorithm"],
1151        },
1152        {
1153            "name": "__cpp_lib_saturation_arithmetic",
1154            "values": {"c++26": 202311},  # P0543R3 Saturation arithmetic
1155            "headers": ["numeric"],
1156        },
1157        {
1158            "name": "__cpp_lib_scoped_lock",
1159            "values": {"c++17": 201703},
1160            "headers": ["mutex"],
1161            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS",
1162            "libcxx_guard": "_LIBCPP_HAS_THREADS",
1163        },
1164        {
1165            "name": "__cpp_lib_semaphore",
1166            "values": {"c++20": 201907},
1167            "headers": ["semaphore"],
1168            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
1169            "libcxx_guard": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
1170        },
1171        {
1172            "name": "__cpp_lib_senders",
1173            "values": {"c++26": 202406},  # P2300R10 std::execution
1174            "headers": ["execution"],
1175            "unimplemented": True,
1176        },
1177        {
1178            "name": "__cpp_lib_shared_mutex",
1179            "values": {"c++17": 201505},
1180            "headers": ["shared_mutex"],
1181            "test_suite_guard": "_LIBCPP_HAS_THREADS",
1182            "libcxx_guard": "_LIBCPP_HAS_THREADS",
1183        },
1184        {
1185            "name": "__cpp_lib_shared_ptr_arrays",
1186            "values": {"c++17": 201611, "c++20": 201707},
1187            "headers": ["memory"],
1188        },
1189        {
1190            "name": "__cpp_lib_shared_ptr_weak_type",
1191            "values": {"c++17": 201606},
1192            "headers": ["memory"],
1193        },
1194        {
1195            "name": "__cpp_lib_shared_timed_mutex",
1196            "values": {"c++14": 201402},
1197            "headers": ["shared_mutex"],
1198            "test_suite_guard": "_LIBCPP_HAS_THREADS",
1199            "libcxx_guard": "_LIBCPP_HAS_THREADS",
1200        },
1201        {
1202            "name": "__cpp_lib_shift",
1203            "values": {"c++20": 201806},
1204            "headers": ["algorithm"],
1205        },
1206        {
1207            "name": "__cpp_lib_smart_ptr_for_overwrite",
1208            "values": {"c++20": 202002},
1209            "headers": ["memory"],
1210        },
1211        {
1212            "name": "__cpp_lib_smart_ptr_owner_equality",
1213            "values": {
1214                "c++26": 202306  # P1901R2 Enabling the Use of weak_ptr as Keys in Unordered Associative Containers
1215            },
1216            "headers": ["memory"],
1217            "unimplemented": True,
1218        },
1219        {
1220            "name": "__cpp_lib_source_location",
1221            "values": {"c++20": 201907},
1222            "headers": ["source_location"],
1223        },
1224        {
1225            "name": "__cpp_lib_span",
1226            "values": {
1227                "c++20": 202002,
1228                # "c++26": 202311,  # P2821R5 span.at()
1229                #          202311   # P2833R2 Freestanding Library: inout expected span
1230            },
1231            "headers": ["span"],
1232        },
1233        {
1234            "name": "__cpp_lib_span_at",
1235            "values": {"c++26": 202311},  # P2821R3 span.at()
1236            "headers": ["span"],
1237        },
1238        {
1239            "name": "__cpp_lib_span_initializer_list",
1240            "values": {"c++26": 202311},  # P2447R6 std::span over an initializer list
1241            "headers": ["span"],
1242        },
1243        {
1244            "name": "__cpp_lib_spanstream",
1245            "values": {"c++23": 202106},
1246            "headers": ["spanstream"],
1247            "unimplemented": True,
1248        },
1249        {
1250            "name": "__cpp_lib_ssize",
1251            "values": {"c++20": 201902},
1252            "headers": ["iterator"],
1253        },
1254        {
1255            "name": "__cpp_lib_sstream_from_string_view",
1256            "values": {
1257                "c++26": 202306  # P2495R3 Interfacing stringstreams with string_view
1258            },
1259            "headers": ["sstream"],
1260        },
1261        {
1262            "name": "__cpp_lib_stacktrace",
1263            "values": {"c++23": 202011},
1264            "headers": ["stacktrace"],
1265            "unimplemented": True,
1266        },
1267        {
1268            "name": "__cpp_lib_starts_ends_with",
1269            "values": {"c++20": 201711},
1270            "headers": ["string", "string_view"],
1271        },
1272        {
1273            "name": "__cpp_lib_stdatomic_h",
1274            "values": {"c++23": 202011},
1275            "headers": ["stdatomic.h"],
1276        },
1277        {
1278            "name": "__cpp_lib_string_contains",
1279            "values": {"c++23": 202011},
1280            "headers": ["string", "string_view"],
1281        },
1282        {
1283            "name": "__cpp_lib_string_resize_and_overwrite",
1284            "values": {"c++23": 202110},
1285            "headers": ["string"],
1286        },
1287        {
1288            "name": "__cpp_lib_string_udls",
1289            "values": {"c++14": 201304},
1290            "headers": ["string"],
1291        },
1292        {
1293            "name": "__cpp_lib_string_view",
1294            "values": {
1295                "c++17": 201606,
1296                "c++20": 201803,
1297                "c++26": 202403,  # P2591R5: Concatenation of strings and string views
1298            },
1299            "headers": ["string", "string_view"],
1300        },
1301        {
1302            "name": "__cpp_lib_submdspan",
1303            "values": {
1304                "c++26": 202306, # P2630R4: submdspan
1305                # "c++26": 202403, # P2642R6: Padded mdspan layouts
1306            },
1307            "headers": ["mdspan"],
1308            "unimplemented": True,
1309        },
1310        {
1311            "name": "__cpp_lib_syncbuf",
1312            "values": {"c++20": 201803},
1313            "headers": ["syncstream"],
1314            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM",
1315            "libcxx_guard": "_LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM",
1316        },
1317        {
1318            "name": "__cpp_lib_text_encoding",
1319            "values": {
1320                "c++26": 202306  # P1885R12 Naming Text Encodings to Demystify Them
1321            },
1322            "headers": ["text_encoding"],
1323            "unimplemented": True,
1324        },
1325        {
1326            "name": "__cpp_lib_three_way_comparison",
1327            "values": {"c++20": 201907},
1328            "headers": ["compare"],
1329        },
1330        {
1331            "name": "__cpp_lib_to_address",
1332            "values": {"c++20": 201711},
1333            "headers": ["memory"],
1334        },
1335        {
1336            "name": "__cpp_lib_to_array",
1337            "values": {"c++20": 201907},
1338            "headers": ["array"],
1339        },
1340        {
1341            "name": "__cpp_lib_to_chars",
1342            "values": {
1343                "c++17": 201611,
1344                "c++26": 202306,  # P2497R0 Testing for success or failure of <charconv> functions
1345            },
1346            "headers": ["charconv"],
1347            "unimplemented": True,
1348        },
1349        {
1350            "name": "__cpp_lib_to_string",
1351            "values": {"c++26": 202306},  # P2587R3 to_string or not to_string
1352            "headers": ["string"],
1353            "unimplemented": True,
1354        },
1355        {
1356            "name": "__cpp_lib_to_underlying",
1357            "values": {"c++23": 202102},
1358            "headers": ["utility"],
1359        },
1360        {
1361            "name": "__cpp_lib_transformation_trait_aliases",
1362            "values": {"c++14": 201304},
1363            "headers": ["type_traits"],
1364        },
1365        {
1366            "name": "__cpp_lib_transparent_operators",
1367            "values": {"c++14": 201210, "c++17": 201510},
1368            "headers": ["functional", "memory"],
1369        },
1370        {
1371            "name": "__cpp_lib_tuple_element_t",
1372            "values": {"c++14": 201402},
1373            "headers": ["tuple"],
1374        },
1375        {
1376            "name": "__cpp_lib_tuple_like",
1377            "values": {
1378                "c++23": 202207,  # P2165R4 Compatibility between tuple, pair and tuple-like objects
1379                "c++26": 202311,  # P2819R2 Add tuple protocol to complex (implemented)
1380            },
1381            "headers": ["map", "tuple", "unordered_map", "utility"],
1382            "unimplemented": True,
1383        },
1384        {
1385            "name": "__cpp_lib_tuples_by_type",
1386            "values": {"c++14": 201304},
1387            "headers": ["tuple", "utility"],
1388        },
1389        {
1390            "name": "__cpp_lib_type_identity",
1391            "values": {"c++20": 201806},
1392            "headers": ["type_traits"],
1393        },
1394        {
1395            "name": "__cpp_lib_type_trait_variable_templates",
1396            "values": {"c++17": 201510},
1397            "headers": ["type_traits"],
1398        },
1399        {
1400            "name": "__cpp_lib_uncaught_exceptions",
1401            "values": {"c++17": 201411},
1402            "headers": ["exception"],
1403        },
1404        {
1405            "name": "__cpp_lib_unordered_map_try_emplace",
1406            "values": {"c++17": 201411},
1407            "headers": ["unordered_map"],
1408        },
1409        {
1410            "name": "__cpp_lib_unreachable",
1411            "values": {"c++23": 202202},
1412            "headers": ["utility"],
1413        },
1414        {
1415            "name": "__cpp_lib_unwrap_ref",
1416            "values": {"c++20": 201811},
1417            "headers": ["functional"],
1418        },
1419        {
1420            "name": "__cpp_lib_variant",
1421            "values": {
1422                "c++17": 202102,  # std::visit for classes derived from std::variant
1423                "c++20": 202106,  # P2231R1 Missing constexpr in std::optional and std::variant
1424                "c++26": 202306,  # P2637R3 Member visit
1425            },
1426            "headers": ["variant"],
1427        },
1428        {
1429            "name": "__cpp_lib_void_t",
1430            "values": {"c++17": 201411},
1431            "headers": ["type_traits"],
1432        },
1433    ]
1434]
1435
1436assert feature_test_macros == sorted(feature_test_macros, key=lambda tc: tc["name"])
1437for tc in feature_test_macros:
1438    assert tc["headers"] == sorted(tc["headers"]), tc
1439    assert ("libcxx_guard" in tc) == ("test_suite_guard" in tc), tc
1440    valid_keys = ["name", "values", "headers", "libcxx_guard", "test_suite_guard", "unimplemented"]
1441    assert all(key in valid_keys for key in tc.keys()), tc
1442
1443# Map from each header to the Lit annotations that should be used for
1444# tests that include that header.
1445#
1446# For example, when threads are not supported, any test that includes
1447# <thread> should be marked as UNSUPPORTED, because including <thread>
1448# is a hard error in that case.
1449lit_markup = {
1450    "barrier": ["UNSUPPORTED: no-threads"],
1451    "filesystem": ["UNSUPPORTED: no-filesystem"],
1452    "fstream": ["UNSUPPORTED: no-localization"],
1453    "iomanip": ["UNSUPPORTED: no-localization"],
1454    "ios": ["UNSUPPORTED: no-localization"],
1455    "iostream": ["UNSUPPORTED: no-localization"],
1456    "istream": ["UNSUPPORTED: no-localization"],
1457    "latch": ["UNSUPPORTED: no-threads"],
1458    "locale": ["UNSUPPORTED: no-localization"],
1459    "mutex": ["UNSUPPORTED: no-threads"],
1460    "ostream": ["UNSUPPORTED: no-localization"],
1461    "print": ["UNSUPPORTED: no-filesystem"],
1462    "regex": ["UNSUPPORTED: no-localization"],
1463    "semaphore": ["UNSUPPORTED: no-threads"],
1464    "shared_mutex": ["UNSUPPORTED: no-threads"],
1465    "sstream": ["UNSUPPORTED: no-localization"],
1466    "syncstream": ["UNSUPPORTED: no-localization"],
1467    "stdatomic.h": ["UNSUPPORTED: no-threads"],
1468    "stop_token": ["UNSUPPORTED: no-threads"],
1469    "thread": ["UNSUPPORTED: no-threads"],
1470}
1471
1472
1473def get_std_dialects():
1474    std_dialects = ["c++14", "c++17", "c++20", "c++23", "c++26"]
1475    return list(std_dialects)
1476
1477
1478def get_first_std(d):
1479    for s in get_std_dialects():
1480        if s in d.keys():
1481            return s
1482    return None
1483
1484
1485def get_last_std(d):
1486    rev_dialects = get_std_dialects()
1487    rev_dialects.reverse()
1488    for s in rev_dialects:
1489        if s in d.keys():
1490            return s
1491    return None
1492
1493
1494def get_std_before(d, std):
1495    std_dialects = get_std_dialects()
1496    candidates = std_dialects[0 : std_dialects.index(std)]
1497    candidates.reverse()
1498    for cand in candidates:
1499        if cand in d.keys():
1500            return cand
1501    return None
1502
1503
1504def get_value_before(d, std):
1505    new_std = get_std_before(d, std)
1506    if new_std is None:
1507        return None
1508    return d[new_std]
1509
1510
1511def get_for_std(d, std):
1512    # This catches the C++11 case for which there should be no defined feature
1513    # test macros.
1514    std_dialects = get_std_dialects()
1515    if std not in std_dialects:
1516        return None
1517    # Find the value for the newest C++ dialect between C++14 and std
1518    std_list = list(std_dialects[0 : std_dialects.index(std) + 1])
1519    std_list.reverse()
1520    for s in std_list:
1521        if s in d.keys():
1522            return d[s]
1523    return None
1524
1525
1526def get_std_number(std):
1527    return std.replace("c++", "")
1528
1529
1530"""
1531  Functions to produce the <version> header
1532"""
1533
1534
1535def produce_macros_definition_for_std(std):
1536    result = ""
1537    indent = 55
1538    for tc in feature_test_macros:
1539        if std not in tc["values"]:
1540            continue
1541        inner_indent = 1
1542        if "test_suite_guard" in tc.keys():
1543            result += "# if %s\n" % tc["libcxx_guard"]
1544            inner_indent += 2
1545        if get_value_before(tc["values"], std) is not None:
1546            assert "test_suite_guard" not in tc.keys()
1547            result += "# undef  %s\n" % tc["name"]
1548        line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])
1549        line += " " * (indent - len(line))
1550        line += " %sL" % tc["values"][std]
1551        if "unimplemented" in tc.keys():
1552            line = "// " + line
1553        result += line
1554        result += "\n"
1555        if "test_suite_guard" in tc.keys():
1556            result += "# endif\n"
1557    return result.strip()
1558
1559
1560def produce_macros_definitions():
1561    macro_definition_template = """#if _LIBCPP_STD_VER >= {std_number}
1562{macro_definition}
1563#endif"""
1564
1565    macros_definitions = []
1566    for std in get_std_dialects():
1567        macros_definitions.append(
1568            macro_definition_template.format(
1569                std_number=get_std_number(std),
1570                macro_definition=produce_macros_definition_for_std(std),
1571            )
1572        )
1573
1574    return "\n\n".join(macros_definitions)
1575
1576
1577def chunks(l, n):
1578    """Yield successive n-sized chunks from l."""
1579    for i in range(0, len(l), n):
1580        yield l[i : i + n]
1581
1582
1583def produce_version_synopsis():
1584    indent = 56
1585    header_indent = 56 + len("20XXYYL ")
1586    result = ""
1587
1588    def indent_to(s, val):
1589        if len(s) >= val:
1590            return s
1591        s += " " * (val - len(s))
1592        return s
1593
1594    line = indent_to("Macro name", indent) + "Value"
1595    line = indent_to(line, header_indent) + "Headers"
1596    result += line + "\n"
1597    for tc in feature_test_macros:
1598        prev_defined_std = get_last_std(tc["values"])
1599        line = "{name: <{indent}}{value}L ".format(
1600            name=tc["name"], indent=indent, value=tc["values"][prev_defined_std]
1601        )
1602        headers = list(tc["headers"])
1603        headers.remove("version")
1604        for chunk in chunks(headers, 3):
1605            line = indent_to(line, header_indent)
1606            chunk = ["<%s>" % header for header in chunk]
1607            line += " ".join(chunk)
1608            result += line
1609            result += "\n"
1610            line = ""
1611        while True:
1612            prev_defined_std = get_std_before(tc["values"], prev_defined_std)
1613            if prev_defined_std is None:
1614                break
1615            result += "%s%sL // %s\n" % (
1616                indent_to("", indent),
1617                tc["values"][prev_defined_std],
1618                prev_defined_std.replace("c++", "C++"),
1619            )
1620    return result
1621
1622
1623def produce_version_header():
1624    template = """// -*- C++ -*-
1625//===----------------------------------------------------------------------===//
1626//
1627// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1628// See https://llvm.org/LICENSE.txt for license information.
1629// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1630//
1631//===----------------------------------------------------------------------===//
1632
1633#ifndef _LIBCPP_VERSIONH
1634#define _LIBCPP_VERSIONH
1635
1636/*
1637  version synopsis
1638
1639{synopsis}
1640
1641*/
1642
1643#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
1644#  include <__cxx03/version>
1645#else
1646#  include <__config>
1647
1648#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1649#    pragma GCC system_header
1650#  endif
1651
1652// clang-format off
1653
1654{cxx_macros}
1655
1656#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
1657
1658// clang-format on
1659
1660#endif // _LIBCPP_VERSIONH
1661"""
1662
1663    version_str = template.format(
1664        synopsis=produce_version_synopsis().strip(),
1665        cxx_macros=produce_macros_definitions(),
1666    )
1667    version_header_path = os.path.join(include_path, "version")
1668    with open(version_header_path, "w", newline="\n") as f:
1669        f.write(version_str)
1670
1671
1672"""
1673    Functions to produce test files
1674"""
1675
1676test_types = {
1677    "undefined": """
1678# ifdef {name}
1679#   error "{name} should not be defined before {std_first}"
1680# endif
1681""",
1682    "test_suite_guard": """
1683# if {test_suite_guard}
1684#   ifndef {name}
1685#     error "{name} should be defined in {std}"
1686#   endif
1687#   if {name} != {value}
1688#     error "{name} should have the value {value} in {std}"
1689#   endif
1690# else
1691#   ifdef {name}
1692#     error "{name} should not be defined when the requirement '{test_suite_guard}' is not met!"
1693#   endif
1694# endif
1695""",
1696    "unimplemented": """
1697# if !defined(_LIBCPP_VERSION)
1698#   ifndef {name}
1699#     error "{name} should be defined in {std}"
1700#   endif
1701#   if {name} != {value}
1702#     error "{name} should have the value {value} in {std}"
1703#   endif
1704# else // _LIBCPP_VERSION
1705#   ifdef {name}
1706#     error "{name} should not be defined because it is unimplemented in libc++!"
1707#   endif
1708# endif
1709""",
1710    "defined": """
1711# ifndef {name}
1712#   error "{name} should be defined in {std}"
1713# endif
1714# if {name} != {value}
1715#   error "{name} should have the value {value} in {std}"
1716# endif
1717""",
1718}
1719
1720
1721def generate_std_test(test_list, std):
1722    result = ""
1723    for tc in test_list:
1724        val = get_for_std(tc["values"], std)
1725        if val is not None:
1726            val = "%sL" % val
1727        if val is None:
1728            result += test_types["undefined"].format(
1729                name=tc["name"], std_first=get_first_std(tc["values"])
1730            )
1731        elif "unimplemented" in tc.keys():
1732            result += test_types["unimplemented"].format(
1733                name=tc["name"], value=val, std=std
1734            )
1735        elif "test_suite_guard" in tc.keys():
1736            result += test_types["test_suite_guard"].format(
1737                name=tc["name"],
1738                value=val,
1739                std=std,
1740                test_suite_guard=tc["test_suite_guard"],
1741            )
1742        else:
1743            result += test_types["defined"].format(name=tc["name"], value=val, std=std)
1744    return result.strip()
1745
1746
1747def generate_std_tests(test_list):
1748    std_tests_template = """#if TEST_STD_VER < {first_std_number}
1749
1750{pre_std_test}
1751
1752{other_std_tests}
1753
1754#elif TEST_STD_VER > {penultimate_std_number}
1755
1756{last_std_test}
1757
1758#endif // TEST_STD_VER > {penultimate_std_number}"""
1759
1760    std_dialects = get_std_dialects()
1761
1762    other_std_tests = []
1763    for std in std_dialects[:-1]:
1764        other_std_tests.append("#elif TEST_STD_VER == " + get_std_number(std))
1765        other_std_tests.append(generate_std_test(test_list, std))
1766
1767    std_tests = std_tests_template.format(
1768        first_std_number=get_std_number(std_dialects[0]),
1769        pre_std_test=generate_std_test(test_list, "c++11"),
1770        other_std_tests="\n\n".join(other_std_tests),
1771        penultimate_std_number=get_std_number(std_dialects[-2]),
1772        last_std_test=generate_std_test(test_list, std_dialects[-1]),
1773    )
1774
1775    return std_tests
1776
1777
1778def generate_synopsis(test_list):
1779    max_name_len = max([len(tc["name"]) for tc in test_list])
1780    indent = max_name_len + 8
1781
1782    def mk_line(prefix, suffix):
1783        return "{prefix: <{max_len}}{suffix}\n".format(
1784            prefix=prefix, suffix=suffix, max_len=indent
1785        )
1786
1787    result = ""
1788    result += mk_line("/*  Constant", "Value")
1789    for tc in test_list:
1790        prefix = "    %s" % tc["name"]
1791        for std in [s for s in get_std_dialects() if s in tc["values"].keys()]:
1792            result += mk_line(
1793                prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++"))
1794            )
1795            prefix = ""
1796    result += "*/"
1797    return result
1798
1799
1800def produce_tests():
1801    headers = set([h for tc in feature_test_macros for h in tc["headers"]])
1802    for h in headers:
1803        test_list = [tc for tc in feature_test_macros if h in tc["headers"]]
1804        if not has_header(h):
1805            for tc in test_list:
1806                assert "unimplemented" in tc.keys()
1807            continue
1808        markup = "\n".join("// " + tag for tag in lit_markup.get(h, []))
1809        test_body = """//===----------------------------------------------------------------------===//
1810//
1811// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1812// See https://llvm.org/LICENSE.txt for license information.
1813// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1814//
1815//===----------------------------------------------------------------------===//
1816//
1817// WARNING: This test was generated by {script_name}
1818// and should not be edited manually.
1819//
1820// clang-format off
1821{markup}
1822// <{header}>
1823
1824// Test the feature test macros defined by <{header}>
1825
1826{synopsis}
1827
1828#include <{header}>
1829#include "test_macros.h"
1830
1831{cxx_tests}
1832
1833""".format(
1834            script_name=script_name,
1835            header=h,
1836            markup=("\n{}\n".format(markup) if markup else ""),
1837            synopsis=generate_synopsis(test_list),
1838            cxx_tests=generate_std_tests(test_list),
1839        )
1840        test_name = "{header}.version.compile.pass.cpp".format(header=h)
1841        out_path = os.path.join(macro_test_path, test_name)
1842        with open(out_path, "w", newline="\n") as f:
1843            f.write(test_body)
1844
1845
1846"""
1847    Produce documentation for the feature test macros
1848"""
1849
1850
1851def make_widths(grid):
1852    widths = []
1853    for i in range(0, len(grid[0])):
1854        cell_width = 2 + max(
1855            reduce(lambda x, y: x + y, [[len(row[i])] for row in grid], [])
1856        )
1857        widths += [cell_width]
1858    return widths
1859
1860
1861def create_table(grid, indent):
1862    indent_str = " " * indent
1863    col_widths = make_widths(grid)
1864    result = [indent_str + add_divider(col_widths, 2)]
1865    header_flag = 2
1866    for row_i in range(0, len(grid)):
1867        row = grid[row_i]
1868        line = indent_str + " ".join(
1869            [pad_cell(row[i], col_widths[i]) for i in range(0, len(row))]
1870        )
1871        result.append(line.rstrip())
1872        if row_i == len(grid) - 1:
1873            header_flag = 2
1874        if row[0].startswith("**"):
1875            header_flag += 1
1876        separator = indent_str + add_divider(col_widths, header_flag)
1877        result.append(separator.rstrip())
1878        header_flag = 0
1879    return "\n".join(result)
1880
1881
1882def add_divider(widths, header_flag):
1883    if header_flag == 3:
1884        return "=".join(["=" * w for w in widths])
1885    if header_flag == 2:
1886        return " ".join(["=" * w for w in widths])
1887    if header_flag == 1:
1888        return "-".join(["-" * w for w in widths])
1889    else:
1890        return " ".join(["-" * w for w in widths])
1891
1892
1893def pad_cell(s, length, left_align=True):
1894    padding = (length - len(s)) * " "
1895    return s + padding
1896
1897
1898def get_status_table():
1899    table = [["Macro Name", "Value"]]
1900    for std in get_std_dialects():
1901        table += [["**" + std.replace("c++", "C++") + "**", ""]]
1902        for tc in feature_test_macros:
1903            if std not in tc["values"].keys():
1904                continue
1905            value = "``%sL``" % tc["values"][std]
1906            if "unimplemented" in tc.keys():
1907                value = "*unimplemented*"
1908            table += [["``%s``" % tc["name"], value]]
1909    return table
1910
1911
1912def produce_docs():
1913    doc_str = """.. _FeatureTestMacroTable:
1914
1915==========================
1916Feature Test Macro Support
1917==========================
1918
1919.. contents::
1920   :local:
1921
1922Overview
1923========
1924
1925This file documents the feature test macros currently supported by libc++.
1926
1927.. _feature-status:
1928
1929Status
1930======
1931
1932.. table:: Current Status
1933    :name: feature-status-table
1934    :widths: auto
1935
1936{status_tables}
1937
1938""".format(
1939        status_tables=create_table(get_status_table(), 4)
1940    )
1941
1942    table_doc_path = os.path.join(docs_path, "FeatureTestMacroTable.rst")
1943    with open(table_doc_path, "w", newline="\n") as f:
1944        f.write(doc_str)
1945
1946
1947def get_ftms(
1948    data, std_dialects: List[str], use_implemented_status: bool
1949) -> Dict[str, Dict[str, Any]]:
1950    """Impementation for FeatureTestMacros.(standard|implemented)_ftms()."""
1951    result = dict()
1952    for feature in data:
1953        last = None
1954        entry = dict()
1955        implemented = True
1956        for std in std_dialects:
1957            if std not in feature["values"].keys():
1958                if last == None:
1959                    continue
1960                else:
1961                    entry[std] = last
1962            else:
1963                if implemented:
1964                    values = feature["values"][std]
1965                    assert len(values) > 0, f"{feature['name']}[{std}] has no entries"
1966                    for value in values:
1967                        papers = list(values[value])
1968                        assert (
1969                            len(papers) > 0
1970                        ), f"{feature['name']}[{std}][{value}] has no entries"
1971                        for paper in papers:
1972                            if use_implemented_status and not paper["implemented"]:
1973                                implemented = False
1974                                break
1975                        if implemented:
1976                            last = f"{value}L"
1977                        else:
1978                            break
1979
1980                entry[std] = last
1981        result[feature["name"]] = entry
1982
1983    return result
1984
1985
1986def generate_version_header_dialect_block(data: Dict[str, Any]) -> str:
1987    """Generates the contents of the version header for a dialect.
1988
1989    This generates the contents of a
1990      #if  _LIBCPP_STD_VER >= XY
1991      #endif // _LIBCPP_STD_VER >= XY
1992    block.
1993    """
1994    result = ""
1995    for element in data:
1996        for ftm, entry in element.items():
1997            if not entry["implemented"]:
1998                # When a FTM is not implemented don't add the guards
1999                # or undefine the (possibly) defined macro.
2000                result += f'// define {ftm} {entry["value"]}\n'
2001            else:
2002                need_undef = entry["need_undef"]
2003                if entry["condition"]:
2004                    result += f'#  if {entry["condition"]}\n'
2005                    if entry["need_undef"]:
2006                        result += f"#    undef {ftm}\n"
2007                    result += f'#    define {ftm} {entry["value"]}\n'
2008                    result += f"#  endif\n"
2009                else:
2010                    if entry["need_undef"]:
2011                        result += f"#  undef {ftm}\n"
2012                    result += f'#  define {ftm} {entry["value"]}\n'
2013
2014    return result
2015
2016
2017def generate_version_header_implementation(data: Dict[str, Dict[str, Any]]) -> str:
2018    """Generates the body of the version header."""
2019
2020    template = """#if _LIBCPP_STD_VER >= {dialect}
2021{feature_test_macros}#endif // _LIBCPP_STD_VER >= {dialect}"""
2022
2023    result = []
2024    for std, ftms in data.items():
2025        result.append(
2026            template.format(
2027                dialect=std,
2028                feature_test_macros=generate_version_header_dialect_block(ftms),
2029            )
2030        )
2031
2032    return "\n\n".join(result)
2033
2034
2035class FeatureTestMacros:
2036    """Provides all feature-test macro (FTM) output components.
2037
2038    The class has several generators to use the feature-test macros in libc++:
2039    - FTM status page
2040    - The version header and its tests
2041
2042    This class is not intended to duplicate
2043    https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros
2044    SD-FeatureTest: Feature-Test Macros and Policies
2045
2046    Historically libc++ did not list all papers affecting a FTM, the new data
2047    structure is able to do that. However there is no intention to add the
2048    historical data. After papers have been implemented this information can be
2049    removed. For example, __cpp_lib_format's value 201907 requires 3 papers,
2050    once implemented it can be reduced to 1 paper and remove the paper number
2051    and title. This would reduce the size of the data.
2052
2053    The input data is stored in the following JSON format:
2054    [ # A list with multiple feature-test macro entries.
2055      {
2056        # required
2057        # The name of the feature test macro. These names should be unique and
2058        # sorted in the list.
2059        "name": "__cpp_lib_any",
2060
2061        # required
2062        # A map with the value of the FTM based on the language standard. Only
2063        # the versions in which the value of the FTM changes are listed. For
2064        # example, this macro's value does not change in C++20 so it does not
2065        # list C++20. If it changes in C++26, it will have entries for C++17 and
2066        # C++26.
2067        "values": {
2068
2069          # required
2070          # The language standard, also named dialect in this class.
2071          "c++17": {
2072
2073            # required
2074            # The value of the feature test macro. This contains an array with
2075            # one or more papers that need to be implemented before this value
2076            # is considered implemented.
2077            "201606": [
2078              {
2079                # optional
2080                # Contains the paper number that is part of the FTM version.
2081                "number": "P0220R1",
2082
2083                # optional
2084                # Contains the title of the paper that is part of the FTM
2085                # version.
2086                "title": "Adopt Library Fundamentals V1 TS Components for C++17"
2087
2088                # required
2089                # The implementation status of the paper.
2090                "implemented": true
2091              }
2092            ]
2093          }
2094        },
2095
2096        # required
2097        # A sorted list of headers that should provide the FTM. The header
2098        # <version> is automatically added to this list. This list could be
2099        # empty. For example, __cpp_lib_modules is only present in version.
2100        # Requiring the field makes it easier to detect accidental omission.
2101        "headers": [
2102          "any"
2103        ],
2104
2105        # optional, required when libcxx_guard is present
2106        # This field is used only to generate the unit tests for the
2107        # feature-test macros. It can't depend on macros defined in <__config>
2108        # because the `test/std/` parts of the test suite are intended to be
2109        # portable to any C++ standard library implementation, not just libc++.
2110        # It may depend on
2111        # * macros defined by the compiler itself, or
2112        # * macros generated by CMake.
2113        # In some cases we add also depend on macros defined in
2114        # <__availability>.
2115        "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR"
2116
2117        # optional, required when test_suite_guard is present
2118        # This field is used only to guard the feature-test macro in
2119        # <version>. It may be the same as `test_suite_guard`, or it may
2120        # depend on macros defined in <__config>.
2121        "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR"
2122      },
2123    ]
2124    """
2125
2126    # The JSON data structure.
2127    __data = None
2128
2129    def __init__(self, filename: str):
2130        """Initializes the class with the JSON data in the file 'filename'."""
2131        with open(filename) as f:
2132            self.__data = json.load(f)
2133
2134    @functools.cached_property
2135    def std_dialects(self) -> List[str]:
2136        """Returns the C++ dialects avaiable.
2137
2138        The available dialects are based on the 'c++xy' keys found the 'values'
2139        entries in '__data'. So when WG21 starts to feature-test macros for a
2140        future C++ Standard this dialect will automatically be available.
2141
2142        The return value is a sorted list with the C++ dialects used. Since FTM
2143        were added in C++14 the list will not contain C++03 or C++11.
2144        """
2145        dialects = set()
2146        for feature in self.__data:
2147            keys = feature["values"].keys()
2148            assert len(keys) > 0, "'values' is empty"
2149            dialects |= keys
2150
2151        return sorted(list(dialects))
2152
2153    @functools.cached_property
2154    def standard_ftms(self) -> Dict[str, Dict[str, Any]]:
2155        """Returns the FTM versions per dialect in the Standard.
2156
2157        This function does not use the 'implemented' flag. The output contains
2158        the versions used in the Standard. When a FTM in libc++ is not
2159        implemented according to the Standard to output may opt to show the
2160        expected value.
2161
2162        The result is a dict with the following content
2163        - key: Name of the feature test macro.
2164        - value: A dict with the following content:
2165          * key: The version of the C++ dialect.
2166          * value: The value of the feature-test macro.
2167        """
2168        return get_ftms(self.__data, self.std_dialects, False)
2169
2170    @functools.cached_property
2171    def implemented_ftms(self) -> Dict[str, Dict[str, Any]]:
2172        """Returns the FTM versions per dialect implemented in libc++.
2173
2174        Unlike `get_std_dialect_versions` this function uses the 'implemented'
2175        flag. This returns the actual implementation status in libc++.
2176
2177        The result is a dict with the following content
2178        - key: Name of the feature test macro.
2179        - value: A dict with the following content:
2180          * key: The version of the C++ dialect.
2181          * value: The value of the feature-test macro. When a feature-test
2182            macro is not implemented its value is None.
2183        """
2184
2185        return get_ftms(self.__data, self.std_dialects, True)
2186
2187    @functools.cached_property
2188    def ftm_metadata(self) -> Dict[str, Dict[str, Any]]:
2189        """Returns the metadata of the FTMs defined in the Standard.
2190
2191        The metadata does not depend on the C++ dialect used.
2192        The result is a dict with the following contents:
2193        - key: Name of the feature test macro.
2194        - value: A dict with the following content:
2195          * headers: The list of headers that should provide the FTM
2196          * test_suite_guard: The condition for testing the FTM in the test suite.
2197          * test_suite_guard: The condition for testing the FTM in the version header.
2198        """
2199        result = dict()
2200        for feature in self.__data:
2201            entry = dict()
2202            entry["headers"] = feature["headers"]
2203            entry["test_suite_guard"] = feature.get("test_suite_guard", None)
2204            entry["libcxx_guard"] = feature.get("libcxx_guard", None)
2205            result[feature["name"]] = entry
2206
2207        return result
2208
2209    @property
2210    def version_header_implementation(self) -> Dict[str, List[Dict[str, Any]]]:
2211        """Generates the body of the version header."""
2212        result = dict()
2213        for std in self.std_dialects:
2214            result[get_std_number(std)] = list()
2215
2216        for ftm, values in self.standard_ftms.items():
2217            last_value = None
2218            last_entry = None
2219            for std, value in values.items():
2220                # When a newer Standard does not change the value of the macro
2221                # there is no need to redefine it with the same value.
2222                if last_value and value == last_value:
2223                    continue
2224                last_value = value
2225
2226                entry = dict()
2227                entry["value"] = value
2228                entry["implemented"] = self.implemented_ftms[ftm][std] == self.standard_ftms[ftm][std]
2229                entry["need_undef"] = last_entry is not None and last_entry["implemented"] and entry["implemented"]
2230                entry["condition"] = self.ftm_metadata[ftm]["libcxx_guard"]
2231
2232                last_entry = entry
2233                result[get_std_number(std)].append(dict({ftm: entry}))
2234
2235        return result
2236
2237    @property
2238    def version_header(self) -> str:
2239        """Generates the version header."""
2240        template = """// -*- C++ -*-
2241//===----------------------------------------------------------------------===//
2242//
2243// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2244// See https://llvm.org/LICENSE.txt for license information.
2245// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2246//
2247//===----------------------------------------------------------------------===//
2248
2249#ifndef _LIBCPP_VERSIONH
2250#define _LIBCPP_VERSIONH
2251
2252#include <__config>
2253
2254#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2255#  pragma GCC system_header
2256#endif
2257
2258{feature_test_macros}
2259
2260#endif // _LIBCPP_VERSIONH
2261"""
2262        return template.format(
2263            feature_test_macros=generate_version_header_implementation(
2264                self.version_header_implementation
2265            )
2266        )
2267
2268
2269def main():
2270    produce_version_header()
2271    produce_tests()
2272    produce_docs()
2273
2274    # Example how to use the new version header generation function to generate
2275    # the file.
2276    if False:
2277        ftm = FeatureTestMacros(
2278            os.path.join(
2279                source_root, "test", "libcxx", "feature_test_macro", "test_data.json"
2280            )
2281        )
2282        version_header_path = os.path.join(include_path, "version")
2283        with open(version_header_path, "w", newline="\n") as f:
2284            f.write(ftm.version_header)
2285
2286
2287if __name__ == "__main__":
2288    main()
2289