4 from builtins
import range
5 from functools
import reduce
6 from typing
import Any
, Dict
, List
# Needed for python 3.8 compatibility.
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(
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()
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")
48 # ================ ============================================================
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
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
78 # ================ ============================================================
79 feature_test_macros
= [
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",
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},
118 "name": "__cpp_lib_any",
119 "values": {"c++17": 201606},
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",
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_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
211 "libcxx_guard": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
214 "name": "__cpp_lib_bind_back",
217 # "c++26": 202306, # P2714R1 Bind front and back to NTTP callables
219 "headers": ["functional"],
222 "name": "__cpp_lib_bind_front",
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},
235 "name": "__cpp_lib_bitops",
236 "values": {"c++20": 201907},
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},
270 "name": "__cpp_lib_char8_t",
271 "values": {"c++20": 201907},
282 "test_suite_guard": "defined(__cpp_char8_t)",
283 "libcxx_guard": "_LIBCPP_HAS_CHAR8_T",
286 "name": "__cpp_lib_chrono",
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",
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
366 "test_suite_guard": "!defined(_LIBCPP_ABI_VCRUNTIME)",
367 "libcxx_guard": "!defined(_LIBCPP_ABI_VCRUNTIME)",
370 "name": "__cpp_lib_constexpr_numeric",
371 "values": {"c++20": 201911},
372 "headers": ["numeric"],
375 "name": "__cpp_lib_constexpr_string",
376 "values": {"c++20": 201907},
377 "headers": ["string"],
380 "name": "__cpp_lib_constexpr_string_view",
381 "values": {"c++20": 201811},
382 "headers": ["string_view"],
385 "name": "__cpp_lib_constexpr_tuple",
386 "values": {"c++20": 201811},
387 "headers": ["tuple"],
390 "name": "__cpp_lib_constexpr_typeinfo",
391 "values": {"c++23": 202106},
392 "headers": ["typeinfo"],
395 "name": "__cpp_lib_constexpr_utility",
396 "values": {"c++20": 201811},
397 "headers": ["utility"],
400 "name": "__cpp_lib_constexpr_vector",
401 "values": {"c++20": 201907},
402 "headers": ["vector"],
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,
411 "name": "__cpp_lib_containers_ranges",
412 "values": {"c++23": 202202},
428 "name": "__cpp_lib_copyable_function",
429 "values": {"c++26": 202306}, # P2548R6 copyable_function
430 "headers": ["functional"],
431 "unimplemented": True,
434 "name": "__cpp_lib_coroutine",
435 "values": {"c++20": 201902},
436 "headers": ["coroutine"],
439 "name": "__cpp_lib_debugging",
441 "c++26": 202311, # P2546R5 Debugging Support
442 # "c++26": 202403, # P2810R4: is_debugger_present is_replaceable
444 "headers": ["debugging"],
445 "unimplemented": True,
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,
454 "name": "__cpp_lib_destroying_delete",
455 "values": {"c++20": 201806},
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",
461 "name": "__cpp_lib_enable_shared_from_this",
462 "values": {"c++17": 201603},
463 "headers": ["memory"],
466 "name": "__cpp_lib_endian",
467 "values": {"c++20": 201907},
471 "name": "__cpp_lib_erase_if",
472 "values": {"c++20": 202002},
486 "name": "__cpp_lib_exchange_function",
487 "values": {"c++14": 201304},
488 "headers": ["utility"],
491 "name": "__cpp_lib_execution",
492 "values": {"c++17": 201603, "c++20": 201902},
493 "headers": ["execution"],
494 "unimplemented": True,
497 "name": "__cpp_lib_expected",
498 "values": {"c++23": 202211},
499 "headers": ["expected"],
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",
509 "name": "__cpp_lib_format",
512 # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types
513 # "c++26": 202306, P2637R3 Member Visit (implemented)
514 # "c++26": 202311, P2918R2 Runtime format strings II (implemented)
516 # Note these three papers are adopted at the June 2023 meeting and have sequential numbering
517 # 202304 P2510R3 Formatting pointers (Implemented)
518 # 202305 P2757R3 Type-checking format args
519 # 202306 P2637R3 Member Visit
520 "headers": ["format"],
523 "name": "__cpp_lib_format_path",
524 "values": {"c++26": 202403}, # P2845R8: Formatting of std::filesystem::path
525 "headers": ["filesystem"],
526 "unimplemented": True,
529 "name": "__cpp_lib_format_ranges",
530 "values": {"c++23": 202207},
531 "headers": ["format"],
534 "name": "__cpp_lib_format_uchar",
536 "c++20": 202311 # DR P2909R4 Fix formatting of code units as integers
539 "format" # TODO verify this entry since the paper was underspecified.
543 "name": "__cpp_lib_formatters",
544 "values": {"c++23": 202302},
545 "headers": ["stacktrace", "thread"],
546 "unimplemented": True,
549 "name": "__cpp_lib_forward_like",
550 "values": {"c++23": 202207},
551 "headers": ["utility"],
554 "name": "__cpp_lib_freestanding_algorithm",
556 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
558 "headers": ["algorithm"],
559 "unimplemented": True,
562 "name": "__cpp_lib_freestanding_array",
564 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
566 "headers": ["array"],
567 "unimplemented": True,
570 "name": "__cpp_lib_freestanding_cstring",
572 "c++26": 202306 # P2338R4 Freestanding Library: Character primitives and the C library
573 # 202311 # P2407R5 Freestanding Library: Partial Classes
575 "headers": ["cstring"],
576 "unimplemented": True,
579 "name": "__cpp_lib_freestanding_expected",
581 "c++26": 202311 # P2833R2 Freestanding Library: inout expected span
583 "headers": ["expected"],
584 "unimplemented": True,
587 "name": "__cpp_lib_freestanding_mdspan",
589 "c++26": 202311 # P2833R2 Freestanding Library: inout expected span
591 "headers": ["mdspan"],
592 "unimplemented": True,
595 "name": "__cpp_lib_freestanding_optional",
597 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
599 "headers": ["optional"],
600 "unimplemented": True,
603 "name": "__cpp_lib_freestanding_string_view",
605 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
607 "headers": ["string_view"],
608 "unimplemented": True,
611 "name": "__cpp_lib_freestanding_variant",
613 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes
615 "headers": ["variant"],
616 "unimplemented": True,
619 "name": "__cpp_lib_fstream_native_handle",
620 "values": {"c++26": 202306}, # P1759R6 Native handles and file streams
621 "headers": ["fstream"],
622 "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION)",
623 "libcxx_guard": "_LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION",
626 "name": "__cpp_lib_function_ref",
628 "c++26": 202306 # P0792R14 function_ref: a type-erased callable reference
630 "headers": ["functional"],
631 "unimplemented": True,
634 "name": "__cpp_lib_gcd_lcm",
635 "values": {"c++17": 201606},
636 "headers": ["numeric"],
639 "name": "__cpp_lib_generate_random",
640 "values": {"c++26": 202403}, # P1068R11: Vector API for random number generation
641 "headers": ["random"],
642 "unimplemented": True,
645 "name": "__cpp_lib_generic_associative_lookup",
646 "values": {"c++14": 201304},
647 "headers": ["map", "set"],
650 "name": "__cpp_lib_generic_unordered_lookup",
651 "values": {"c++20": 201811},
652 "headers": ["unordered_map", "unordered_set"],
655 "name": "__cpp_lib_hardware_interference_size",
656 "values": {"c++17": 201703},
657 "test_suite_guard": "!defined(_LIBCPP_VERSION) || (defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE))",
658 "libcxx_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)",
662 "name": "__cpp_lib_has_unique_object_representations",
663 "values": {"c++17": 201606},
664 "headers": ["type_traits"],
667 "name": "__cpp_lib_hazard_pointer",
668 "values": {"c++26": 202306}, # P2530R3 Hazard Pointers for C++26
670 "hazard_pointer" # TODO verify this entry since the paper was underspecified.
672 "unimplemented": True,
675 "name": "__cpp_lib_hypot",
676 "values": {"c++17": 201603},
677 "headers": ["cmath"],
680 "name": "__cpp_lib_incomplete_container_elements",
681 "values": {"c++17": 201505},
682 "headers": ["forward_list", "list", "vector"],
685 "name": "__cpp_lib_inplace_vector",
686 "values": {"c++26": 202406}, # P0843R14 inplace_vector
687 "headers": ["inplace_vector"],
688 "unimplemented": True,
691 "name": "__cpp_lib_int_pow2",
692 "values": {"c++20": 202002},
696 "name": "__cpp_lib_integer_comparison_functions",
697 "values": {"c++20": 202002},
698 "headers": ["utility"],
701 "name": "__cpp_lib_integer_sequence",
702 "values": {"c++14": 201304},
703 "headers": ["utility"],
706 "name": "__cpp_lib_integral_constant_callable",
707 "values": {"c++14": 201304},
708 "headers": ["type_traits"],
711 "name": "__cpp_lib_interpolate",
712 "values": {"c++20": 201902},
713 "headers": ["cmath", "numeric"],
716 "name": "__cpp_lib_invoke",
717 "values": {"c++17": 201411},
718 "headers": ["functional"],
721 "name": "__cpp_lib_invoke_r",
722 "values": {"c++23": 202106},
723 "headers": ["functional"],
726 "name": "__cpp_lib_ios_noreplace",
727 "values": {"c++23": 202207},
731 "name": "__cpp_lib_is_aggregate",
732 "values": {"c++17": 201703},
733 "headers": ["type_traits"],
736 "name": "__cpp_lib_is_constant_evaluated",
737 "values": {"c++20": 201811},
738 "headers": ["type_traits"],
741 "name": "__cpp_lib_is_final",
742 "values": {"c++14": 201402},
743 "headers": ["type_traits"],
746 "name": "__cpp_lib_is_implicit_lifetime",
747 "values": {"c++23": 202302},
748 "headers": ["type_traits"],
749 "test_suite_guard": "__has_builtin(__builtin_is_implicit_lifetime)",
750 "libcxx_guard": "__has_builtin(__builtin_is_implicit_lifetime)",
753 "name": "__cpp_lib_is_invocable",
754 "values": {"c++17": 201703},
755 "headers": ["type_traits"],
758 "name": "__cpp_lib_is_layout_compatible",
759 "values": {"c++20": 201907},
760 "headers": ["type_traits"],
761 "unimplemented": True,
764 "name": "__cpp_lib_is_nothrow_convertible",
765 "values": {"c++20": 201806},
766 "headers": ["type_traits"],
769 "name": "__cpp_lib_is_null_pointer",
770 "values": {"c++14": 201309},
771 "headers": ["type_traits"],
774 "name": "__cpp_lib_is_pointer_interconvertible",
775 "values": {"c++20": 201907},
776 "headers": ["type_traits"],
777 "unimplemented": True,
780 "name": "__cpp_lib_is_scoped_enum",
781 "values": {"c++23": 202011},
782 "headers": ["type_traits"],
785 "name": "__cpp_lib_is_swappable",
786 "values": {"c++17": 201603},
787 "headers": ["type_traits"],
790 "name": "__cpp_lib_is_virtual_base_of",
792 "c++26": 202406 # P2985R0 A type trait for detecting virtual base classes
794 "headers": ["type_traits"],
795 "test_suite_guard": "__has_builtin(__builtin_is_virtual_base_of)",
796 "libcxx_guard": "__has_builtin(__builtin_is_virtual_base_of)",
799 "name": "__cpp_lib_is_within_lifetime",
800 # Note this name was changed from "__cpp_lib_within_lifetime" when the paper was adopted
801 # https://github.com/cplusplus/draft/commit/0facada4cadd97e1ba15bfaea76a804f1dc5c309
803 "c++26": 202306 # P2641R4 Checking if a union alternative is active
805 "headers": ["type_traits"],
806 "unimplemented": True,
809 "name": "__cpp_lib_jthread",
810 "values": {"c++20": 201911},
811 "headers": ["stop_token", "thread"],
812 "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
813 "libcxx_guard": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
816 "name": "__cpp_lib_latch",
817 "values": {"c++20": 201907},
818 "headers": ["latch"],
819 "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
820 "libcxx_guard": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
823 "name": "__cpp_lib_launder",
824 "values": {"c++17": 201606},
828 "name": "__cpp_lib_linalg",
830 "c++26": 202311 # P1673 A free function linear algebra interface based on the BLAS
832 "headers": ["linalg"],
833 "unimplemented": True,
836 "name": "__cpp_lib_list_remove_return_type",
837 "values": {"c++20": 201806},
838 "headers": ["forward_list", "list"],
841 "name": "__cpp_lib_logical_traits",
842 "values": {"c++17": 201510},
843 "headers": ["type_traits"],
846 "name": "__cpp_lib_make_from_tuple",
847 "values": {"c++17": 201606},
848 "headers": ["tuple"],
851 "name": "__cpp_lib_make_reverse_iterator",
852 "values": {"c++14": 201402},
853 "headers": ["iterator"],
856 "name": "__cpp_lib_make_unique",
857 "values": {"c++14": 201304},
858 "headers": ["memory"],
861 "name": "__cpp_lib_map_try_emplace",
862 "values": {"c++17": 201411},
866 "name": "__cpp_lib_math_constants",
867 "values": {"c++20": 201907},
868 "headers": ["numbers"],
871 "name": "__cpp_lib_math_special_functions",
872 "values": {"c++17": 201603},
873 "headers": ["cmath"],
874 "unimplemented": True,
877 "name": "__cpp_lib_mdspan",
880 "c++26": 202406, # P2389R2 dextents Index Type Parameter
882 "headers": ["mdspan"],
885 "name": "__cpp_lib_memory_resource",
886 "values": {"c++17": 201603},
887 "headers": ["memory_resource"],
888 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",
889 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",
892 "name": "__cpp_lib_modules",
893 "values": {"c++23": 202207},
897 "name": "__cpp_lib_move_iterator_concept",
898 "values": {"c++20": 202207},
899 "headers": ["iterator"],
902 "name": "__cpp_lib_move_only_function",
903 "values": {"c++23": 202110},
904 "headers": ["functional"],
905 "unimplemented": True,
908 "name": "__cpp_lib_node_extract",
909 "values": {"c++17": 201606},
910 "headers": ["map", "set", "unordered_map", "unordered_set"],
913 "name": "__cpp_lib_nonmember_container_access",
914 "values": {"c++17": 201411},
931 "name": "__cpp_lib_not_fn",
934 # "c++26": 202306, # P2714R1 Bind front and back to NTTP callables
936 "headers": ["functional"],
939 "name": "__cpp_lib_null_iterators",
940 "values": {"c++14": 201304},
941 "headers": ["iterator"],
944 "name": "__cpp_lib_optional",
947 "c++20": 202106, # P2231R1 Missing constexpr in std::optional and std::variant
948 "c++23": 202110, # P0798R8 Monadic operations for std::optional + LWG3621 Remove feature-test macro __cpp_lib_monadic_optional
950 "headers": ["optional"],
953 "name": "__cpp_lib_optional_range_support",
954 "values": {"c++26": 202406}, # P3168R2 Give std::optional Range Support
955 "headers": ["optional"],
956 "unimplemented": True,
959 "name": "__cpp_lib_out_ptr",
962 "c++26": 202311, # P2833R2 Freestanding Library: inout expected span
964 "headers": ["memory"],
967 "name": "__cpp_lib_parallel_algorithm",
968 "values": {"c++17": 201603},
969 "headers": ["algorithm", "numeric"],
970 "unimplemented": True,
973 "name": "__cpp_lib_philox_engine",
976 }, # P2075R6 Philox as an extension of the C++ RNG engines
977 # Note the paper mentions 202310L as value, which differs from the typical procedure.
978 "headers": ["random"],
979 "unimplemented": True,
982 "name": "__cpp_lib_polymorphic_allocator",
983 "values": {"c++20": 201902},
984 "headers": ["memory_resource"],
985 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",
986 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",
989 "name": "__cpp_lib_print",
992 # "c++26": 202403, # P3107R5: Permit an efficient implementation of std::print
993 # "c++26": 202406, # P3235R3 std::print more types faster with less memory
995 "headers": ["ostream", "print"],
998 "name": "__cpp_lib_quoted_string_io",
999 "values": {"c++14": 201304},
1000 "headers": ["iomanip"],
1001 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_LOCALIZATION",
1002 "libcxx_guard": "_LIBCPP_HAS_LOCALIZATION",
1005 "name": "__cpp_lib_ranges",
1007 "c++20": 202110, # P2415R2 What is a view?
1008 "c++23": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts (implemented as a DR against C++20)
1010 "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
1013 "name": "__cpp_lib_ranges_as_const",
1015 "c++23": 202207 # P2278R4 cbegin should always return a constant iterator
1016 # 202311 # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility
1018 "headers": ["ranges"],
1019 "unimplemented": True,
1022 "name": "__cpp_lib_ranges_as_rvalue",
1023 "values": {"c++23": 202207},
1024 "headers": ["ranges"],
1027 "name": "__cpp_lib_ranges_chunk",
1028 "values": {"c++23": 202202},
1029 "headers": ["ranges"],
1030 "unimplemented": True,
1033 "name": "__cpp_lib_ranges_chunk_by",
1034 "values": {"c++23": 202202},
1035 "headers": ["ranges"],
1038 "name": "__cpp_lib_ranges_concat",
1039 "values": {"c++26": 202403}, # P2542R8: views::concat
1040 "headers": ["ranges"],
1041 "unimplemented": True,
1044 "name": "__cpp_lib_ranges_contains",
1045 "values": {"c++23": 202207},
1046 "headers": ["algorithm"],
1049 "name": "__cpp_lib_ranges_find_last",
1050 "values": {"c++23": 202207},
1051 "headers": ["algorithm"],
1054 "name": "__cpp_lib_ranges_iota",
1055 "values": {"c++23": 202202},
1056 "headers": ["numeric"],
1057 "unimplemented": True,
1060 "name": "__cpp_lib_ranges_join_with",
1061 "values": {"c++23": 202202},
1062 "headers": ["ranges"],
1063 "unimplemented": True,
1066 "name": "__cpp_lib_ranges_repeat",
1067 "values": {"c++23": 202207},
1068 "headers": ["ranges"],
1071 "name": "__cpp_lib_ranges_slide",
1072 "values": {"c++23": 202202},
1073 "headers": ["ranges"],
1074 "unimplemented": True,
1077 "name": "__cpp_lib_ranges_starts_ends_with",
1078 "values": {"c++23": 202106},
1079 "headers": ["algorithm"],
1082 "name": "__cpp_lib_ranges_to_container",
1083 "values": {"c++23": 202202},
1084 "headers": ["ranges"],
1087 "name": "__cpp_lib_ranges_zip",
1088 "values": {"c++23": 202110},
1089 "headers": ["ranges", "tuple", "utility"],
1090 "unimplemented": True,
1093 "name": "__cpp_lib_ratio",
1094 "values": {"c++26": 202306}, # P2734R0 Adding the new SI prefixes
1095 "headers": ["ratio"],
1098 "name": "__cpp_lib_raw_memory_algorithms",
1099 "values": {"c++17": 201606},
1100 "headers": ["memory"],
1103 "name": "__cpp_lib_rcu",
1104 "values": {"c++26": 202306}, # P2545R4 Read-Copy Update (RCU)
1106 "rcu" # TODO verify this entry since the paper was underspecified.
1108 "unimplemented": True,
1111 "name": "__cpp_lib_reference_from_temporary",
1112 "values": {"c++23": 202202},
1113 "headers": ["type_traits"],
1114 "unimplemented": True,
1117 "name": "__cpp_lib_reference_wrapper",
1118 "values": {"c++26": 202403}, # P2944R3: Comparisons for reference_wrapper
1119 "headers": ["functional"],
1122 "name": "__cpp_lib_remove_cvref",
1123 "values": {"c++20": 201711},
1124 "headers": ["type_traits"],
1127 "name": "__cpp_lib_result_of_sfinae",
1128 "values": {"c++14": 201210},
1129 "headers": ["functional", "type_traits"],
1132 "name": "__cpp_lib_robust_nonmodifying_seq_ops",
1133 "values": {"c++14": 201304},
1134 "headers": ["algorithm"],
1137 "name": "__cpp_lib_sample",
1138 "values": {"c++17": 201603},
1139 "headers": ["algorithm"],
1142 "name": "__cpp_lib_saturation_arithmetic",
1143 "values": {"c++26": 202311}, # P0543R3 Saturation arithmetic
1144 "headers": ["numeric"],
1147 "name": "__cpp_lib_scoped_lock",
1148 "values": {"c++17": 201703},
1149 "headers": ["mutex"],
1150 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS",
1151 "libcxx_guard": "_LIBCPP_HAS_THREADS",
1154 "name": "__cpp_lib_semaphore",
1155 "values": {"c++20": 201907},
1156 "headers": ["semaphore"],
1157 "test_suite_guard": "!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
1158 "libcxx_guard": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
1161 "name": "__cpp_lib_senders",
1162 "values": {"c++26": 202406}, # P2300R10 std::execution
1163 "headers": ["execution"],
1164 "unimplemented": True,
1167 "name": "__cpp_lib_shared_mutex",
1168 "values": {"c++17": 201505},
1169 "headers": ["shared_mutex"],
1170 "test_suite_guard": "_LIBCPP_HAS_THREADS",
1171 "libcxx_guard": "_LIBCPP_HAS_THREADS",
1174 "name": "__cpp_lib_shared_ptr_arrays",
1175 "values": {"c++17": 201611, "c++20": 201707},
1176 "headers": ["memory"],
1179 "name": "__cpp_lib_shared_ptr_weak_type",
1180 "values": {"c++17": 201606},
1181 "headers": ["memory"],
1184 "name": "__cpp_lib_shared_timed_mutex",
1185 "values": {"c++14": 201402},
1186 "headers": ["shared_mutex"],
1187 "test_suite_guard": "_LIBCPP_HAS_THREADS",
1188 "libcxx_guard": "_LIBCPP_HAS_THREADS",
1191 "name": "__cpp_lib_shift",
1192 "values": {"c++20": 201806},
1193 "headers": ["algorithm"],
1196 "name": "__cpp_lib_smart_ptr_for_overwrite",
1197 "values": {"c++20": 202002},
1198 "headers": ["memory"],
1201 "name": "__cpp_lib_smart_ptr_owner_equality",
1203 "c++26": 202306 # P1901R2 Enabling the Use of weak_ptr as Keys in Unordered Associative Containers
1205 "headers": ["memory"],
1206 "unimplemented": True,
1209 "name": "__cpp_lib_source_location",
1210 "values": {"c++20": 201907},
1211 "headers": ["source_location"],
1214 "name": "__cpp_lib_span",
1217 # "c++26": 202311, # P2821R5 span.at()
1218 # 202311 # P2833R2 Freestanding Library: inout expected span
1220 "headers": ["span"],
1223 "name": "__cpp_lib_span_at",
1224 "values": {"c++26": 202311}, # P2821R3 span.at()
1225 "headers": ["span"],
1228 "name": "__cpp_lib_span_initializer_list",
1229 "values": {"c++26": 202311}, # P2447R6 std::span over an initializer list
1230 "headers": ["span"],
1233 "name": "__cpp_lib_spanstream",
1234 "values": {"c++23": 202106},
1235 "headers": ["spanstream"],
1236 "unimplemented": True,
1239 "name": "__cpp_lib_ssize",
1240 "values": {"c++20": 201902},
1241 "headers": ["iterator"],
1244 "name": "__cpp_lib_sstream_from_string_view",
1246 "c++26": 202306 # P2495R3 Interfacing stringstreams with string_view
1248 "headers": ["sstream"],
1251 "name": "__cpp_lib_stacktrace",
1252 "values": {"c++23": 202011},
1253 "headers": ["stacktrace"],
1254 "unimplemented": True,
1257 "name": "__cpp_lib_starts_ends_with",
1258 "values": {"c++20": 201711},
1259 "headers": ["string", "string_view"],
1262 "name": "__cpp_lib_stdatomic_h",
1263 "values": {"c++23": 202011},
1264 "headers": ["stdatomic.h"],
1267 "name": "__cpp_lib_string_contains",
1268 "values": {"c++23": 202011},
1269 "headers": ["string", "string_view"],
1272 "name": "__cpp_lib_string_resize_and_overwrite",
1273 "values": {"c++23": 202110},
1274 "headers": ["string"],
1277 "name": "__cpp_lib_string_udls",
1278 "values": {"c++14": 201304},
1279 "headers": ["string"],
1282 "name": "__cpp_lib_string_view",
1286 "c++26": 202403, # P2591R5: Concatenation of strings and string views
1288 "headers": ["string", "string_view"],
1291 "name": "__cpp_lib_submdspan",
1293 "c++26": 202306, # P2630R4: submdspan
1294 # "c++26": 202403, # P2642R6: Padded mdspan layouts
1296 "headers": ["mdspan"],
1297 "unimplemented": True,
1300 "name": "__cpp_lib_syncbuf",
1301 "values": {"c++20": 201803},
1302 "headers": ["syncstream"],
1303 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)",
1304 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)",
1307 "name": "__cpp_lib_text_encoding",
1309 "c++26": 202306 # P1885R12 Naming Text Encodings to Demystify Them
1311 "headers": ["text_encoding"],
1312 "unimplemented": True,
1315 "name": "__cpp_lib_three_way_comparison",
1316 "values": {"c++20": 201907},
1317 "headers": ["compare"],
1320 "name": "__cpp_lib_to_address",
1321 "values": {"c++20": 201711},
1322 "headers": ["memory"],
1325 "name": "__cpp_lib_to_array",
1326 "values": {"c++20": 201907},
1327 "headers": ["array"],
1330 "name": "__cpp_lib_to_chars",
1333 "c++26": 202306, # P2497R0 Testing for success or failure of <charconv> functions
1335 "headers": ["charconv"],
1336 "unimplemented": True,
1339 "name": "__cpp_lib_to_string",
1340 "values": {"c++26": 202306}, # P2587R3 to_string or not to_string
1341 "headers": ["string"],
1342 "unimplemented": True,
1345 "name": "__cpp_lib_to_underlying",
1346 "values": {"c++23": 202102},
1347 "headers": ["utility"],
1350 "name": "__cpp_lib_transformation_trait_aliases",
1351 "values": {"c++14": 201304},
1352 "headers": ["type_traits"],
1355 "name": "__cpp_lib_transparent_operators",
1356 "values": {"c++14": 201210, "c++17": 201510},
1357 "headers": ["functional", "memory"],
1360 "name": "__cpp_lib_tuple_element_t",
1361 "values": {"c++14": 201402},
1362 "headers": ["tuple"],
1365 "name": "__cpp_lib_tuple_like",
1367 "c++23": 202207, # P2165R4 Compatibility between tuple, pair and tuple-like objects
1368 "c++26": 202311, # P2819R2 Add tuple protocol to complex (implemented)
1370 "headers": ["map", "tuple", "unordered_map", "utility"],
1371 "unimplemented": True,
1374 "name": "__cpp_lib_tuples_by_type",
1375 "values": {"c++14": 201304},
1376 "headers": ["tuple", "utility"],
1379 "name": "__cpp_lib_type_identity",
1380 "values": {"c++20": 201806},
1381 "headers": ["type_traits"],
1384 "name": "__cpp_lib_type_trait_variable_templates",
1385 "values": {"c++17": 201510},
1386 "headers": ["type_traits"],
1389 "name": "__cpp_lib_uncaught_exceptions",
1390 "values": {"c++17": 201411},
1391 "headers": ["exception"],
1394 "name": "__cpp_lib_unordered_map_try_emplace",
1395 "values": {"c++17": 201411},
1396 "headers": ["unordered_map"],
1399 "name": "__cpp_lib_unreachable",
1400 "values": {"c++23": 202202},
1401 "headers": ["utility"],
1404 "name": "__cpp_lib_unwrap_ref",
1405 "values": {"c++20": 201811},
1406 "headers": ["functional"],
1409 "name": "__cpp_lib_variant",
1411 "c++17": 202102, # std::visit for classes derived from std::variant
1412 "c++20": 202106, # P2231R1 Missing constexpr in std::optional and std::variant
1413 "c++26": 202306, # P2637R3 Member visit
1415 "headers": ["variant"],
1418 "name": "__cpp_lib_void_t",
1419 "values": {"c++17": 201411},
1420 "headers": ["type_traits"],
1425 assert feature_test_macros
== sorted(feature_test_macros
, key
=lambda tc
: tc
["name"])
1426 for tc
in feature_test_macros
:
1427 assert tc
["headers"] == sorted(tc
["headers"]), tc
1428 assert ("libcxx_guard" in tc
) == ("test_suite_guard" in tc
), tc
1429 valid_keys
= ["name", "values", "headers", "libcxx_guard", "test_suite_guard", "unimplemented"]
1430 assert all(key
in valid_keys
for key
in tc
.keys()), tc
1432 # Map from each header to the Lit annotations that should be used for
1433 # tests that include that header.
1435 # For example, when threads are not supported, any test that includes
1436 # <thread> should be marked as UNSUPPORTED, because including <thread>
1437 # is a hard error in that case.
1439 "barrier": ["UNSUPPORTED: no-threads"],
1440 "filesystem": ["UNSUPPORTED: no-filesystem"],
1441 "fstream": ["UNSUPPORTED: no-localization"],
1442 "iomanip": ["UNSUPPORTED: no-localization"],
1443 "ios": ["UNSUPPORTED: no-localization"],
1444 "iostream": ["UNSUPPORTED: no-localization"],
1445 "istream": ["UNSUPPORTED: no-localization"],
1446 "latch": ["UNSUPPORTED: no-threads"],
1447 "locale": ["UNSUPPORTED: no-localization"],
1448 "mutex": ["UNSUPPORTED: no-threads"],
1449 "ostream": ["UNSUPPORTED: no-localization"],
1450 "print": ["UNSUPPORTED: no-filesystem"],
1451 "regex": ["UNSUPPORTED: no-localization"],
1452 "semaphore": ["UNSUPPORTED: no-threads"],
1453 "shared_mutex": ["UNSUPPORTED: no-threads"],
1454 "sstream": ["UNSUPPORTED: no-localization"],
1455 "syncstream": ["UNSUPPORTED: no-localization"],
1456 "stdatomic.h": ["UNSUPPORTED: no-threads"],
1457 "stop_token": ["UNSUPPORTED: no-threads"],
1458 "thread": ["UNSUPPORTED: no-threads"],
1462 def get_std_dialects():
1463 std_dialects
= ["c++14", "c++17", "c++20", "c++23", "c++26"]
1464 return list(std_dialects
)
1467 def get_first_std(d
):
1468 for s
in get_std_dialects():
1474 def get_last_std(d
):
1475 rev_dialects
= get_std_dialects()
1476 rev_dialects
.reverse()
1477 for s
in rev_dialects
:
1483 def get_std_before(d
, std
):
1484 std_dialects
= get_std_dialects()
1485 candidates
= std_dialects
[0 : std_dialects
.index(std
)]
1486 candidates
.reverse()
1487 for cand
in candidates
:
1488 if cand
in d
.keys():
1493 def get_value_before(d
, std
):
1494 new_std
= get_std_before(d
, std
)
1500 def get_for_std(d
, std
):
1501 # This catches the C++11 case for which there should be no defined feature
1503 std_dialects
= get_std_dialects()
1504 if std
not in std_dialects
:
1506 # Find the value for the newest C++ dialect between C++14 and std
1507 std_list
= list(std_dialects
[0 : std_dialects
.index(std
) + 1])
1515 def get_std_number(std
):
1516 return std
.replace("c++", "")
1520 Functions to produce the <version> header
1524 def produce_macros_definition_for_std(std
):
1527 for tc
in feature_test_macros
:
1528 if std
not in tc
["values"]:
1531 if "test_suite_guard" in tc
.keys():
1532 result
+= "# if %s\n" % tc
["libcxx_guard"]
1534 if get_value_before(tc
["values"], std
) is not None:
1535 assert "test_suite_guard" not in tc
.keys()
1536 result
+= "# undef %s\n" % tc
["name"]
1537 line
= "#%sdefine %s" % ((" " * inner_indent
), tc
["name"])
1538 line
+= " " * (indent
- len(line
))
1539 line
+= " %sL" % tc
["values"][std
]
1540 if "unimplemented" in tc
.keys():
1544 if "test_suite_guard" in tc
.keys():
1545 result
+= "# endif\n"
1546 return result
.strip()
1549 def produce_macros_definitions():
1550 macro_definition_template
= """#if _LIBCPP_STD_VER >= {std_number}
1554 macros_definitions
= []
1555 for std
in get_std_dialects():
1556 macros_definitions
.append(
1557 macro_definition_template
.format(
1558 std_number
=get_std_number(std
),
1559 macro_definition
=produce_macros_definition_for_std(std
),
1563 return "\n\n".join(macros_definitions
)
1567 """Yield successive n-sized chunks from l."""
1568 for i
in range(0, len(l
), n
):
1572 def produce_version_synopsis():
1574 header_indent
= 56 + len("20XXYYL ")
1577 def indent_to(s
, val
):
1580 s
+= " " * (val
- len(s
))
1583 line
= indent_to("Macro name", indent
) + "Value"
1584 line
= indent_to(line
, header_indent
) + "Headers"
1585 result
+= line
+ "\n"
1586 for tc
in feature_test_macros
:
1587 prev_defined_std
= get_last_std(tc
["values"])
1588 line
= "{name: <{indent}}{value}L ".format(
1589 name
=tc
["name"], indent
=indent
, value
=tc
["values"][prev_defined_std
]
1591 headers
= list(tc
["headers"])
1592 headers
.remove("version")
1593 for chunk
in chunks(headers
, 3):
1594 line
= indent_to(line
, header_indent
)
1595 chunk
= ["<%s>" % header
for header
in chunk
]
1596 line
+= " ".join(chunk
)
1601 prev_defined_std
= get_std_before(tc
["values"], prev_defined_std
)
1602 if prev_defined_std
is None:
1604 result
+= "%s%sL // %s\n" % (
1605 indent_to("", indent
),
1606 tc
["values"][prev_defined_std
],
1607 prev_defined_std
.replace("c++", "C++"),
1612 def produce_version_header():
1613 template
= """// -*- C++ -*-
1614 //===----------------------------------------------------------------------===//
1616 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1617 // See https://llvm.org/LICENSE.txt for license information.
1618 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1620 //===----------------------------------------------------------------------===//
1622 #ifndef _LIBCPP_VERSIONH
1623 #define _LIBCPP_VERSIONH
1634 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1635 # pragma GCC system_header
1644 #endif // _LIBCPP_VERSIONH
1647 version_str
= template
.format(
1648 synopsis
=produce_version_synopsis().strip(),
1649 cxx_macros
=produce_macros_definitions(),
1651 version_header_path
= os
.path
.join(include_path
, "version")
1652 with
open(version_header_path
, "w", newline
="\n") as f
:
1653 f
.write(version_str
)
1657 Functions to produce test files
1663 # error "{name} should not be defined before {std_first}"
1666 "test_suite_guard": """
1667 # if {test_suite_guard}
1669 # error "{name} should be defined in {std}"
1671 # if {name} != {value}
1672 # error "{name} should have the value {value} in {std}"
1676 # error "{name} should not be defined when the requirement '{test_suite_guard}' is not met!"
1680 "unimplemented": """
1681 # if !defined(_LIBCPP_VERSION)
1683 # error "{name} should be defined in {std}"
1685 # if {name} != {value}
1686 # error "{name} should have the value {value} in {std}"
1688 # else // _LIBCPP_VERSION
1690 # error "{name} should not be defined because it is unimplemented in libc++!"
1696 # error "{name} should be defined in {std}"
1698 # if {name} != {value}
1699 # error "{name} should have the value {value} in {std}"
1705 def generate_std_test(test_list
, std
):
1707 for tc
in test_list
:
1708 val
= get_for_std(tc
["values"], std
)
1712 result
+= test_types
["undefined"].format(
1713 name
=tc
["name"], std_first
=get_first_std(tc
["values"])
1715 elif "unimplemented" in tc
.keys():
1716 result
+= test_types
["unimplemented"].format(
1717 name
=tc
["name"], value
=val
, std
=std
1719 elif "test_suite_guard" in tc
.keys():
1720 result
+= test_types
["test_suite_guard"].format(
1724 test_suite_guard
=tc
["test_suite_guard"],
1727 result
+= test_types
["defined"].format(name
=tc
["name"], value
=val
, std
=std
)
1728 return result
.strip()
1731 def generate_std_tests(test_list
):
1732 std_tests_template
= """#if TEST_STD_VER < {first_std_number}
1738 #elif TEST_STD_VER > {penultimate_std_number}
1742 #endif // TEST_STD_VER > {penultimate_std_number}"""
1744 std_dialects
= get_std_dialects()
1746 other_std_tests
= []
1747 for std
in std_dialects
[:-1]:
1748 other_std_tests
.append("#elif TEST_STD_VER == " + get_std_number(std
))
1749 other_std_tests
.append(generate_std_test(test_list
, std
))
1751 std_tests
= std_tests_template
.format(
1752 first_std_number
=get_std_number(std_dialects
[0]),
1753 pre_std_test
=generate_std_test(test_list
, "c++11"),
1754 other_std_tests
="\n\n".join(other_std_tests
),
1755 penultimate_std_number
=get_std_number(std_dialects
[-2]),
1756 last_std_test
=generate_std_test(test_list
, std_dialects
[-1]),
1762 def generate_synopsis(test_list
):
1763 max_name_len
= max([len(tc
["name"]) for tc
in test_list
])
1764 indent
= max_name_len
+ 8
1766 def mk_line(prefix
, suffix
):
1767 return "{prefix: <{max_len}}{suffix}\n".format(
1768 prefix
=prefix
, suffix
=suffix
, max_len
=indent
1772 result
+= mk_line("/* Constant", "Value")
1773 for tc
in test_list
:
1774 prefix
= " %s" % tc
["name"]
1775 for std
in [s
for s
in get_std_dialects() if s
in tc
["values"].keys()]:
1777 prefix
, "%sL [%s]" % (tc
["values"][std
], std
.replace("c++", "C++"))
1784 def produce_tests():
1785 headers
= set([h
for tc
in feature_test_macros
for h
in tc
["headers"]])
1787 test_list
= [tc
for tc
in feature_test_macros
if h
in tc
["headers"]]
1788 if not has_header(h
):
1789 for tc
in test_list
:
1790 assert "unimplemented" in tc
.keys()
1792 markup
= "\n".join("// " + tag
for tag
in lit_markup
.get(h
, []))
1793 test_body
= """//===----------------------------------------------------------------------===//
1795 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1796 // See https://llvm.org/LICENSE.txt for license information.
1797 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1799 //===----------------------------------------------------------------------===//
1801 // WARNING: This test was generated by {script_name}
1802 // and should not be edited manually.
1808 // Test the feature test macros defined by <{header}>
1813 #include "test_macros.h"
1818 script_name
=script_name
,
1820 markup
=("\n{}\n".format(markup
) if markup
else ""),
1821 synopsis
=generate_synopsis(test_list
),
1822 cxx_tests
=generate_std_tests(test_list
),
1824 test_name
= "{header}.version.compile.pass.cpp".format(header
=h
)
1825 out_path
= os
.path
.join(macro_test_path
, test_name
)
1826 with
open(out_path
, "w", newline
="\n") as f
:
1831 Produce documentation for the feature test macros
1835 def make_widths(grid
):
1837 for i
in range(0, len(grid
[0])):
1838 cell_width
= 2 + max(
1839 reduce(lambda x
, y
: x
+ y
, [[len(row
[i
])] for row
in grid
], [])
1841 widths
+= [cell_width
]
1845 def create_table(grid
, indent
):
1846 indent_str
= " " * indent
1847 col_widths
= make_widths(grid
)
1848 result
= [indent_str
+ add_divider(col_widths
, 2)]
1850 for row_i
in range(0, len(grid
)):
1852 line
= indent_str
+ " ".join(
1853 [pad_cell(row
[i
], col_widths
[i
]) for i
in range(0, len(row
))]
1855 result
.append(line
.rstrip())
1856 if row_i
== len(grid
) - 1:
1858 if row
[0].startswith("**"):
1860 separator
= indent_str
+ add_divider(col_widths
, header_flag
)
1861 result
.append(separator
.rstrip())
1863 return "\n".join(result
)
1866 def add_divider(widths
, header_flag
):
1867 if header_flag
== 3:
1868 return "=".join(["=" * w
for w
in widths
])
1869 if header_flag
== 2:
1870 return " ".join(["=" * w
for w
in widths
])
1871 if header_flag
== 1:
1872 return "-".join(["-" * w
for w
in widths
])
1874 return " ".join(["-" * w
for w
in widths
])
1877 def pad_cell(s
, length
, left_align
=True):
1878 padding
= (length
- len(s
)) * " "
1882 def get_status_table():
1883 table
= [["Macro Name", "Value"]]
1884 for std
in get_std_dialects():
1885 table
+= [["**" + std
.replace("c++", "C++") + "**", ""]]
1886 for tc
in feature_test_macros
:
1887 if std
not in tc
["values"].keys():
1889 value
= "``%sL``" % tc
["values"][std
]
1890 if "unimplemented" in tc
.keys():
1891 value
= "*unimplemented*"
1892 table
+= [["``%s``" % tc
["name"], value
]]
1897 doc_str
= """.. _FeatureTestMacroTable:
1899 ==========================
1900 Feature Test Macro Support
1901 ==========================
1909 This file documents the feature test macros currently supported by libc++.
1916 .. table:: Current Status
1917 :name: feature-status-table
1923 status_tables
=create_table(get_status_table(), 4)
1926 table_doc_path
= os
.path
.join(docs_path
, "FeatureTestMacroTable.rst")
1927 with
open(table_doc_path
, "w", newline
="\n") as f
:
1932 data
, std_dialects
: List
[str], use_implemented_status
: bool
1933 ) -> Dict
[str, Dict
[str, Any
]]:
1934 """Impementation for FeatureTestMacros.(standard|implemented)_ftms()."""
1936 for feature
in data
:
1940 for std
in std_dialects
:
1941 if std
not in feature
["values"].keys():
1948 values
= feature
["values"][std
]
1949 assert len(values
) > 0, f
"{feature['name']}[{std}] has no entries"
1950 for value
in values
:
1951 papers
= list(values
[value
])
1954 ), f
"{feature['name']}[{std}][{value}] has no entries"
1955 for paper
in papers
:
1956 if use_implemented_status
and not paper
["implemented"]:
1965 result
[feature
["name"]] = entry
1970 def generate_version_header_dialect_block(data
: Dict
[str, Any
]) -> str:
1971 """Generates the contents of the version header for a dialect.
1973 This generates the contents of a
1974 #if _LIBCPP_STD_VER >= XY
1975 #endif // _LIBCPP_STD_VER >= XY
1979 for element
in data
:
1980 for ftm
, entry
in element
.items():
1981 if not entry
["implemented"]:
1982 # When a FTM is not implemented don't add the guards
1983 # or undefine the (possibly) defined macro.
1984 result
+= f
'// define {ftm} {entry["value"]}\n'
1986 need_undef
= entry
["need_undef"]
1987 if entry
["condition"]:
1988 result
+= f
'# if {entry["condition"]}\n'
1989 if entry
["need_undef"]:
1990 result
+= f
"# undef {ftm}\n"
1991 result
+= f
'# define {ftm} {entry["value"]}\n'
1992 result
+= f
"# endif\n"
1994 if entry
["need_undef"]:
1995 result
+= f
"# undef {ftm}\n"
1996 result
+= f
'# define {ftm} {entry["value"]}\n'
2001 def generate_version_header_implementation(data
: Dict
[str, Dict
[str, Any
]]) -> str:
2002 """Generates the body of the version header."""
2004 template
= """#if _LIBCPP_STD_VER >= {dialect}
2005 {feature_test_macros}#endif // _LIBCPP_STD_VER >= {dialect}"""
2008 for std
, ftms
in data
.items():
2012 feature_test_macros
=generate_version_header_dialect_block(ftms
),
2016 return "\n\n".join(result
)
2019 class FeatureTestMacros
:
2020 """Provides all feature-test macro (FTM) output components.
2022 The class has several generators to use the feature-test macros in libc++:
2024 - The version header and its tests
2026 This class is not intended to duplicate
2027 https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros
2028 SD-FeatureTest: Feature-Test Macros and Policies
2030 Historically libc++ did not list all papers affecting a FTM, the new data
2031 structure is able to do that. However there is no intention to add the
2032 historical data. After papers have been implemented this information can be
2033 removed. For example, __cpp_lib_format's value 201907 requires 3 papers,
2034 once implemented it can be reduced to 1 paper and remove the paper number
2035 and title. This would reduce the size of the data.
2037 The input data is stored in the following JSON format:
2038 [ # A list with multiple feature-test macro entries.
2041 # The name of the feature test macro. These names should be unique and
2042 # sorted in the list.
2043 "name": "__cpp_lib_any",
2046 # A map with the value of the FTM based on the language standard. Only
2047 # the versions in which the value of the FTM changes are listed. For
2048 # example, this macro's value does not change in C++20 so it does not
2049 # list C++20. If it changes in C++26, it will have entries for C++17 and
2054 # The language standard, also named dialect in this class.
2058 # The value of the feature test macro. This contains an array with
2059 # one or more papers that need to be implemented before this value
2060 # is considered implemented.
2064 # Contains the paper number that is part of the FTM version.
2065 "number": "P0220R1",
2068 # Contains the title of the paper that is part of the FTM
2070 "title": "Adopt Library Fundamentals V1 TS Components for C++17"
2073 # The implementation status of the paper.
2081 # A sorted list of headers that should provide the FTM. The header
2082 # <version> is automatically added to this list. This list could be
2083 # empty. For example, __cpp_lib_modules is only present in version.
2084 # Requiring the field makes it easier to detect accidental omission.
2089 # optional, required when libcxx_guard is present
2090 # This field is used only to generate the unit tests for the
2091 # feature-test macros. It can't depend on macros defined in <__config>
2092 # because the `test/std/` parts of the test suite are intended to be
2093 # portable to any C++ standard library implementation, not just libc++.
2095 # * macros defined by the compiler itself, or
2096 # * macros generated by CMake.
2097 # In some cases we add also depend on macros defined in
2099 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR"
2101 # optional, required when test_suite_guard is present
2102 # This field is used only to guard the feature-test macro in
2103 # <version>. It may be the same as `test_suite_guard`, or it may
2104 # depend on macros defined in <__config>.
2105 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR"
2110 # The JSON data structure.
2113 def __init__(self
, filename
: str):
2114 """Initializes the class with the JSON data in the file 'filename'."""
2115 with
open(filename
) as f
:
2116 self
.__data
= json
.load(f
)
2118 @functools.cached_property
2119 def std_dialects(self
) -> List
[str]:
2120 """Returns the C++ dialects avaiable.
2122 The available dialects are based on the 'c++xy' keys found the 'values'
2123 entries in '__data'. So when WG21 starts to feature-test macros for a
2124 future C++ Standard this dialect will automatically be available.
2126 The return value is a sorted list with the C++ dialects used. Since FTM
2127 were added in C++14 the list will not contain C++03 or C++11.
2130 for feature
in self
.__data
:
2131 keys
= feature
["values"].keys()
2132 assert len(keys
) > 0, "'values' is empty"
2135 return sorted(list(dialects
))
2137 @functools.cached_property
2138 def standard_ftms(self
) -> Dict
[str, Dict
[str, Any
]]:
2139 """Returns the FTM versions per dialect in the Standard.
2141 This function does not use the 'implemented' flag. The output contains
2142 the versions used in the Standard. When a FTM in libc++ is not
2143 implemented according to the Standard to output may opt to show the
2146 The result is a dict with the following content
2147 - key: Name of the feature test macro.
2148 - value: A dict with the following content:
2149 * key: The version of the C++ dialect.
2150 * value: The value of the feature-test macro.
2152 return get_ftms(self
.__data
, self
.std_dialects
, False)
2154 @functools.cached_property
2155 def implemented_ftms(self
) -> Dict
[str, Dict
[str, Any
]]:
2156 """Returns the FTM versions per dialect implemented in libc++.
2158 Unlike `get_std_dialect_versions` this function uses the 'implemented'
2159 flag. This returns the actual implementation status in libc++.
2161 The result is a dict with the following content
2162 - key: Name of the feature test macro.
2163 - value: A dict with the following content:
2164 * key: The version of the C++ dialect.
2165 * value: The value of the feature-test macro. When a feature-test
2166 macro is not implemented its value is None.
2169 return get_ftms(self
.__data
, self
.std_dialects
, True)
2171 @functools.cached_property
2172 def ftm_metadata(self
) -> Dict
[str, Dict
[str, Any
]]:
2173 """Returns the metadata of the FTMs defined in the Standard.
2175 The metadata does not depend on the C++ dialect used.
2176 The result is a dict with the following contents:
2177 - key: Name of the feature test macro.
2178 - value: A dict with the following content:
2179 * headers: The list of headers that should provide the FTM
2180 * test_suite_guard: The condition for testing the FTM in the test suite.
2181 * test_suite_guard: The condition for testing the FTM in the version header.
2184 for feature
in self
.__data
:
2186 entry
["headers"] = feature
["headers"]
2187 entry
["test_suite_guard"] = feature
.get("test_suite_guard", None)
2188 entry
["libcxx_guard"] = feature
.get("libcxx_guard", None)
2189 result
[feature
["name"]] = entry
2194 def version_header_implementation(self
) -> Dict
[str, List
[Dict
[str, Any
]]]:
2195 """Generates the body of the version header."""
2197 for std
in self
.std_dialects
:
2198 result
[get_std_number(std
)] = list()
2200 for ftm
, values
in self
.standard_ftms
.items():
2203 for std
, value
in values
.items():
2204 # When a newer Standard does not change the value of the macro
2205 # there is no need to redefine it with the same value.
2206 if last_value
and value
== last_value
:
2211 entry
["value"] = value
2212 entry
["implemented"] = self
.implemented_ftms
[ftm
][std
] == self
.standard_ftms
[ftm
][std
]
2213 entry
["need_undef"] = last_entry
is not None and last_entry
["implemented"] and entry
["implemented"]
2214 entry
["condition"] = self
.ftm_metadata
[ftm
]["libcxx_guard"]
2217 result
[get_std_number(std
)].append(dict({ftm
: entry
}))
2222 def version_header(self
) -> str:
2223 """Generates the version header."""
2224 template
= """// -*- C++ -*-
2225 //===----------------------------------------------------------------------===//
2227 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2228 // See https://llvm.org/LICENSE.txt for license information.
2229 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2231 //===----------------------------------------------------------------------===//
2233 #ifndef _LIBCPP_VERSION
2234 #define _LIBCPP_VERSION
2238 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2239 # pragma GCC system_header
2242 {feature_test_macros}
2244 #endif // _LIBCPP_VERSION
2246 return template
.format(
2247 feature_test_macros
=generate_version_header_implementation(
2248 self
.version_header_implementation
2254 produce_version_header()
2258 # Example how to use the new version header generation function to generate
2261 ftm
= FeatureTestMacros(
2263 source_root
, "test", "libcxx", "feature_test_macro", "test_data.json"
2266 version_header_path
= os
.path
.join(include_path
, "version")
2267 with
open(version_header_path
, "w", newline
="\n") as f
:
2268 f
.write(ftm
.version_header
)
2271 if __name__
== "__main__":