Bump version to 19.1.0 (final)
[llvm-project.git] / libcxx / utils / generate_feature_test_macro_components.py
blob6c42748002aee3b0c4b18d7e1ececfbe5c42919e
1 #!/usr/bin/env python
3 import os
4 from builtins import range
5 from functools import reduce
6 from typing import Any, Dict, List # Needed for python 3.8 compatibility.
7 import functools
8 import json
11 def 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",
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")
32 return script_name, src_root, include_path, docs_path, macro_test_path
35 script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths()
38 def has_header(h):
39 h_path = os.path.join(include_path, h)
40 return os.path.exists(h_path)
43 def add_version_header(tc):
44 tc["headers"].append("version")
45 return tc
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 # ================ ============================================================
79 feature_test_macros = [
80 add_version_header(x)
81 for x in [
83 "name": "__cpp_lib_adaptor_iterator_pair_constructor",
84 "values": {"c++23": 202106},
85 "headers": ["queue", "stack"],
88 "name": "__cpp_lib_addressof_constexpr",
89 "values": {"c++17": 201603},
90 "headers": ["memory"],
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
98 "headers": ["memory"],
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",
118 "name": "__cpp_lib_any",
119 "values": {"c++17": 201606},
120 "headers": ["any"],
123 "name": "__cpp_lib_apply",
124 "values": {"c++17": 201603},
125 "headers": ["tuple"],
128 "name": "__cpp_lib_array_constexpr",
129 "values": {"c++17": 201603, "c++20": 201811},
130 "headers": ["array", "iterator"],
133 "name": "__cpp_lib_as_const",
134 "values": {"c++17": 201510},
135 "headers": ["utility"],
138 "name": "__cpp_lib_associative_heterogeneous_erasure",
139 "values": {"c++23": 202110},
140 "headers": ["map", "set", "unordered_map", "unordered_set"],
141 "unimplemented": True,
144 "name": "__cpp_lib_associative_heterogeneous_insertion",
145 "values": {
146 "c++26": 202306 # P2363R5 Extending associative containers with the remaining heterogeneous overloads
148 "headers": ["map", "set", "unordered_map", "unordered_set"],
149 "unimplemented": True,
152 "name": "__cpp_lib_assume_aligned",
153 "values": {"c++20": 201811},
154 "headers": ["memory"],
157 "name": "__cpp_lib_atomic_flag_test",
158 "values": {"c++20": 201907},
159 "headers": ["atomic"],
162 "name": "__cpp_lib_atomic_float",
163 "values": {"c++20": 201711},
164 "headers": ["atomic"],
165 "unimplemented": True,
168 "name": "__cpp_lib_atomic_is_always_lock_free",
169 "values": {"c++17": 201603},
170 "headers": ["atomic"],
173 "name": "__cpp_lib_atomic_lock_free_type_aliases",
174 "values": {"c++20": 201907},
175 "headers": ["atomic"],
178 "name": "__cpp_lib_atomic_min_max",
179 "values": {"c++26": 202403}, # P0493R5: Atomic minimum/maximum
180 "headers": ["atomic"],
181 "unimplemented": True,
184 "name": "__cpp_lib_atomic_ref",
185 "values": {"c++20": 201806},
186 "headers": ["atomic"],
189 "name": "__cpp_lib_atomic_shared_ptr",
190 "values": {"c++20": 201711},
191 "headers": ["atomic"],
192 "unimplemented": True,
195 "name": "__cpp_lib_atomic_value_initialization",
196 "values": {"c++20": 201911},
197 "headers": ["atomic", "memory"],
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",
207 "name": "__cpp_lib_barrier",
208 "values": {"c++20": 201907},
209 "headers": ["barrier"],
210 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
211 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
214 "name": "__cpp_lib_bind_back",
215 "values": {
216 "c++23": 202202,
217 # "c++26": 202306, # P2714R1 Bind front and back to NTTP callables
219 "headers": ["functional"],
222 "name": "__cpp_lib_bind_front",
223 "values": {
224 "c++20": 201907,
225 "c++26": 202306, # P2714R1 Bind front and back to NTTP callables
227 "headers": ["functional"],
230 "name": "__cpp_lib_bit_cast",
231 "values": {"c++20": 201806},
232 "headers": ["bit"],
235 "name": "__cpp_lib_bitops",
236 "values": {"c++20": 201907},
237 "headers": ["bit"],
240 "name": "__cpp_lib_bitset",
241 "values": {"c++26": 202306}, # P2697R1 Interfacing bitset with string_view
242 "headers": ["bitset"],
245 "name": "__cpp_lib_bool_constant",
246 "values": {"c++17": 201505},
247 "headers": ["type_traits"],
250 "name": "__cpp_lib_bounded_array_traits",
251 "values": {"c++20": 201902},
252 "headers": ["type_traits"],
255 "name": "__cpp_lib_boyer_moore_searcher",
256 "values": {"c++17": 201603},
257 "headers": ["functional"],
260 "name": "__cpp_lib_byte",
261 "values": {"c++17": 201603},
262 "headers": ["cstddef"],
265 "name": "__cpp_lib_byteswap",
266 "values": {"c++23": 202110},
267 "headers": ["bit"],
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",
282 "test_suite_guard": "defined(__cpp_char8_t)",
283 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CHAR8_T)",
286 "name": "__cpp_lib_chrono",
287 "values": {
288 "c++17": 201611,
289 # "c++26": 202306, # P2592R3 Hashing support for std::chrono value classes
291 "headers": ["chrono"],
294 "name": "__cpp_lib_chrono_udls",
295 "values": {"c++14": 201304},
296 "headers": ["chrono"],
299 "name": "__cpp_lib_clamp",
300 "values": {"c++17": 201603},
301 "headers": ["algorithm"],
304 "name": "__cpp_lib_complex_udls",
305 "values": {"c++14": 201309},
306 "headers": ["complex"],
309 "name": "__cpp_lib_concepts",
310 "values": {"c++20": 202002},
311 "headers": ["concepts"],
314 "name": "__cpp_lib_constexpr_algorithms",
315 "values": {
316 "c++20": 201806,
317 # "c++26": 202306, # P2562R1 constexpr Stable Sorting
319 "headers": ["algorithm", "utility"],
322 "name": "__cpp_lib_constexpr_bitset",
323 "values": {"c++23": 202207},
324 "headers": ["bitset"],
327 "name": "__cpp_lib_constexpr_charconv",
328 "values": {"c++23": 202207},
329 "headers": ["charconv"],
332 "name": "__cpp_lib_constexpr_cmath",
333 "values": {"c++23": 202202},
334 "headers": ["cmath", "cstdlib"],
335 "unimplemented": True,
338 "name": "__cpp_lib_constexpr_complex",
339 "values": {"c++20": 201711},
340 "headers": ["complex"],
343 "name": "__cpp_lib_constexpr_dynamic_alloc",
344 "values": {"c++20": 201907},
345 "headers": ["memory"],
348 "name": "__cpp_lib_constexpr_functional",
349 "values": {"c++20": 201907},
350 "headers": ["functional"],
353 "name": "__cpp_lib_constexpr_iterator",
354 "values": {"c++20": 201811},
355 "headers": ["iterator"],
358 "name": "__cpp_lib_constexpr_memory",
359 "values": {"c++20": 201811, "c++23": 202202},
360 "headers": ["memory"],
363 "name": "__cpp_lib_constexpr_new",
364 "values": {"c++26": 202406}, # P2747R2 constexpr placement new
365 "headers": ["new"],
366 "unimplemented": True,
369 "name": "__cpp_lib_constexpr_numeric",
370 "values": {"c++20": 201911},
371 "headers": ["numeric"],
374 "name": "__cpp_lib_constexpr_string",
375 "values": {"c++20": 201907},
376 "headers": ["string"],
379 "name": "__cpp_lib_constexpr_string_view",
380 "values": {"c++20": 201811},
381 "headers": ["string_view"],
384 "name": "__cpp_lib_constexpr_tuple",
385 "values": {"c++20": 201811},
386 "headers": ["tuple"],
389 "name": "__cpp_lib_constexpr_typeinfo",
390 "values": {"c++23": 202106},
391 "headers": ["typeinfo"],
394 "name": "__cpp_lib_constexpr_utility",
395 "values": {"c++20": 201811},
396 "headers": ["utility"],
399 "name": "__cpp_lib_constexpr_vector",
400 "values": {"c++20": 201907},
401 "headers": ["vector"],
404 "name": "__cpp_lib_constrained_equality",
405 "values": {"c++26": 202403}, # P2944R3: Comparisons for reference_wrapper
406 "headers": ["optional", "tuple", "utility", "variant"],
407 "unimplemented": True,
410 "name": "__cpp_lib_containers_ranges",
411 "values": {"c++23": 202202},
412 "headers": [
413 "deque",
414 "forward_list",
415 "list",
416 "map",
417 "queue",
418 "set",
419 "stack",
420 "string",
421 "unordered_map",
422 "unordered_set",
423 "vector",
427 "name": "__cpp_lib_copyable_function",
428 "values": {"c++26": 202306}, # P2548R6 copyable_function
429 "headers": ["functional"],
430 "unimplemented": True,
433 "name": "__cpp_lib_coroutine",
434 "values": {"c++20": 201902},
435 "headers": ["coroutine"],
438 "name": "__cpp_lib_debugging",
439 "values": {
440 "c++26": 202311, # P2546R5 Debugging Support
441 # "c++26": 202403, # P2810R4: is_debugger_present is_replaceable
443 "headers": ["debugging"],
444 "unimplemented": True,
447 "name": "__cpp_lib_default_template_type_for_algorithm_values",
448 "values": {"c++26": 202403}, # P2248R8: Enabling list-initialization for algorithms
449 "headers": ["algorithm", "deque", "forward_list", "list", "ranges", "string", "vector"],
450 "unimplemented": True,
453 "name": "__cpp_lib_destroying_delete",
454 "values": {"c++20": 201806},
455 "headers": ["new"],
456 "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
457 "libcxx_guard": "_LIBCPP_STD_VER >= 20 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
460 "name": "__cpp_lib_enable_shared_from_this",
461 "values": {"c++17": 201603},
462 "headers": ["memory"],
465 "name": "__cpp_lib_endian",
466 "values": {"c++20": 201907},
467 "headers": ["bit"],
470 "name": "__cpp_lib_erase_if",
471 "values": {"c++20": 202002},
472 "headers": [
473 "deque",
474 "forward_list",
475 "list",
476 "map",
477 "set",
478 "string",
479 "unordered_map",
480 "unordered_set",
481 "vector",
485 "name": "__cpp_lib_exchange_function",
486 "values": {"c++14": 201304},
487 "headers": ["utility"],
490 "name": "__cpp_lib_execution",
491 "values": {"c++17": 201603, "c++20": 201902},
492 "headers": ["execution"],
493 "unimplemented": True,
496 "name": "__cpp_lib_expected",
497 "values": {"c++23": 202211},
498 "headers": ["expected"],
501 "name": "__cpp_lib_filesystem",
502 "values": {"c++17": 201703},
503 "headers": ["filesystem"],
504 "test_suite_guard": "!defined(_LIBCPP_VERSION) || (!defined(_LIBCPP_HAS_NO_FILESYSTEM) && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)",
505 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_FILESYSTEM) && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY",
508 "name": "__cpp_lib_format",
509 "values": {
510 "c++20": 202110,
511 # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types
512 # "c++26": 202306, P2637R3 Member Visit (implemented)
513 # "c++26": 202311, P2918R2 Runtime format strings II (implemented)
515 # Note these three papers are adopted at the June 2023 meeting and have sequential numbering
516 # 202304 P2510R3 Formatting pointers (Implemented)
517 # 202305 P2757R3 Type-checking format args
518 # 202306 P2637R3 Member Visit
519 "headers": ["format"],
522 "name": "__cpp_lib_format_path",
523 "values": {"c++26": 202403}, # P2845R8: Formatting of std::filesystem::path
524 "headers": ["filesystem"],
525 "unimplemented": True,
528 "name": "__cpp_lib_format_ranges",
529 "values": {"c++23": 202207},
530 "headers": ["format"],
533 "name": "__cpp_lib_format_uchar",
534 "values": {
535 "c++20": 202311 # DR P2909R4 Fix formatting of code units as integers
537 "headers": [
538 "format" # TODO verify this entry since the paper was underspecified.
542 "name": "__cpp_lib_formatters",
543 "values": {"c++23": 202302},
544 "headers": ["stacktrace", "thread"],
545 "unimplemented": True,
548 "name": "__cpp_lib_forward_like",
549 "values": {"c++23": 202207},
550 "headers": ["utility"],
553 "name": "__cpp_lib_freestanding_algorithm",
554 "values": {
555 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
557 "headers": ["algorithm"],
558 "unimplemented": True,
561 "name": "__cpp_lib_freestanding_array",
562 "values": {
563 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
565 "headers": ["array"],
566 "unimplemented": True,
569 "name": "__cpp_lib_freestanding_cstring",
570 "values": {
571 "c++26": 202306 # P2338R4 Freestanding Library: Character primitives and the C library
572 # 202311 # P2407R5 Freestanding Library: Partial Classes
574 "headers": ["cstring"],
575 "unimplemented": True,
578 "name": "__cpp_lib_freestanding_expected",
579 "values": {
580 "c++26": 202311 # P2833R2 Freestanding Library: inout expected span
582 "headers": ["expected"],
583 "unimplemented": True,
586 "name": "__cpp_lib_freestanding_mdspan",
587 "values": {
588 "c++26": 202311 # P2833R2 Freestanding Library: inout expected span
590 "headers": ["mdspan"],
591 "unimplemented": True,
594 "name": "__cpp_lib_freestanding_optional",
595 "values": {
596 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
598 "headers": ["optional"],
599 "unimplemented": True,
602 "name": "__cpp_lib_freestanding_string_view",
603 "values": {
604 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
606 "headers": ["string_view"],
607 "unimplemented": True,
610 "name": "__cpp_lib_freestanding_variant",
611 "values": {
612 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
614 "headers": ["variant"],
615 "unimplemented": True,
618 "name": "__cpp_lib_fstream_native_handle",
619 "values": {"c++26": 202306}, # P1759R6 Native handles and file streams
620 "headers": ["fstream"],
621 "test_suite_guard": "!defined(_LIBCPP_VERSION) || (!defined(_LIBCPP_HAS_NO_FILESYSTEM) && !defined(_LIBCPP_HAS_NO_LOCALIZATION))",
622 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_FILESYSTEM) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)",
625 "name": "__cpp_lib_function_ref",
626 "values": {
627 "c++26": 202306 # P0792R14 function_ref: a type-erased callable reference
629 "headers": ["functional"],
630 "unimplemented": True,
633 "name": "__cpp_lib_gcd_lcm",
634 "values": {"c++17": 201606},
635 "headers": ["numeric"],
638 "name": "__cpp_lib_generate_random",
639 "values": {"c++26": 202403}, # P1068R11: Vector API for random number generation
640 "headers": ["random"],
641 "unimplemented": True,
644 "name": "__cpp_lib_generic_associative_lookup",
645 "values": {"c++14": 201304},
646 "headers": ["map", "set"],
649 "name": "__cpp_lib_generic_unordered_lookup",
650 "values": {"c++20": 201811},
651 "headers": ["unordered_map", "unordered_set"],
654 "name": "__cpp_lib_hardware_interference_size",
655 "values": {"c++17": 201703},
656 "test_suite_guard": "!defined(_LIBCPP_VERSION) || (defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE))",
657 "libcxx_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)",
658 "headers": ["new"],
661 "name": "__cpp_lib_has_unique_object_representations",
662 "values": {"c++17": 201606},
663 "headers": ["type_traits"],
666 "name": "__cpp_lib_hazard_pointer",
667 "values": {"c++26": 202306}, # P2530R3 Hazard Pointers for C++26
668 "headers": [
669 "hazard_pointer" # TODO verify this entry since the paper was underspecified.
671 "unimplemented": True,
674 "name": "__cpp_lib_hypot",
675 "values": {"c++17": 201603},
676 "headers": ["cmath"],
679 "name": "__cpp_lib_incomplete_container_elements",
680 "values": {"c++17": 201505},
681 "headers": ["forward_list", "list", "vector"],
684 "name": "__cpp_lib_inplace_vector",
685 "values": {"c++26": 202406}, # P0843R14 inplace_vector
686 "headers": ["inplace_vector"],
687 "unimplemented": True,
690 "name": "__cpp_lib_int_pow2",
691 "values": {"c++20": 202002},
692 "headers": ["bit"],
695 "name": "__cpp_lib_integer_comparison_functions",
696 "values": {"c++20": 202002},
697 "headers": ["utility"],
700 "name": "__cpp_lib_integer_sequence",
701 "values": {"c++14": 201304},
702 "headers": ["utility"],
705 "name": "__cpp_lib_integral_constant_callable",
706 "values": {"c++14": 201304},
707 "headers": ["type_traits"],
710 "name": "__cpp_lib_interpolate",
711 "values": {"c++20": 201902},
712 "headers": ["cmath", "numeric"],
715 "name": "__cpp_lib_invoke",
716 "values": {"c++17": 201411},
717 "headers": ["functional"],
720 "name": "__cpp_lib_invoke_r",
721 "values": {"c++23": 202106},
722 "headers": ["functional"],
725 "name": "__cpp_lib_ios_noreplace",
726 "values": {"c++23": 202207},
727 "headers": ["ios"],
730 "name": "__cpp_lib_is_aggregate",
731 "values": {"c++17": 201703},
732 "headers": ["type_traits"],
735 "name": "__cpp_lib_is_constant_evaluated",
736 "values": {"c++20": 201811},
737 "headers": ["type_traits"],
740 "name": "__cpp_lib_is_final",
741 "values": {"c++14": 201402},
742 "headers": ["type_traits"],
745 "name": "__cpp_lib_is_invocable",
746 "values": {"c++17": 201703},
747 "headers": ["type_traits"],
750 "name": "__cpp_lib_is_layout_compatible",
751 "values": {"c++20": 201907},
752 "headers": ["type_traits"],
753 "unimplemented": True,
756 "name": "__cpp_lib_is_nothrow_convertible",
757 "values": {"c++20": 201806},
758 "headers": ["type_traits"],
761 "name": "__cpp_lib_is_null_pointer",
762 "values": {"c++14": 201309},
763 "headers": ["type_traits"],
766 "name": "__cpp_lib_is_pointer_interconvertible",
767 "values": {"c++20": 201907},
768 "headers": ["type_traits"],
769 "unimplemented": True,
772 "name": "__cpp_lib_is_scoped_enum",
773 "values": {"c++23": 202011},
774 "headers": ["type_traits"],
777 "name": "__cpp_lib_is_swappable",
778 "values": {"c++17": 201603},
779 "headers": ["type_traits"],
782 "name": "__cpp_lib_is_virtual_base_of",
783 "values": {
784 "c++26": 202406 # P2985R0 A type trait for detecting virtual base classes
786 "headers": ["type_traits"],
787 "unimplemented": True,
790 "name": "__cpp_lib_is_within_lifetime",
791 # Note this name was changed from "__cpp_lib_within_lifetime" when the paper was adopted
792 # https://github.com/cplusplus/draft/commit/0facada4cadd97e1ba15bfaea76a804f1dc5c309
793 "values": {
794 "c++26": 202306 # P2641R4 Checking if a union alternative is active
796 "headers": ["type_traits"],
797 "unimplemented": True,
800 "name": "__cpp_lib_jthread",
801 "values": {"c++20": 201911},
802 "headers": ["stop_token", "thread"],
803 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
804 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN) && _LIBCPP_AVAILABILITY_HAS_SYNC",
807 "name": "__cpp_lib_latch",
808 "values": {"c++20": 201907},
809 "headers": ["latch"],
810 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
811 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
814 "name": "__cpp_lib_launder",
815 "values": {"c++17": 201606},
816 "headers": ["new"],
819 "name": "__cpp_lib_linalg",
820 "values": {
821 "c++26": 202311 # P1673 A free function linear algebra interface based on the BLAS
823 "headers": ["linalg"],
824 "unimplemented": True,
827 "name": "__cpp_lib_list_remove_return_type",
828 "values": {"c++20": 201806},
829 "headers": ["forward_list", "list"],
832 "name": "__cpp_lib_logical_traits",
833 "values": {"c++17": 201510},
834 "headers": ["type_traits"],
837 "name": "__cpp_lib_make_from_tuple",
838 "values": {"c++17": 201606},
839 "headers": ["tuple"],
842 "name": "__cpp_lib_make_reverse_iterator",
843 "values": {"c++14": 201402},
844 "headers": ["iterator"],
847 "name": "__cpp_lib_make_unique",
848 "values": {"c++14": 201304},
849 "headers": ["memory"],
852 "name": "__cpp_lib_map_try_emplace",
853 "values": {"c++17": 201411},
854 "headers": ["map"],
857 "name": "__cpp_lib_math_constants",
858 "values": {"c++20": 201907},
859 "headers": ["numbers"],
862 "name": "__cpp_lib_math_special_functions",
863 "values": {"c++17": 201603},
864 "headers": ["cmath"],
865 "unimplemented": True,
868 "name": "__cpp_lib_mdspan",
869 "values": {
870 "c++23": 202207,
871 "c++26": 202406, # P2389R2 dextents Index Type Parameter
873 "headers": ["mdspan"],
876 "name": "__cpp_lib_memory_resource",
877 "values": {"c++17": 201603},
878 "headers": ["memory_resource"],
879 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",
880 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",
883 "name": "__cpp_lib_modules",
884 "values": {"c++23": 202207},
885 "headers": [],
888 "name": "__cpp_lib_move_iterator_concept",
889 "values": {"c++20": 202207},
890 "headers": ["iterator"],
893 "name": "__cpp_lib_move_only_function",
894 "values": {"c++23": 202110},
895 "headers": ["functional"],
896 "unimplemented": True,
899 "name": "__cpp_lib_node_extract",
900 "values": {"c++17": 201606},
901 "headers": ["map", "set", "unordered_map", "unordered_set"],
904 "name": "__cpp_lib_nonmember_container_access",
905 "values": {"c++17": 201411},
906 "headers": [
907 "array",
908 "deque",
909 "forward_list",
910 "iterator",
911 "list",
912 "map",
913 "regex",
914 "set",
915 "string",
916 "unordered_map",
917 "unordered_set",
918 "vector",
922 "name": "__cpp_lib_not_fn",
923 "values": {
924 "c++17": 201603,
925 # "c++26": 202306, # P2714R1 Bind front and back to NTTP callables
927 "headers": ["functional"],
930 "name": "__cpp_lib_null_iterators",
931 "values": {"c++14": 201304},
932 "headers": ["iterator"],
935 "name": "__cpp_lib_optional",
936 "values": {"c++17": 201606, "c++23": 202110},
937 "headers": ["optional"],
940 "name": "__cpp_lib_optional_range_support",
941 "values": {"c++26": 202406}, # P3168R2 Give std::optional Range Support
942 "headers": ["optional"],
943 "unimplemented": True,
946 "name": "__cpp_lib_out_ptr",
947 "values": {
948 "c++23": 202106,
949 "c++26": 202311, # P2833R2 Freestanding Library: inout expected span
951 "headers": ["memory"],
954 "name": "__cpp_lib_parallel_algorithm",
955 "values": {"c++17": 201603},
956 "headers": ["algorithm", "numeric"],
957 "unimplemented": True,
960 "name": "__cpp_lib_philox_engine",
961 "values": {
962 "c++26": 202406
963 }, # P2075R6 Philox as an extension of the C++ RNG engines
964 # Note the paper mentions 202310L as value, which differs from the typical procedure.
965 "headers": ["random"],
966 "unimplemented": True,
969 "name": "__cpp_lib_polymorphic_allocator",
970 "values": {"c++20": 201902},
971 "headers": ["memory_resource"],
972 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",
973 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",
976 "name": "__cpp_lib_print",
977 "values": {
978 "c++23": 202207,
979 # "c++26": 202403, # P3107R5: Permit an efficient implementation of std::print
980 # "c++26": 202406, # P3235R3 std::print more types faster with less memory
982 "headers": ["ostream", "print"],
985 "name": "__cpp_lib_quoted_string_io",
986 "values": {"c++14": 201304},
987 "headers": ["iomanip"],
988 "test_suite_guard": "!defined(_LIBCPP_VERSION) || !defined(_LIBCPP_HAS_NO_LOCALIZATION)",
989 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
992 "name": "__cpp_lib_ranges",
993 "values": {
994 "c++20": 202207,
995 # "c++23": 202302, # Relaxing Ranges Just A Smidge
996 # "c++26": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts (already implemented as a DR)
998 "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
1001 "name": "__cpp_lib_ranges_as_const",
1002 "values": {
1003 "c++23": 202207 # P2278R4 cbegin should always return a constant iterator
1004 # 202311 # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility
1006 "headers": ["ranges"],
1007 "unimplemented": True,
1010 "name": "__cpp_lib_ranges_as_rvalue",
1011 "values": {"c++23": 202207},
1012 "headers": ["ranges"],
1015 "name": "__cpp_lib_ranges_chunk",
1016 "values": {"c++23": 202202},
1017 "headers": ["ranges"],
1018 "unimplemented": True,
1021 "name": "__cpp_lib_ranges_chunk_by",
1022 "values": {"c++23": 202202},
1023 "headers": ["ranges"],
1026 "name": "__cpp_lib_ranges_concat",
1027 "values": {"c++26": 202403}, # P2542R8: views::concat
1028 "headers": ["ranges"],
1029 "unimplemented": True,
1032 "name": "__cpp_lib_ranges_contains",
1033 "values": {"c++23": 202207},
1034 "headers": ["algorithm"],
1037 "name": "__cpp_lib_ranges_find_last",
1038 "values": {"c++23": 202207},
1039 "headers": ["algorithm"],
1042 "name": "__cpp_lib_ranges_iota",
1043 "values": {"c++23": 202202},
1044 "headers": ["numeric"],
1045 "unimplemented": True,
1048 "name": "__cpp_lib_ranges_join_with",
1049 "values": {"c++23": 202202},
1050 "headers": ["ranges"],
1051 "unimplemented": True,
1054 "name": "__cpp_lib_ranges_repeat",
1055 "values": {"c++23": 202207},
1056 "headers": ["ranges"],
1059 "name": "__cpp_lib_ranges_slide",
1060 "values": {"c++23": 202202},
1061 "headers": ["ranges"],
1062 "unimplemented": True,
1065 "name": "__cpp_lib_ranges_starts_ends_with",
1066 "values": {"c++23": 202106},
1067 "headers": ["algorithm"],
1070 "name": "__cpp_lib_ranges_to_container",
1071 "values": {"c++23": 202202},
1072 "headers": ["ranges"],
1075 "name": "__cpp_lib_ranges_zip",
1076 "values": {"c++23": 202110},
1077 "headers": ["ranges", "tuple", "utility"],
1078 "unimplemented": True,
1081 "name": "__cpp_lib_ratio",
1082 "values": {"c++26": 202306}, # P2734R0 Adding the new SI prefixes
1083 "headers": ["ratio"],
1086 "name": "__cpp_lib_raw_memory_algorithms",
1087 "values": {"c++17": 201606},
1088 "headers": ["memory"],
1091 "name": "__cpp_lib_rcu",
1092 "values": {"c++26": 202306}, # P2545R4 Read-Copy Update (RCU)
1093 "headers": [
1094 "rcu" # TODO verify this entry since the paper was underspecified.
1096 "unimplemented": True,
1099 "name": "__cpp_lib_reference_from_temporary",
1100 "values": {"c++23": 202202},
1101 "headers": ["type_traits"],
1102 "unimplemented": True,
1105 "name": "__cpp_lib_reference_wrapper",
1106 "values": {"c++26": 202403}, # P2944R3: Comparisons for reference_wrapper
1107 "headers": ["functional"],
1110 "name": "__cpp_lib_remove_cvref",
1111 "values": {"c++20": 201711},
1112 "headers": ["type_traits"],
1115 "name": "__cpp_lib_result_of_sfinae",
1116 "values": {"c++14": 201210},
1117 "headers": ["functional", "type_traits"],
1120 "name": "__cpp_lib_robust_nonmodifying_seq_ops",
1121 "values": {"c++14": 201304},
1122 "headers": ["algorithm"],
1125 "name": "__cpp_lib_sample",
1126 "values": {"c++17": 201603},
1127 "headers": ["algorithm"],
1130 "name": "__cpp_lib_saturation_arithmetic",
1131 "values": {"c++26": 202311}, # P0543R3 Saturation arithmetic
1132 "headers": ["numeric"],
1135 "name": "__cpp_lib_scoped_lock",
1136 "values": {"c++17": 201703},
1137 "headers": ["mutex"],
1138 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1139 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1142 "name": "__cpp_lib_semaphore",
1143 "values": {"c++20": 201907},
1144 "headers": ["semaphore"],
1145 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
1146 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
1149 "name": "__cpp_lib_senders",
1150 "values": {"c++26": 202406}, # P2300R10 std::execution
1151 "headers": ["execution"],
1152 "unimplemented": True,
1155 "name": "__cpp_lib_shared_mutex",
1156 "values": {"c++17": 201505},
1157 "headers": ["shared_mutex"],
1158 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1159 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1162 "name": "__cpp_lib_shared_ptr_arrays",
1163 "values": {"c++17": 201611, "c++20": 201707},
1164 "headers": ["memory"],
1167 "name": "__cpp_lib_shared_ptr_weak_type",
1168 "values": {"c++17": 201606},
1169 "headers": ["memory"],
1172 "name": "__cpp_lib_shared_timed_mutex",
1173 "values": {"c++14": 201402},
1174 "headers": ["shared_mutex"],
1175 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1176 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1179 "name": "__cpp_lib_shift",
1180 "values": {"c++20": 201806},
1181 "headers": ["algorithm"],
1184 "name": "__cpp_lib_smart_ptr_for_overwrite",
1185 "values": {"c++20": 202002},
1186 "headers": ["memory"],
1187 "unimplemented": True,
1190 "name": "__cpp_lib_smart_ptr_owner_equality",
1191 "values": {
1192 "c++26": 202306 # P1901R2 Enabling the Use of weak_ptr as Keys in Unordered Associative Containers
1194 "headers": ["memory"],
1195 "unimplemented": True,
1198 "name": "__cpp_lib_source_location",
1199 "values": {"c++20": 201907},
1200 "headers": ["source_location"],
1203 "name": "__cpp_lib_span",
1204 "values": {
1205 "c++20": 202002,
1206 # "c++26": 202311, # P2821R5 span.at()
1207 # 202311 # P2833R2 Freestanding Library: inout expected span
1209 "headers": ["span"],
1212 "name": "__cpp_lib_span_at",
1213 "values": {"c++26": 202311}, # P2821R3 span.at()
1214 "headers": ["span"],
1217 "name": "__cpp_lib_span_initializer_list",
1218 "values": {"c++26": 202311}, # P2447R6 std::span over an initializer list
1219 "headers": ["span"],
1222 "name": "__cpp_lib_spanstream",
1223 "values": {"c++23": 202106},
1224 "headers": ["spanstream"],
1225 "unimplemented": True,
1228 "name": "__cpp_lib_ssize",
1229 "values": {"c++20": 201902},
1230 "headers": ["iterator"],
1233 "name": "__cpp_lib_sstream_from_string_view",
1234 "values": {
1235 "c++26": 202306 # P2495R3 Interfacing stringstreams with string_view
1237 "headers": ["sstream"],
1240 "name": "__cpp_lib_stacktrace",
1241 "values": {"c++23": 202011},
1242 "headers": ["stacktrace"],
1243 "unimplemented": True,
1246 "name": "__cpp_lib_starts_ends_with",
1247 "values": {"c++20": 201711},
1248 "headers": ["string", "string_view"],
1251 "name": "__cpp_lib_stdatomic_h",
1252 "values": {"c++23": 202011},
1253 "headers": ["stdatomic.h"],
1256 "name": "__cpp_lib_string_contains",
1257 "values": {"c++23": 202011},
1258 "headers": ["string", "string_view"],
1261 "name": "__cpp_lib_string_resize_and_overwrite",
1262 "values": {"c++23": 202110},
1263 "headers": ["string"],
1266 "name": "__cpp_lib_string_udls",
1267 "values": {"c++14": 201304},
1268 "headers": ["string"],
1271 "name": "__cpp_lib_string_view",
1272 "values": {
1273 "c++17": 201606,
1274 "c++20": 201803,
1275 "c++26": 202403, # P2591R5: Concatenation of strings and string views
1277 "headers": ["string", "string_view"],
1280 "name": "__cpp_lib_submdspan",
1281 "values": {
1282 "c++26": 202306, # P2630R4: submdspan
1283 # "c++26": 202403, # P2642R6: Padded mdspan layouts
1285 "headers": ["mdspan"],
1286 "unimplemented": True,
1289 "name": "__cpp_lib_syncbuf",
1290 "values": {"c++20": 201803},
1291 "headers": ["syncstream"],
1292 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)",
1293 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)",
1296 "name": "__cpp_lib_text_encoding",
1297 "values": {
1298 "c++26": 202306 # P1885R12 Naming Text Encodings to Demystify Them
1300 "headers": ["text_encoding"],
1301 "unimplemented": True,
1304 "name": "__cpp_lib_three_way_comparison",
1305 "values": {"c++20": 201907},
1306 "headers": ["compare"],
1309 "name": "__cpp_lib_to_address",
1310 "values": {"c++20": 201711},
1311 "headers": ["memory"],
1314 "name": "__cpp_lib_to_array",
1315 "values": {"c++20": 201907},
1316 "headers": ["array"],
1319 "name": "__cpp_lib_to_chars",
1320 "values": {
1321 "c++17": 201611,
1322 "c++26": 202306, # P2497R0 Testing for success or failure of <charconv> functions
1324 "headers": ["charconv"],
1325 "unimplemented": True,
1328 "name": "__cpp_lib_to_string",
1329 "values": {"c++26": 202306}, # P2587R3 to_string or not to_string
1330 "headers": ["string"],
1331 "unimplemented": True,
1334 "name": "__cpp_lib_to_underlying",
1335 "values": {"c++23": 202102},
1336 "headers": ["utility"],
1339 "name": "__cpp_lib_transformation_trait_aliases",
1340 "values": {"c++14": 201304},
1341 "headers": ["type_traits"],
1344 "name": "__cpp_lib_transparent_operators",
1345 "values": {"c++14": 201210, "c++17": 201510},
1346 "headers": ["functional", "memory"],
1349 "name": "__cpp_lib_tuple_element_t",
1350 "values": {"c++14": 201402},
1351 "headers": ["tuple"],
1354 "name": "__cpp_lib_tuple_like",
1355 "values": {
1356 "c++23": 202207, # P2165R4 Compatibility between tuple, pair and tuple-like objects
1357 "c++26": 202311, # P2819R2 Add tuple protocol to complex (implemented)
1359 "headers": ["map", "tuple", "unordered_map", "utility"],
1360 "unimplemented": True,
1363 "name": "__cpp_lib_tuples_by_type",
1364 "values": {"c++14": 201304},
1365 "headers": ["tuple", "utility"],
1368 "name": "__cpp_lib_type_identity",
1369 "values": {"c++20": 201806},
1370 "headers": ["type_traits"],
1373 "name": "__cpp_lib_type_trait_variable_templates",
1374 "values": {"c++17": 201510},
1375 "headers": ["type_traits"],
1378 "name": "__cpp_lib_uncaught_exceptions",
1379 "values": {"c++17": 201411},
1380 "headers": ["exception"],
1383 "name": "__cpp_lib_unordered_map_try_emplace",
1384 "values": {"c++17": 201411},
1385 "headers": ["unordered_map"],
1388 "name": "__cpp_lib_unreachable",
1389 "values": {"c++23": 202202},
1390 "headers": ["utility"],
1393 "name": "__cpp_lib_unwrap_ref",
1394 "values": {"c++20": 201811},
1395 "headers": ["functional"],
1398 "name": "__cpp_lib_variant",
1399 "values": {
1400 "c++17": 202102, # std::visit for classes derived from std::variant
1401 # "c++20": 202106, # Fully constexpr std::variant
1402 # "c++26": 202306, # Member visit (implemented)
1404 "headers": ["variant"],
1407 "name": "__cpp_lib_void_t",
1408 "values": {"c++17": 201411},
1409 "headers": ["type_traits"],
1414 assert feature_test_macros == sorted(feature_test_macros, key=lambda tc: tc["name"])
1415 for tc in feature_test_macros:
1416 assert tc["headers"] == sorted(tc["headers"]), tc
1417 assert ("libcxx_guard" in tc) == ("test_suite_guard" in tc), tc
1418 valid_keys = ["name", "values", "headers", "libcxx_guard", "test_suite_guard", "unimplemented"]
1419 assert all(key in valid_keys for key in tc.keys()), tc
1421 # Map from each header to the Lit annotations that should be used for
1422 # tests that include that header.
1424 # For example, when threads are not supported, any test that includes
1425 # <thread> should be marked as UNSUPPORTED, because including <thread>
1426 # is a hard error in that case.
1427 lit_markup = {
1428 "barrier": ["UNSUPPORTED: no-threads"],
1429 "filesystem": ["UNSUPPORTED: no-filesystem"],
1430 "fstream": ["UNSUPPORTED: no-localization"],
1431 "iomanip": ["UNSUPPORTED: no-localization"],
1432 "ios": ["UNSUPPORTED: no-localization"],
1433 "iostream": ["UNSUPPORTED: no-localization"],
1434 "istream": ["UNSUPPORTED: no-localization"],
1435 "latch": ["UNSUPPORTED: no-threads"],
1436 "locale": ["UNSUPPORTED: no-localization"],
1437 "mutex": ["UNSUPPORTED: no-threads"],
1438 "ostream": ["UNSUPPORTED: no-localization"],
1439 "print": ["UNSUPPORTED: no-filesystem"],
1440 "regex": ["UNSUPPORTED: no-localization"],
1441 "semaphore": ["UNSUPPORTED: no-threads"],
1442 "shared_mutex": ["UNSUPPORTED: no-threads"],
1443 "sstream": ["UNSUPPORTED: no-localization"],
1444 "syncstream": ["UNSUPPORTED: no-localization"],
1445 "stdatomic.h": ["UNSUPPORTED: no-threads"],
1446 "stop_token": ["UNSUPPORTED: no-threads"],
1447 "thread": ["UNSUPPORTED: no-threads"],
1451 def get_std_dialects():
1452 std_dialects = ["c++14", "c++17", "c++20", "c++23", "c++26"]
1453 return list(std_dialects)
1456 def get_first_std(d):
1457 for s in get_std_dialects():
1458 if s in d.keys():
1459 return s
1460 return None
1463 def get_last_std(d):
1464 rev_dialects = get_std_dialects()
1465 rev_dialects.reverse()
1466 for s in rev_dialects:
1467 if s in d.keys():
1468 return s
1469 return None
1472 def get_std_before(d, std):
1473 std_dialects = get_std_dialects()
1474 candidates = std_dialects[0 : std_dialects.index(std)]
1475 candidates.reverse()
1476 for cand in candidates:
1477 if cand in d.keys():
1478 return cand
1479 return None
1482 def get_value_before(d, std):
1483 new_std = get_std_before(d, std)
1484 if new_std is None:
1485 return None
1486 return d[new_std]
1489 def get_for_std(d, std):
1490 # This catches the C++11 case for which there should be no defined feature
1491 # test macros.
1492 std_dialects = get_std_dialects()
1493 if std not in std_dialects:
1494 return None
1495 # Find the value for the newest C++ dialect between C++14 and std
1496 std_list = list(std_dialects[0 : std_dialects.index(std) + 1])
1497 std_list.reverse()
1498 for s in std_list:
1499 if s in d.keys():
1500 return d[s]
1501 return None
1504 def get_std_number(std):
1505 return std.replace("c++", "")
1509 Functions to produce the <version> header
1513 def produce_macros_definition_for_std(std):
1514 result = ""
1515 indent = 55
1516 for tc in feature_test_macros:
1517 if std not in tc["values"]:
1518 continue
1519 inner_indent = 1
1520 if "test_suite_guard" in tc.keys():
1521 result += "# if %s\n" % tc["libcxx_guard"]
1522 inner_indent += 2
1523 if get_value_before(tc["values"], std) is not None:
1524 assert "test_suite_guard" not in tc.keys()
1525 result += "# undef %s\n" % tc["name"]
1526 line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])
1527 line += " " * (indent - len(line))
1528 line += " %sL" % tc["values"][std]
1529 if "unimplemented" in tc.keys():
1530 line = "// " + line
1531 result += line
1532 result += "\n"
1533 if "test_suite_guard" in tc.keys():
1534 result += "# endif\n"
1535 return result.strip()
1538 def produce_macros_definitions():
1539 macro_definition_template = """#if _LIBCPP_STD_VER >= {std_number}
1540 {macro_definition}
1541 #endif"""
1543 macros_definitions = []
1544 for std in get_std_dialects():
1545 macros_definitions.append(
1546 macro_definition_template.format(
1547 std_number=get_std_number(std),
1548 macro_definition=produce_macros_definition_for_std(std),
1552 return "\n\n".join(macros_definitions)
1555 def chunks(l, n):
1556 """Yield successive n-sized chunks from l."""
1557 for i in range(0, len(l), n):
1558 yield l[i : i + n]
1561 def produce_version_synopsis():
1562 indent = 56
1563 header_indent = 56 + len("20XXYYL ")
1564 result = ""
1566 def indent_to(s, val):
1567 if len(s) >= val:
1568 return s
1569 s += " " * (val - len(s))
1570 return s
1572 line = indent_to("Macro name", indent) + "Value"
1573 line = indent_to(line, header_indent) + "Headers"
1574 result += line + "\n"
1575 for tc in feature_test_macros:
1576 prev_defined_std = get_last_std(tc["values"])
1577 line = "{name: <{indent}}{value}L ".format(
1578 name=tc["name"], indent=indent, value=tc["values"][prev_defined_std]
1580 headers = list(tc["headers"])
1581 headers.remove("version")
1582 for chunk in chunks(headers, 3):
1583 line = indent_to(line, header_indent)
1584 chunk = ["<%s>" % header for header in chunk]
1585 line += " ".join(chunk)
1586 result += line
1587 result += "\n"
1588 line = ""
1589 while True:
1590 prev_defined_std = get_std_before(tc["values"], prev_defined_std)
1591 if prev_defined_std is None:
1592 break
1593 result += "%s%sL // %s\n" % (
1594 indent_to("", indent),
1595 tc["values"][prev_defined_std],
1596 prev_defined_std.replace("c++", "C++"),
1598 return result
1601 def produce_version_header():
1602 template = """// -*- C++ -*-
1603 //===----------------------------------------------------------------------===//
1605 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1606 // See https://llvm.org/LICENSE.txt for license information.
1607 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1609 //===----------------------------------------------------------------------===//
1611 #ifndef _LIBCPP_VERSIONH
1612 #define _LIBCPP_VERSIONH
1615 version synopsis
1617 {synopsis}
1621 #include <__config>
1623 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1624 # pragma GCC system_header
1625 #endif
1627 // clang-format off
1629 {cxx_macros}
1631 // clang-format on
1633 #endif // _LIBCPP_VERSIONH
1636 version_str = template.format(
1637 synopsis=produce_version_synopsis().strip(),
1638 cxx_macros=produce_macros_definitions(),
1640 version_header_path = os.path.join(include_path, "version")
1641 with open(version_header_path, "w", newline="\n") as f:
1642 f.write(version_str)
1646 Functions to produce test files
1649 test_types = {
1650 "undefined": """
1651 # ifdef {name}
1652 # error "{name} should not be defined before {std_first}"
1653 # endif
1654 """,
1655 "test_suite_guard": """
1656 # if {test_suite_guard}
1657 # ifndef {name}
1658 # error "{name} should be defined in {std}"
1659 # endif
1660 # if {name} != {value}
1661 # error "{name} should have the value {value} in {std}"
1662 # endif
1663 # else
1664 # ifdef {name}
1665 # error "{name} should not be defined when the requirement '{test_suite_guard}' is not met!"
1666 # endif
1667 # endif
1668 """,
1669 "unimplemented": """
1670 # if !defined(_LIBCPP_VERSION)
1671 # ifndef {name}
1672 # error "{name} should be defined in {std}"
1673 # endif
1674 # if {name} != {value}
1675 # error "{name} should have the value {value} in {std}"
1676 # endif
1677 # else // _LIBCPP_VERSION
1678 # ifdef {name}
1679 # error "{name} should not be defined because it is unimplemented in libc++!"
1680 # endif
1681 # endif
1682 """,
1683 "defined": """
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 """,
1694 def generate_std_test(test_list, std):
1695 result = ""
1696 for tc in test_list:
1697 val = get_for_std(tc["values"], std)
1698 if val is not None:
1699 val = "%sL" % val
1700 if val is None:
1701 result += test_types["undefined"].format(
1702 name=tc["name"], std_first=get_first_std(tc["values"])
1704 elif "unimplemented" in tc.keys():
1705 result += test_types["unimplemented"].format(
1706 name=tc["name"], value=val, std=std
1708 elif "test_suite_guard" in tc.keys():
1709 result += test_types["test_suite_guard"].format(
1710 name=tc["name"],
1711 value=val,
1712 std=std,
1713 test_suite_guard=tc["test_suite_guard"],
1715 else:
1716 result += test_types["defined"].format(name=tc["name"], value=val, std=std)
1717 return result.strip()
1720 def generate_std_tests(test_list):
1721 std_tests_template = """#if TEST_STD_VER < {first_std_number}
1723 {pre_std_test}
1725 {other_std_tests}
1727 #elif TEST_STD_VER > {penultimate_std_number}
1729 {last_std_test}
1731 #endif // TEST_STD_VER > {penultimate_std_number}"""
1733 std_dialects = get_std_dialects()
1735 other_std_tests = []
1736 for std in std_dialects[:-1]:
1737 other_std_tests.append("#elif TEST_STD_VER == " + get_std_number(std))
1738 other_std_tests.append(generate_std_test(test_list, std))
1740 std_tests = std_tests_template.format(
1741 first_std_number=get_std_number(std_dialects[0]),
1742 pre_std_test=generate_std_test(test_list, "c++11"),
1743 other_std_tests="\n\n".join(other_std_tests),
1744 penultimate_std_number=get_std_number(std_dialects[-2]),
1745 last_std_test=generate_std_test(test_list, std_dialects[-1]),
1748 return std_tests
1751 def generate_synopsis(test_list):
1752 max_name_len = max([len(tc["name"]) for tc in test_list])
1753 indent = max_name_len + 8
1755 def mk_line(prefix, suffix):
1756 return "{prefix: <{max_len}}{suffix}\n".format(
1757 prefix=prefix, suffix=suffix, max_len=indent
1760 result = ""
1761 result += mk_line("/* Constant", "Value")
1762 for tc in test_list:
1763 prefix = " %s" % tc["name"]
1764 for std in [s for s in get_std_dialects() if s in tc["values"].keys()]:
1765 result += mk_line(
1766 prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++"))
1768 prefix = ""
1769 result += "*/"
1770 return result
1773 def produce_tests():
1774 headers = set([h for tc in feature_test_macros for h in tc["headers"]])
1775 for h in headers:
1776 test_list = [tc for tc in feature_test_macros if h in tc["headers"]]
1777 if not has_header(h):
1778 for tc in test_list:
1779 assert "unimplemented" in tc.keys()
1780 continue
1781 markup = "\n".join("// " + tag for tag in lit_markup.get(h, []))
1782 test_body = """//===----------------------------------------------------------------------===//
1784 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1785 // See https://llvm.org/LICENSE.txt for license information.
1786 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1788 //===----------------------------------------------------------------------===//
1790 // WARNING: This test was generated by {script_name}
1791 // and should not be edited manually.
1793 // clang-format off
1794 {markup}
1795 // <{header}>
1797 // Test the feature test macros defined by <{header}>
1799 {synopsis}
1801 #include <{header}>
1802 #include "test_macros.h"
1804 {cxx_tests}
1806 """.format(
1807 script_name=script_name,
1808 header=h,
1809 markup=("\n{}\n".format(markup) if markup else ""),
1810 synopsis=generate_synopsis(test_list),
1811 cxx_tests=generate_std_tests(test_list),
1813 test_name = "{header}.version.compile.pass.cpp".format(header=h)
1814 out_path = os.path.join(macro_test_path, test_name)
1815 with open(out_path, "w", newline="\n") as f:
1816 f.write(test_body)
1820 Produce documentation for the feature test macros
1824 def make_widths(grid):
1825 widths = []
1826 for i in range(0, len(grid[0])):
1827 cell_width = 2 + max(
1828 reduce(lambda x, y: x + y, [[len(row[i])] for row in grid], [])
1830 widths += [cell_width]
1831 return widths
1834 def create_table(grid, indent):
1835 indent_str = " " * indent
1836 col_widths = make_widths(grid)
1837 result = [indent_str + add_divider(col_widths, 2)]
1838 header_flag = 2
1839 for row_i in range(0, len(grid)):
1840 row = grid[row_i]
1841 line = indent_str + " ".join(
1842 [pad_cell(row[i], col_widths[i]) for i in range(0, len(row))]
1844 result.append(line.rstrip())
1845 if row_i == len(grid) - 1:
1846 header_flag = 2
1847 if row[0].startswith("**"):
1848 header_flag += 1
1849 separator = indent_str + add_divider(col_widths, header_flag)
1850 result.append(separator.rstrip())
1851 header_flag = 0
1852 return "\n".join(result)
1855 def add_divider(widths, header_flag):
1856 if header_flag == 3:
1857 return "=".join(["=" * w for w in widths])
1858 if header_flag == 2:
1859 return " ".join(["=" * w for w in widths])
1860 if header_flag == 1:
1861 return "-".join(["-" * w for w in widths])
1862 else:
1863 return " ".join(["-" * w for w in widths])
1866 def pad_cell(s, length, left_align=True):
1867 padding = (length - len(s)) * " "
1868 return s + padding
1871 def get_status_table():
1872 table = [["Macro Name", "Value"]]
1873 for std in get_std_dialects():
1874 table += [["**" + std.replace("c++", "C++") + "**", ""]]
1875 for tc in feature_test_macros:
1876 if std not in tc["values"].keys():
1877 continue
1878 value = "``%sL``" % tc["values"][std]
1879 if "unimplemented" in tc.keys():
1880 value = "*unimplemented*"
1881 table += [["``%s``" % tc["name"], value]]
1882 return table
1885 def produce_docs():
1886 doc_str = """.. _FeatureTestMacroTable:
1888 ==========================
1889 Feature Test Macro Support
1890 ==========================
1892 .. contents::
1893 :local:
1895 Overview
1896 ========
1898 This file documents the feature test macros currently supported by libc++.
1900 .. _feature-status:
1902 Status
1903 ======
1905 .. table:: Current Status
1906 :name: feature-status-table
1907 :widths: auto
1909 {status_tables}
1911 """.format(
1912 status_tables=create_table(get_status_table(), 4)
1915 table_doc_path = os.path.join(docs_path, "FeatureTestMacroTable.rst")
1916 with open(table_doc_path, "w", newline="\n") as f:
1917 f.write(doc_str)
1920 def get_ftms(
1921 data, std_dialects: List[str], use_implemented_status: bool
1922 ) -> Dict[str, Dict[str, Any]]:
1923 """Impementation for FeatureTestMacros.(standard|implemented)_ftms()."""
1924 result = dict()
1925 for feature in data:
1926 last = None
1927 entry = dict()
1928 implemented = True
1929 for std in std_dialects:
1930 if std not in feature["values"].keys():
1931 if last == None:
1932 continue
1933 else:
1934 entry[std] = last
1935 else:
1936 if implemented:
1937 values = feature["values"][std]
1938 assert len(values) > 0, f"{feature['name']}[{std}] has no entries"
1939 for value in values:
1940 papers = list(values[value])
1941 assert (
1942 len(papers) > 0
1943 ), f"{feature['name']}[{std}][{value}] has no entries"
1944 for paper in papers:
1945 if use_implemented_status and not paper["implemented"]:
1946 implemented = False
1947 break
1948 if implemented:
1949 last = f"{value}L"
1950 else:
1951 break
1953 entry[std] = last
1954 result[feature["name"]] = entry
1956 return result
1959 class FeatureTestMacros:
1960 """Provides all feature-test macro (FTM) output components.
1962 The class has several generators to use the feature-test macros in libc++:
1963 - FTM status page
1964 - The version header and its tests
1966 This class is not intended to duplicate
1967 https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros
1968 SD-FeatureTest: Feature-Test Macros and Policies
1970 Historically libc++ did not list all papers affecting a FTM, the new data
1971 structure is able to do that. However there is no intention to add the
1972 historical data. After papers have been implemented this information can be
1973 removed. For example, __cpp_lib_format's value 201907 requires 3 papers,
1974 once implemented it can be reduced to 1 paper and remove the paper number
1975 and title. This would reduce the size of the data.
1977 The input data is stored in the following JSON format:
1978 [ # A list with multiple feature-test macro entries.
1980 # required
1981 # The name of the feature test macro. These names should be unique and
1982 # sorted in the list.
1983 "name": "__cpp_lib_any",
1985 # required
1986 # A map with the value of the FTM based on the language standard. Only
1987 # the versions in which the value of the FTM changes are listed. For
1988 # example, this macro's value does not change in C++20 so it does not
1989 # list C++20. If it changes in C++26, it will have entries for C++17 and
1990 # C++26.
1991 "values": {
1993 # required
1994 # The language standard, also named dialect in this class.
1995 "c++17": {
1997 # required
1998 # The value of the feature test macro. This contains an array with
1999 # one or more papers that need to be implemented before this value
2000 # is considered implemented.
2001 "201606": [
2003 # optional
2004 # Contains the paper number that is part of the FTM version.
2005 "number": "P0220R1",
2007 # optional
2008 # Contains the title of the paper that is part of the FTM
2009 # version.
2010 "title": "Adopt Library Fundamentals V1 TS Components for C++17"
2012 # required
2013 # The implementation status of the paper.
2014 "implemented": true
2020 # required
2021 # A sorted list of headers that should provide the FTM. The header
2022 # <version> is automatically added to this list. This list could be
2023 # empty. For example, __cpp_lib_modules is only present in version.
2024 # Requiring the field makes it easier to detect accidental omission.
2025 "headers": [
2026 "any"
2029 # optional, required when libcxx_guard is present
2030 # This field is used only to generate the unit tests for the
2031 # feature-test macros. It can't depend on macros defined in <__config>
2032 # because the `test/std/` parts of the test suite are intended to be
2033 # portable to any C++ standard library implementation, not just libc++.
2034 # It may depend on
2035 # * macros defined by the compiler itself, or
2036 # * macros generated by CMake.
2037 # In some cases we add also depend on macros defined in
2038 # <__availability>.
2039 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR"
2041 # optional, required when test_suite_guard is present
2042 # This field is used only to guard the feature-test macro in
2043 # <version>. It may be the same as `test_suite_guard`, or it may
2044 # depend on macros defined in <__config>.
2045 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR"
2050 # The JSON data structure.
2051 __data = None
2053 def __init__(self, filename: str):
2054 """Initializes the class with the JSON data in the file 'filename'."""
2055 self.__data = json.load(open(filename))
2057 @functools.cached_property
2058 def std_dialects(self) -> List[str]:
2059 """Returns the C++ dialects avaiable.
2061 The available dialects are based on the 'c++xy' keys found the 'values'
2062 entries in '__data'. So when WG21 starts to feature-test macros for a
2063 future C++ Standard this dialect will automatically be available.
2065 The return value is a sorted list with the C++ dialects used. Since FTM
2066 were added in C++14 the list will not contain C++03 or C++11.
2068 dialects = set()
2069 for feature in self.__data:
2070 keys = feature["values"].keys()
2071 assert len(keys) > 0, "'values' is empty"
2072 dialects |= keys
2074 return sorted(list(dialects))
2076 @functools.cached_property
2077 def standard_ftms(self) -> Dict[str, Dict[str, Any]]:
2078 """Returns the FTM versions per dialect in the Standard.
2080 This function does not use the 'implemented' flag. The output contains
2081 the versions used in the Standard. When a FTM in libc++ is not
2082 implemented according to the Standard to output may opt to show the
2083 expected value.
2085 The result is a dict with the following content
2086 - key: Name of the feature test macro.
2087 - value: A dict with the following content:
2088 * key: The version of the C++ dialect.
2089 * value: The value of the feature-test macro.
2091 return get_ftms(self.__data, self.std_dialects, False)
2093 @functools.cached_property
2094 def implemented_ftms(self) -> Dict[str, Dict[str, Any]]:
2095 """Returns the FTM versions per dialect implemented in libc++.
2097 Unlike `get_std_dialect_versions` this function uses the 'implemented'
2098 flag. This returns the actual implementation status in libc++.
2100 The result is a dict with the following content
2101 - key: Name of the feature test macro.
2102 - value: A dict with the following content:
2103 * key: The version of the C++ dialect.
2104 * value: The value of the feature-test macro. When a feature-test
2105 macro is not implemented its value is None.
2108 return get_ftms(self.__data, self.std_dialects, True)
2111 def main():
2112 produce_version_header()
2113 produce_tests()
2114 produce_docs()
2117 if __name__ == "__main__":
2118 main()