4 from builtins
import range
5 from functools
import reduce
8 def get_libcxx_paths():
9 utils_path
= os
.path
.dirname(os
.path
.abspath(__file__
))
10 script_name
= os
.path
.basename(__file__
)
11 assert os
.path
.exists(utils_path
)
12 src_root
= os
.path
.dirname(utils_path
)
13 include_path
= os
.path
.join(src_root
, "include")
14 assert os
.path
.exists(include_path
)
15 docs_path
= os
.path
.join(src_root
, "docs")
16 assert os
.path
.exists(docs_path
)
17 macro_test_path
= os
.path
.join(
23 "support.limits.general",
25 assert os
.path
.exists(macro_test_path
)
26 assert os
.path
.exists(
27 os
.path
.join(macro_test_path
, "version.version.compile.pass.cpp")
29 return script_name
, src_root
, include_path
, docs_path
, macro_test_path
32 script_name
, source_root
, include_path
, docs_path
, macro_test_path
= get_libcxx_paths()
36 h_path
= os
.path
.join(include_path
, h
)
37 return os
.path
.exists(h_path
)
40 def add_version_header(tc
):
41 tc
["headers"].append("version")
45 # ================ ============================================================
47 # ================ ============================================================
48 # name The name of the feature-test macro.
49 # values A dict whose keys are C++ versions and whose values are the
50 # value of the feature-test macro for that C++ version.
51 # (TODO: This isn't a very clean model for feature-test
52 # macros affected by multiple papers.)
53 # headers An array with the headers that should provide the
55 # test_suite_guard An optional string field. When this field is provided,
56 # `libcxx_guard` must also be provided. This field is used
57 # only to generate the unit tests for the feature-test macros.
58 # It can't depend on macros defined in <__config> because the
59 # `test/std/` parts of the test suite are intended to be
60 # portable to any C++ standard library implementation, not
61 # just libc++. It may depend on
62 # * macros defined by the compiler itself, or
63 # * macros generated by CMake.
64 # In some cases we add also depend on macros defined in <__availability>.
65 # libcxx_guard An optional string field. When this field is provided,
66 # `test_suite_guard` must also be provided. This field is used
67 # only to guard the feature-test macro in <version>. It may
68 # be the same as `test_suite_guard`, or it may depend on
69 # macros defined in <__config>.
70 # unimplemented An optional Boolean field with the value `True`. This field
71 # is only used when a feature isn't fully implemented. Once
72 # you've fully implemented the feature, you should remove
74 # ================ ============================================================
75 feature_test_macros
= [
79 "name": "__cpp_lib_adaptor_iterator_pair_constructor",
80 "values": {"c++23": 202106},
81 "headers": ["queue", "stack"],
84 "name": "__cpp_lib_addressof_constexpr",
85 "values": {"c++17": 201603},
86 "headers": ["memory"],
89 "name": "__cpp_lib_allocate_at_least",
92 # Note LWG3887 Version macro for allocate_at_least
93 #"c++26": 202302, # P2652R2 Disallow User Specialization of allocator_traits
95 "headers": ["memory"],
98 "name": "__cpp_lib_allocator_traits_is_always_equal",
99 "values": {"c++17": 201411},
115 "name": "__cpp_lib_any",
116 "values": {"c++17": 201606},
120 "name": "__cpp_lib_apply",
121 "values": {"c++17": 201603},
122 "headers": ["tuple"],
125 "name": "__cpp_lib_array_constexpr",
126 "values": {"c++17": 201603, "c++20": 201811},
127 "headers": ["array", "iterator"],
130 "name": "__cpp_lib_as_const",
131 "values": {"c++17": 201510},
132 "headers": ["utility"],
135 "name": "__cpp_lib_associative_heterogeneous_erasure",
136 "values": {"c++23": 202110},
137 "headers": ["map", "set", "unordered_map", "unordered_set"],
138 "unimplemented": True,
141 "name": "__cpp_lib_associative_heterogeneous_insertion",
142 "values": {"c++26": 202306}, # P2363R5 Extending associative containers with the remaining heterogeneous overloads
143 "headers": ["map", "set", "unordered_map", "unordered_set"],
144 "unimplemented": True,
147 "name": "__cpp_lib_assume_aligned",
148 "values": {"c++20": 201811},
149 "headers": ["memory"],
152 "name": "__cpp_lib_atomic_flag_test",
153 "values": {"c++20": 201907},
154 "headers": ["atomic"],
157 "name": "__cpp_lib_atomic_float",
158 "values": {"c++20": 201711},
159 "headers": ["atomic"],
160 "unimplemented": True,
163 "name": "__cpp_lib_atomic_is_always_lock_free",
164 "values": {"c++17": 201603},
165 "headers": ["atomic"],
168 "name": "__cpp_lib_atomic_lock_free_type_aliases",
169 "values": {"c++20": 201907},
170 "headers": ["atomic"],
173 "name": "__cpp_lib_atomic_ref",
174 "values": {"c++20": 201806},
175 "headers": ["atomic"],
176 "unimplemented": True,
179 "name": "__cpp_lib_atomic_shared_ptr",
180 "values": {"c++20": 201711},
181 "headers": ["atomic"],
182 "unimplemented": True,
185 "name": "__cpp_lib_atomic_value_initialization",
186 "values": {"c++20": 201911},
187 "headers": ["atomic", "memory"],
190 "name": "__cpp_lib_atomic_wait",
191 "values": {"c++20": 201907},
192 "headers": ["atomic"],
193 "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
194 "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
197 "name": "__cpp_lib_barrier",
198 "values": {"c++20": 201907},
199 "headers": ["barrier"],
200 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
201 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
204 "name": "__cpp_lib_bind_back",
207 "c++26": 202306, # P2714R1 Bind front and back to NTTP callables
209 "headers": ["functional"],
210 "unimplemented": True,
213 "name": "__cpp_lib_bind_front",
216 "c++26": 202306, # P2714R1 Bind front and back to NTTP callables
218 "headers": ["functional"],
221 "name": "__cpp_lib_bit_cast",
222 "values": {"c++20": 201806},
226 "name": "__cpp_lib_bitops",
227 "values": {"c++20": 201907},
231 "name": "__cpp_lib_bitset",
232 "values": {"c++26": 202306}, # P2697R1 Interfacing bitset with string_view
233 "headers": ["bitset"],
236 "name": "__cpp_lib_bool_constant",
237 "values": {"c++17": 201505},
238 "headers": ["type_traits"],
241 "name": "__cpp_lib_bounded_array_traits",
242 "values": {"c++20": 201902},
243 "headers": ["type_traits"],
246 "name": "__cpp_lib_boyer_moore_searcher",
247 "values": {"c++17": 201603},
248 "headers": ["functional"],
251 "name": "__cpp_lib_byte",
252 "values": {"c++17": 201603},
253 "headers": ["cstddef"],
256 "name": "__cpp_lib_byteswap",
257 "values": {"c++23": 202110},
261 "name": "__cpp_lib_char8_t",
262 "values": {"c++20": 201907},
273 "test_suite_guard": "defined(__cpp_char8_t)",
274 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CHAR8_T)",
277 "name": "__cpp_lib_chrono",
280 #"c++26": 202306, # P2592R3 Hashing support for std::chrono value classes
282 "headers": ["chrono"],
285 "name": "__cpp_lib_chrono_udls",
286 "values": {"c++14": 201304},
287 "headers": ["chrono"],
290 "name": "__cpp_lib_clamp",
291 "values": {"c++17": 201603},
292 "headers": ["algorithm"],
295 "name": "__cpp_lib_complex_udls",
296 "values": {"c++14": 201309},
297 "headers": ["complex"],
300 "name": "__cpp_lib_concepts",
301 "values": {"c++20": 202002},
302 "headers": ["concepts"],
305 "name": "__cpp_lib_constexpr_algorithms",
308 #"c++26": 202306, # P2562R1 constexpr Stable Sorting
310 "headers": ["algorithm", "utility"],
313 "name": "__cpp_lib_constexpr_bitset",
314 "values": {"c++23": 202207},
315 "headers": ["bitset"],
318 "name": "__cpp_lib_constexpr_charconv",
319 "values": {"c++23": 202207},
320 "headers": ["charconv"],
323 "name": "__cpp_lib_constexpr_cmath",
324 "values": {"c++23": 202202},
325 "headers": ["cmath", "cstdlib"],
326 "unimplemented": True,
329 "name": "__cpp_lib_constexpr_complex",
330 "values": {"c++20": 201711},
331 "headers": ["complex"],
334 "name": "__cpp_lib_constexpr_dynamic_alloc",
335 "values": {"c++20": 201907},
336 "headers": ["memory"],
339 "name": "__cpp_lib_constexpr_functional",
340 "values": {"c++20": 201907},
341 "headers": ["functional"],
344 "name": "__cpp_lib_constexpr_iterator",
345 "values": {"c++20": 201811},
346 "headers": ["iterator"],
349 "name": "__cpp_lib_constexpr_memory",
350 "values": {"c++20": 201811, "c++23": 202202},
351 "headers": ["memory"],
354 "name": "__cpp_lib_constexpr_numeric",
355 "values": {"c++20": 201911},
356 "headers": ["numeric"],
359 "name": "__cpp_lib_constexpr_string",
360 "values": {"c++20": 201907},
361 "headers": ["string"],
364 "name": "__cpp_lib_constexpr_string_view",
365 "values": {"c++20": 201811},
366 "headers": ["string_view"],
369 "name": "__cpp_lib_constexpr_tuple",
370 "values": {"c++20": 201811},
371 "headers": ["tuple"],
374 "name": "__cpp_lib_constexpr_typeinfo",
375 "values": {"c++23": 202106},
376 "headers": ["typeinfo"],
379 "name": "__cpp_lib_constexpr_utility",
380 "values": {"c++20": 201811},
381 "headers": ["utility"],
384 "name": "__cpp_lib_constexpr_vector",
385 "values": {"c++20": 201907},
386 "headers": ["vector"],
389 "name": "__cpp_lib_copyable_function",
390 "values": {"c++26": 202306}, # P2548R6 copyable_function
391 "headers": ["functional"],
392 "unimplemented": True,
395 "name": "__cpp_lib_coroutine",
396 "values": {"c++20": 201902},
397 "headers": ["coroutine"],
400 "name": "__cpp_lib_destroying_delete",
401 "values": {"c++20": 201806},
403 "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
404 "libcxx_guard": "_LIBCPP_STD_VER >= 20 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
407 "name": "__cpp_lib_enable_shared_from_this",
408 "values": {"c++17": 201603},
409 "headers": ["memory"],
412 "name": "__cpp_lib_endian",
413 "values": {"c++20": 201907},
417 "name": "__cpp_lib_erase_if",
418 "values": {"c++20": 202002},
432 "name": "__cpp_lib_exchange_function",
433 "values": {"c++14": 201304},
434 "headers": ["utility"],
437 "name": "__cpp_lib_execution",
438 "values": {"c++17": 201603, "c++20": 201902},
439 "headers": ["execution"],
440 "unimplemented": True,
443 "name": "__cpp_lib_expected",
444 "values": {"c++23": 202211},
445 "headers": ["expected"],
448 "name": "__cpp_lib_filesystem",
449 "values": {"c++17": 201703},
450 "headers": ["filesystem"],
451 "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM_LIBRARY)",
452 "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM_LIBRARY)",
455 "name": "__cpp_lib_format",
457 # "c++20": 201907 Not implemented P1361R2 Integration of chrono with text formatting
458 # "c++20": 202106 Fully implemented
459 # "c++20": 202110 Not implemented P2372R3 Fixing locale handling in chrono formatters
461 # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types
463 # Note these three papers are adopted at the June 2023 meeting and have sequential numbering
464 # 202304 P2510R3 Formatting pointers (Implemented)
465 # 202305 P2757R3 Type-checking format args
466 # 202306 P2637R3 Member Visit
467 "headers": ["format"],
468 "unimplemented": True,
471 "name": "__cpp_lib_format_ranges",
472 "values": {"c++23": 202207},
473 "headers": ["format"],
476 "name": "__cpp_lib_formatters",
477 "values": {"c++23": 202302},
478 "headers": ["stacktrace", "thread"],
479 "unimplemented": True,
482 "name": "__cpp_lib_forward_like",
483 "values": {"c++23": 202207},
484 "headers": ["utility"],
487 "name": "__cpp_lib_fstream_native_handle",
488 "values": {"c++26": 202306}, # P1759R6 Native handles and file streams
489 "headers": ["fstream"],
490 "unimplemented": True,
493 "name": "__cpp_lib_function_ref",
494 "values": {"c++26": 202306}, # P0792R14 function_ref: a type-erased callable reference
495 "headers": ["functional"],
496 "unimplemented": True,
499 "name": "__cpp_lib_gcd_lcm",
500 "values": {"c++17": 201606},
501 "headers": ["numeric"],
504 "name": "__cpp_lib_generic_associative_lookup",
505 "values": {"c++14": 201304},
506 "headers": ["map", "set"],
509 "name": "__cpp_lib_generic_unordered_lookup",
510 "values": {"c++20": 201811},
511 "headers": ["unordered_map", "unordered_set"],
514 "name": "__cpp_lib_hardware_interference_size",
515 "values": {"c++17": 201703},
516 "test_suite_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)",
517 "libcxx_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)",
521 "name": "__cpp_lib_has_unique_object_representations",
522 "values": {"c++17": 201606},
523 "headers": ["type_traits"],
526 "name": "__cpp_lib_hazard_pointer",
527 "values": {"c++26": 202306}, # P2530R3 Hazard Pointers for C++26
528 "headers": ["hazard_pointer"],# TODO verify this entry since the paper was underspecified.
529 "unimplemented": True,
532 "name": "__cpp_lib_hypot",
533 "values": {"c++17": 201603},
534 "headers": ["cmath"],
537 "name": "__cpp_lib_incomplete_container_elements",
538 "values": {"c++17": 201505},
539 "headers": ["forward_list", "list", "vector"],
542 "name": "__cpp_lib_int_pow2",
543 "values": {"c++20": 202002},
547 "name": "__cpp_lib_integer_comparison_functions",
548 "values": {"c++20": 202002},
549 "headers": ["utility"],
552 "name": "__cpp_lib_integer_sequence",
553 "values": {"c++14": 201304},
554 "headers": ["utility"],
557 "name": "__cpp_lib_integral_constant_callable",
558 "values": {"c++14": 201304},
559 "headers": ["type_traits"],
562 "name": "__cpp_lib_interpolate",
563 "values": {"c++20": 201902},
564 "headers": ["cmath", "numeric"],
567 "name": "__cpp_lib_invoke",
568 "values": {"c++17": 201411},
569 "headers": ["functional"],
572 "name": "__cpp_lib_invoke_r",
573 "values": {"c++23": 202106},
574 "headers": ["functional"],
577 "name": "__cpp_lib_is_aggregate",
578 "values": {"c++17": 201703},
579 "headers": ["type_traits"],
582 "name": "__cpp_lib_is_constant_evaluated",
583 "values": {"c++20": 201811},
584 "headers": ["type_traits"],
587 "name": "__cpp_lib_is_final",
588 "values": {"c++14": 201402},
589 "headers": ["type_traits"],
592 "name": "__cpp_lib_is_invocable",
593 "values": {"c++17": 201703},
594 "headers": ["type_traits"],
597 "name": "__cpp_lib_is_layout_compatible",
598 "values": {"c++20": 201907},
599 "headers": ["type_traits"],
600 "unimplemented": True,
603 "name": "__cpp_lib_is_nothrow_convertible",
604 "values": {"c++20": 201806},
605 "headers": ["type_traits"],
608 "name": "__cpp_lib_is_null_pointer",
609 "values": {"c++14": 201309},
610 "headers": ["type_traits"],
613 "name": "__cpp_lib_is_pointer_interconvertible",
614 "values": {"c++20": 201907},
615 "headers": ["type_traits"],
616 "unimplemented": True,
619 "name": "__cpp_lib_is_scoped_enum",
620 "values": {"c++23": 202011},
621 "headers": ["type_traits"],
624 "name": "__cpp_lib_is_swappable",
625 "values": {"c++17": 201603},
626 "headers": ["type_traits"],
629 "name": "__cpp_lib_jthread",
630 "values": {"c++20": 201911},
631 "headers": ["stop_token", "thread"],
632 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
633 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
636 "name": "__cpp_lib_latch",
637 "values": {"c++20": 201907},
638 "headers": ["latch"],
639 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
640 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
643 "name": "__cpp_lib_launder",
644 "values": {"c++17": 201606},
648 "name": "__cpp_lib_list_remove_return_type",
649 "values": {"c++20": 201806},
650 "headers": ["forward_list", "list"],
653 "name": "__cpp_lib_logical_traits",
654 "values": {"c++17": 201510},
655 "headers": ["type_traits"],
658 "name": "__cpp_lib_make_from_tuple",
659 "values": {"c++17": 201606},
660 "headers": ["tuple"],
663 "name": "__cpp_lib_make_reverse_iterator",
664 "values": {"c++14": 201402},
665 "headers": ["iterator"],
668 "name": "__cpp_lib_make_unique",
669 "values": {"c++14": 201304},
670 "headers": ["memory"],
673 "name": "__cpp_lib_map_try_emplace",
674 "values": {"c++17": 201411},
678 "name": "__cpp_lib_math_constants",
679 "values": {"c++20": 201907},
680 "headers": ["numbers"],
683 "name": "__cpp_lib_math_special_functions",
684 "values": {"c++17": 201603},
685 "headers": ["cmath"],
686 "unimplemented": True,
689 "name": "__cpp_lib_mdspan",
690 "values": {"c++23": 202207},
691 "headers": ["mdspan"],
694 "name": "__cpp_lib_memory_resource",
695 "values": {"c++17": 201603},
696 "headers": ["memory_resource"],
697 "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_PMR)",
698 "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_PMR)",
701 "name": "__cpp_lib_move_iterator_concept",
702 "values": {"c++20": 202207},
703 "headers": ["iterator"],
706 "name": "__cpp_lib_move_only_function",
707 "values": {"c++23": 202110},
708 "headers": ["functional"],
709 "unimplemented": True,
712 "name": "__cpp_lib_node_extract",
713 "values": {"c++17": 201606},
714 "headers": ["map", "set", "unordered_map", "unordered_set"],
717 "name": "__cpp_lib_nonmember_container_access",
718 "values": {"c++17": 201411},
735 "name": "__cpp_lib_not_fn",
738 #"c++26": 202306, # P2714R1 Bind front and back to NTTP callables
740 "headers": ["functional"],
743 "name": "__cpp_lib_null_iterators",
744 "values": {"c++14": 201304},
745 "headers": ["iterator"],
748 "name": "__cpp_lib_optional",
749 "values": {"c++17": 201606, "c++23": 202110},
750 "headers": ["optional"],
753 "name": "__cpp_lib_out_ptr",
754 "values": {"c++23": 202106},
755 "headers": ["memory"],
756 "unimplemented": True,
759 "name": "__cpp_lib_parallel_algorithm",
760 "values": {"c++17": 201603},
761 "headers": ["algorithm", "numeric"],
762 "unimplemented": True,
765 "name": "__cpp_lib_polymorphic_allocator",
766 "values": {"c++20": 201902},
767 "headers": ["memory_resource"],
768 "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_PMR)",
769 "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_PMR)",
772 "name": "__cpp_lib_print",
773 "values": {"c++23": 202207},
774 "headers": ["ostream", "print"],
775 "unimplemented": True,
778 "name": "__cpp_lib_quoted_string_io",
779 "values": {"c++14": 201304},
780 "headers": ["iomanip"],
783 "name": "__cpp_lib_ranges",
784 "values": {"c++20": 202207},
785 "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
788 "name": "__cpp_lib_ranges_as_rvalue",
789 "values": {"c++23": 202207},
790 "headers": ["ranges"],
793 "name": "__cpp_lib_ranges_chunk",
794 "values": {"c++23": 202202},
795 "headers": ["ranges"],
796 "unimplemented": True,
799 "name": "__cpp_lib_ranges_chunk_by",
800 "values": {"c++23": 202202},
801 "headers": ["ranges"],
804 "name": "__cpp_lib_ranges_iota",
805 "values": {"c++23": 202202},
806 "headers": ["numeric"],
807 "unimplemented": True,
810 "name": "__cpp_lib_ranges_join_with",
811 "values": {"c++23": 202202},
812 "headers": ["ranges"],
813 "unimplemented": True,
816 "name": "__cpp_lib_ranges_repeat",
817 "values": { "c++23": 202207},
818 "headers": ["ranges"],
821 "name": "__cpp_lib_ranges_slide",
822 "values": {"c++23": 202202},
823 "headers": ["ranges"],
824 "unimplemented": True,
827 "name": "__cpp_lib_ranges_starts_ends_with",
828 "values": {"c++23": 202106},
829 "headers": ["algorithm"],
830 "unimplemented": True,
833 "name": "__cpp_lib_ranges_to_container",
834 "values": {"c++23": 202202},
851 "name": "__cpp_lib_ranges_zip",
852 "values": {"c++23": 202110},
853 "headers": ["ranges", "tuple", "utility"],
854 "unimplemented": True,
857 "name": "__cpp_lib_ratio",
858 "values": {"c++26": 202306}, # P2734R0 Adding the new SI prefixes
859 "headers": ["ratio"],
862 "name": "__cpp_lib_raw_memory_algorithms",
863 "values": {"c++17": 201606},
864 "headers": ["memory"],
867 "name": "__cpp_lib_rcu",
868 "values": {"c++26": 202306}, # P2545R4 Read-Copy Update (RCU)
869 "headers": ["rcu"], # TODO verify this entry since the paper was underspecified.
870 "unimplemented": True,
873 "name": "__cpp_lib_reference_from_temporary",
874 "values": {"c++23": 202202},
875 "headers": ["type_traits"],
876 "unimplemented": True,
879 "name": "__cpp_lib_remove_cvref",
880 "values": {"c++20": 201711},
881 "headers": ["type_traits"],
884 "name": "__cpp_lib_result_of_sfinae",
885 "values": {"c++14": 201210},
886 "headers": ["functional", "type_traits"],
889 "name": "__cpp_lib_robust_nonmodifying_seq_ops",
890 "values": {"c++14": 201304},
891 "headers": ["algorithm"],
894 "name": "__cpp_lib_sample",
895 "values": {"c++17": 201603},
896 "headers": ["algorithm"],
899 "name": "__cpp_lib_scoped_lock",
900 "values": {"c++17": 201703},
901 "headers": ["mutex"],
904 "name": "__cpp_lib_semaphore",
905 "values": {"c++20": 201907},
906 "headers": ["semaphore"],
907 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
908 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)",
911 "name": "__cpp_lib_shared_mutex",
912 "values": {"c++17": 201505},
913 "headers": ["shared_mutex"],
914 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)",
915 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)",
918 "name": "__cpp_lib_shared_ptr_arrays",
919 "values": {"c++17": 201611, "c++20": 201707},
920 "headers": ["memory"],
923 "name": "__cpp_lib_shared_ptr_weak_type",
924 "values": {"c++17": 201606},
925 "headers": ["memory"],
928 "name": "__cpp_lib_shared_timed_mutex",
929 "values": {"c++14": 201402},
930 "headers": ["shared_mutex"],
931 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)",
932 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)",
935 "name": "__cpp_lib_shift",
936 "values": {"c++20": 201806},
937 "headers": ["algorithm"],
940 "name": "__cpp_lib_smart_ptr_for_overwrite",
941 "values": {"c++20": 202002},
942 "headers": ["memory"],
943 "unimplemented": True,
946 "name": "__cpp_lib_smart_ptr_owner_equality",
947 "values": {"c++26": 202306}, # P1901R2 Enabling the Use of weak_ptr as Keys in Unordered Associative Containers
948 "headers": ["memory"],
949 "unimplemented": True,
952 "name": "__cpp_lib_source_location",
953 "values": {"c++20": 201907},
954 "headers": ["source_location"],
955 "test_suite_guard": "__has_builtin(__builtin_source_location) && !(defined(TEST_APPLE_CLANG_VER) && TEST_APPLE_CLANG_VER <= 1403)",
956 "libcxx_guard": "__has_builtin(__builtin_source_location) && !(defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER <= 1403)",
959 "name": "__cpp_lib_span",
960 "values": {"c++20": 202002},
964 "name": "__cpp_lib_spanstream",
965 "values": {"c++23": 202106},
966 "headers": ["spanstream"],
967 "unimplemented": True,
970 "name": "__cpp_lib_ssize",
971 "values": {"c++20": 201902},
972 "headers": ["iterator"],
975 "name": "__cpp_lib_sstream_from_string_view",
976 "values": {"c++26": 202306}, # P2495R3 Interfacing stringstreams with string_view
977 "headers": ["sstream"],
978 "unimplemented": True,
981 "name": "__cpp_lib_stacktrace",
982 "values": {"c++23": 202011},
983 "headers": ["stacktrace"],
984 "unimplemented": True,
987 "name": "__cpp_lib_starts_ends_with",
988 "values": {"c++20": 201711},
989 "headers": ["string", "string_view"],
992 "name": "__cpp_lib_stdatomic_h",
993 "values": {"c++23": 202011},
994 "headers": ["stdatomic.h"],
997 "name": "__cpp_lib_string_contains",
998 "values": {"c++23": 202011},
999 "headers": ["string", "string_view"],
1002 "name": "__cpp_lib_string_resize_and_overwrite",
1003 "values": {"c++23": 202110},
1004 "headers": ["string"],
1007 "name": "__cpp_lib_string_udls",
1008 "values": {"c++14": 201304},
1009 "headers": ["string"],
1012 "name": "__cpp_lib_string_view",
1013 "values": {"c++17": 201606, "c++20": 201803},
1014 "headers": ["string", "string_view"],
1017 "name": "__cpp_lib_submdspan",
1018 "values": {"c++26": 202306}, # P2630R4 submdspan
1019 "headers": ["mdspan"],
1020 "unimplemented": True,
1023 "name": "__cpp_lib_syncbuf",
1024 "values": {"c++20": 201803},
1025 "headers": ["syncstream"],
1026 "unimplemented": True,
1029 "name": "__cpp_lib_text_encoding",
1030 "values": {"c++26": 202306}, # P1885R12 Naming Text Encodings to Demystify Them
1031 "headers": ["text_encoding"],
1032 "unimplemented": True,
1035 "name": "__cpp_lib_three_way_comparison",
1036 "values": {"c++20": 201907},
1037 "headers": ["compare"],
1038 "unimplemented": True,
1041 "name": "__cpp_lib_to_address",
1042 "values": {"c++20": 201711},
1043 "headers": ["memory"],
1046 "name": "__cpp_lib_to_array",
1047 "values": {"c++20": 201907},
1048 "headers": ["array"],
1051 "name": "__cpp_lib_to_chars",
1054 "c++26": 202306, # P2497R0 Testing for success or failure of <charconv> functions
1056 "headers": ["charconv"],
1057 "unimplemented": True,
1060 "name": "__cpp_lib_to_string",
1061 "values": {"c++23": 202306}, # P2587R3 to_string or not to_string
1062 "headers": ["string"],
1063 "unimplemented": True,
1066 "name": "__cpp_lib_to_underlying",
1067 "values": {"c++23": 202102},
1068 "headers": ["utility"],
1071 "name": "__cpp_lib_transformation_trait_aliases",
1072 "values": {"c++14": 201304},
1073 "headers": ["type_traits"],
1076 "name": "__cpp_lib_transparent_operators",
1077 "values": {"c++14": 201210, "c++17": 201510},
1078 "headers": ["functional", "memory"],
1081 "name": "__cpp_lib_tuple_element_t",
1082 "values": {"c++14": 201402},
1083 "headers": ["tuple"],
1086 "name": "__cpp_lib_tuples_by_type",
1087 "values": {"c++14": 201304},
1088 "headers": ["tuple", "utility"],
1091 "name": "__cpp_lib_type_identity",
1092 "values": {"c++20": 201806},
1093 "headers": ["type_traits"],
1096 "name": "__cpp_lib_type_trait_variable_templates",
1097 "values": {"c++17": 201510},
1098 "headers": ["type_traits"],
1101 "name": "__cpp_lib_uncaught_exceptions",
1102 "values": {"c++17": 201411},
1103 "headers": ["exception"],
1106 "name": "__cpp_lib_unordered_map_try_emplace",
1107 "values": {"c++17": 201411},
1108 "headers": ["unordered_map"],
1111 "name": "__cpp_lib_unreachable",
1112 "values": {"c++23": 202202},
1113 "headers": ["utility"],
1116 "name": "__cpp_lib_unwrap_ref",
1117 "values": {"c++20": 201811},
1118 "headers": ["functional"],
1121 "name": "__cpp_lib_variant",
1122 "values": {"c++17": 202102},
1123 "headers": ["variant"],
1126 "name": "__cpp_lib_void_t",
1127 "values": {"c++17": 201411},
1128 "headers": ["type_traits"],
1131 "name": "__cpp_lib_within_lifetime",
1132 "values": {"c++26": 202306}, # P2641R4 Checking if a union alternative is active
1133 "headers": ["type_traits"],
1134 "unimplemented": True,
1139 assert feature_test_macros
== sorted(feature_test_macros
, key
=lambda tc
: tc
["name"])
1140 assert all(tc
["headers"] == sorted(tc
["headers"]) for tc
in feature_test_macros
)
1142 ("libcxx_guard" in tc
) == ("test_suite_guard" in tc
) for tc
in feature_test_macros
1155 for key
in tc
.keys()
1157 for tc
in feature_test_macros
1160 # Map from each header to the Lit annotations that should be used for
1161 # tests that include that header.
1163 # For example, when threads are not supported, any test that includes
1164 # <thread> should be marked as UNSUPPORTED, because including <thread>
1165 # is a hard error in that case.
1167 "barrier": ["UNSUPPORTED: no-threads"],
1168 "filesystem": ["UNSUPPORTED: no-filesystem"],
1169 "fstream": ["UNSUPPORTED: no-localization"],
1170 "iomanip": ["UNSUPPORTED: no-localization"],
1171 "ios": ["UNSUPPORTED: no-localization"],
1172 "iostream": ["UNSUPPORTED: no-localization"],
1173 "istream": ["UNSUPPORTED: no-localization"],
1174 "latch": ["UNSUPPORTED: no-threads"],
1175 "locale": ["UNSUPPORTED: no-localization"],
1176 "mutex": ["UNSUPPORTED: no-threads"],
1177 "ostream": ["UNSUPPORTED: no-localization"],
1178 "print": ["UNSUPPORTED: no-filesystem"],
1179 "regex": ["UNSUPPORTED: no-localization"],
1180 "semaphore": ["UNSUPPORTED: no-threads"],
1181 "shared_mutex": ["UNSUPPORTED: no-threads"],
1182 "sstream": ["UNSUPPORTED: no-localization"],
1183 "stdatomic.h": ["UNSUPPORTED: no-threads"],
1184 "stop_token": ["UNSUPPORTED: no-threads"],
1185 "thread": ["UNSUPPORTED: no-threads"],
1189 def get_std_dialects():
1190 std_dialects
= ["c++14", "c++17", "c++20", "c++23", "c++26"]
1191 return list(std_dialects
)
1194 def get_first_std(d
):
1195 for s
in get_std_dialects():
1201 def get_last_std(d
):
1202 rev_dialects
= get_std_dialects()
1203 rev_dialects
.reverse()
1204 for s
in rev_dialects
:
1210 def get_std_before(d
, std
):
1211 std_dialects
= get_std_dialects()
1212 candidates
= std_dialects
[0 : std_dialects
.index(std
)]
1213 candidates
.reverse()
1214 for cand
in candidates
:
1215 if cand
in d
.keys():
1220 def get_value_before(d
, std
):
1221 new_std
= get_std_before(d
, std
)
1227 def get_for_std(d
, std
):
1228 # This catches the C++11 case for which there should be no defined feature
1230 std_dialects
= get_std_dialects()
1231 if std
not in std_dialects
:
1233 # Find the value for the newest C++ dialect between C++14 and std
1234 std_list
= list(std_dialects
[0 : std_dialects
.index(std
) + 1])
1242 def get_std_number(std
):
1243 return std
.replace("c++", "")
1247 Functions to produce the <version> header
1251 def produce_macros_definition_for_std(std
):
1254 for tc
in feature_test_macros
:
1255 if std
not in tc
["values"]:
1258 if "test_suite_guard" in tc
.keys():
1259 result
+= "# if %s\n" % tc
["libcxx_guard"]
1261 if get_value_before(tc
["values"], std
) is not None:
1262 assert "test_suite_guard" not in tc
.keys()
1263 result
+= "# undef %s\n" % tc
["name"]
1264 line
= "#%sdefine %s" % ((" " * inner_indent
), tc
["name"])
1265 line
+= " " * (indent
- len(line
))
1266 line
+= " %sL" % tc
["values"][std
]
1267 if "unimplemented" in tc
.keys():
1271 if "test_suite_guard" in tc
.keys():
1272 result
+= "# endif\n"
1273 return result
.strip()
1276 def produce_macros_definitions():
1277 macro_definition_template
= """#if _LIBCPP_STD_VER >= {std_number}
1281 macros_definitions
= []
1282 for std
in get_std_dialects():
1283 macros_definitions
.append(
1284 macro_definition_template
.format(
1285 std_number
=get_std_number(std
),
1286 macro_definition
=produce_macros_definition_for_std(std
),
1290 return "\n\n".join(macros_definitions
)
1294 """Yield successive n-sized chunks from l."""
1295 for i
in range(0, len(l
), n
):
1299 def produce_version_synopsis():
1301 header_indent
= 56 + len("20XXYYL ")
1304 def indent_to(s
, val
):
1307 s
+= " " * (val
- len(s
))
1310 line
= indent_to("Macro name", indent
) + "Value"
1311 line
= indent_to(line
, header_indent
) + "Headers"
1312 result
+= line
+ "\n"
1313 for tc
in feature_test_macros
:
1314 prev_defined_std
= get_last_std(tc
["values"])
1315 line
= "{name: <{indent}}{value}L ".format(
1316 name
=tc
["name"], indent
=indent
, value
=tc
["values"][prev_defined_std
]
1318 headers
= list(tc
["headers"])
1319 headers
.remove("version")
1320 for chunk
in chunks(headers
, 3):
1321 line
= indent_to(line
, header_indent
)
1322 chunk
= ["<%s>" % header
for header
in chunk
]
1323 line
+= " ".join(chunk
)
1328 prev_defined_std
= get_std_before(tc
["values"], prev_defined_std
)
1329 if prev_defined_std
is None:
1331 result
+= "%s%sL // %s\n" % (
1332 indent_to("", indent
),
1333 tc
["values"][prev_defined_std
],
1334 prev_defined_std
.replace("c++", "C++"),
1339 def produce_version_header():
1340 template
= """// -*- C++ -*-
1341 //===----------------------------------------------------------------------===//
1343 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1344 // See https://llvm.org/LICENSE.txt for license information.
1345 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1347 //===----------------------------------------------------------------------===//
1349 #ifndef _LIBCPP_VERSIONH
1350 #define _LIBCPP_VERSIONH
1359 #include <__assert> // all public C++ headers provide the assertion handler
1362 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1363 # pragma GCC system_header
1372 #endif // _LIBCPP_VERSIONH
1375 version_str
= template
.format(
1376 synopsis
=produce_version_synopsis().strip(),
1377 cxx_macros
=produce_macros_definitions(),
1379 version_header_path
= os
.path
.join(include_path
, "version")
1380 with
open(version_header_path
, "w", newline
="\n") as f
:
1381 f
.write(version_str
)
1385 Functions to produce test files
1391 # error "{name} should not be defined before {std_first}"
1394 "test_suite_guard": """
1395 # if {test_suite_guard}
1397 # error "{name} should be defined in {std}"
1399 # if {name} != {value}
1400 # error "{name} should have the value {value} in {std}"
1404 # error "{name} should not be defined when the requirement '{test_suite_guard}' is not met!"
1408 "unimplemented": """
1409 # if !defined(_LIBCPP_VERSION)
1411 # error "{name} should be defined in {std}"
1413 # if {name} != {value}
1414 # error "{name} should have the value {value} in {std}"
1416 # else // _LIBCPP_VERSION
1418 # error "{name} should not be defined because it is unimplemented in libc++!"
1424 # error "{name} should be defined in {std}"
1426 # if {name} != {value}
1427 # error "{name} should have the value {value} in {std}"
1433 def generate_std_test(test_list
, std
):
1435 for tc
in test_list
:
1436 val
= get_for_std(tc
["values"], std
)
1440 result
+= test_types
["undefined"].format(
1441 name
=tc
["name"], std_first
=get_first_std(tc
["values"])
1443 elif "unimplemented" in tc
.keys():
1444 result
+= test_types
["unimplemented"].format(
1445 name
=tc
["name"], value
=val
, std
=std
1447 elif "test_suite_guard" in tc
.keys():
1448 result
+= test_types
["test_suite_guard"].format(
1452 test_suite_guard
=tc
["test_suite_guard"],
1455 result
+= test_types
["defined"].format(name
=tc
["name"], value
=val
, std
=std
)
1456 return result
.strip()
1459 def generate_std_tests(test_list
):
1460 std_tests_template
= """#if TEST_STD_VER < {first_std_number}
1466 #elif TEST_STD_VER > {penultimate_std_number}
1470 #endif // TEST_STD_VER > {penultimate_std_number}"""
1472 std_dialects
= get_std_dialects()
1474 other_std_tests
= []
1475 for std
in std_dialects
[:-1]:
1476 other_std_tests
.append("#elif TEST_STD_VER == " + get_std_number(std
))
1477 other_std_tests
.append(generate_std_test(test_list
, std
))
1479 std_tests
= std_tests_template
.format(
1480 first_std_number
=get_std_number(std_dialects
[0]),
1481 pre_std_test
=generate_std_test(test_list
, "c++11"),
1482 other_std_tests
="\n\n".join(other_std_tests
),
1483 penultimate_std_number
=get_std_number(std_dialects
[-2]),
1484 last_std_test
=generate_std_test(test_list
, std_dialects
[-1]),
1490 def generate_synopsis(test_list
):
1491 max_name_len
= max([len(tc
["name"]) for tc
in test_list
])
1492 indent
= max_name_len
+ 8
1494 def mk_line(prefix
, suffix
):
1495 return "{prefix: <{max_len}}{suffix}\n".format(
1496 prefix
=prefix
, suffix
=suffix
, max_len
=indent
1500 result
+= mk_line("/* Constant", "Value")
1501 for tc
in test_list
:
1502 prefix
= " %s" % tc
["name"]
1503 for std
in [s
for s
in get_std_dialects() if s
in tc
["values"].keys()]:
1505 prefix
, "%sL [%s]" % (tc
["values"][std
], std
.replace("c++", "C++"))
1512 def produce_tests():
1513 headers
= set([h
for tc
in feature_test_macros
for h
in tc
["headers"]])
1515 test_list
= [tc
for tc
in feature_test_macros
if h
in tc
["headers"]]
1516 if not has_header(h
):
1517 for tc
in test_list
:
1518 assert "unimplemented" in tc
.keys()
1520 markup
= "\n".join("// " + tag
for tag
in lit_markup
.get(h
, []))
1521 test_body
= """//===----------------------------------------------------------------------===//
1523 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1524 // See https://llvm.org/LICENSE.txt for license information.
1525 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1527 //===----------------------------------------------------------------------===//
1529 // WARNING: This test was generated by {script_name}
1530 // and should not be edited manually.
1536 // Test the feature test macros defined by <{header}>
1541 #include "test_macros.h"
1546 script_name
=script_name
,
1548 markup
=("\n{}\n".format(markup
) if markup
else ""),
1549 synopsis
=generate_synopsis(test_list
),
1550 cxx_tests
=generate_std_tests(test_list
),
1552 test_name
= "{header}.version.compile.pass.cpp".format(header
=h
)
1553 out_path
= os
.path
.join(macro_test_path
, test_name
)
1554 with
open(out_path
, "w", newline
="\n") as f
:
1559 Produce documentation for the feature test macros
1563 def make_widths(grid
):
1565 for i
in range(0, len(grid
[0])):
1566 cell_width
= 2 + max(
1567 reduce(lambda x
, y
: x
+ y
, [[len(row
[i
])] for row
in grid
], [])
1569 widths
+= [cell_width
]
1573 def create_table(grid
, indent
):
1574 indent_str
= " " * indent
1575 col_widths
= make_widths(grid
)
1576 result
= [indent_str
+ add_divider(col_widths
, 2)]
1578 for row_i
in range(0, len(grid
)):
1580 line
= indent_str
+ " ".join(
1581 [pad_cell(row
[i
], col_widths
[i
]) for i
in range(0, len(row
))]
1583 result
.append(line
.rstrip())
1584 if row_i
== len(grid
) - 1:
1586 if row
[0].startswith("**"):
1588 separator
= indent_str
+ add_divider(col_widths
, header_flag
)
1589 result
.append(separator
.rstrip())
1591 return "\n".join(result
)
1594 def add_divider(widths
, header_flag
):
1595 if header_flag
== 3:
1596 return "=".join(["=" * w
for w
in widths
])
1597 if header_flag
== 2:
1598 return " ".join(["=" * w
for w
in widths
])
1599 if header_flag
== 1:
1600 return "-".join(["-" * w
for w
in widths
])
1602 return " ".join(["-" * w
for w
in widths
])
1605 def pad_cell(s
, length
, left_align
=True):
1606 padding
= (length
- len(s
)) * " "
1610 def get_status_table():
1611 table
= [["Macro Name", "Value"]]
1612 for std
in get_std_dialects():
1613 table
+= [["**" + std
.replace("c++", "C++ ") + "**", ""]]
1614 for tc
in feature_test_macros
:
1615 if std
not in tc
["values"].keys():
1617 value
= "``%sL``" % tc
["values"][std
]
1618 if "unimplemented" in tc
.keys():
1619 value
= "*unimplemented*"
1620 table
+= [["``%s``" % tc
["name"], value
]]
1625 doc_str
= """.. _FeatureTestMacroTable:
1627 ==========================
1628 Feature Test Macro Support
1629 ==========================
1637 This file documents the feature test macros currently supported by libc++.
1644 .. table:: Current Status
1645 :name: feature-status-table
1651 status_tables
=create_table(get_status_table(), 4)
1654 table_doc_path
= os
.path
.join(docs_path
, "FeatureTestMacroTable.rst")
1655 with
open(table_doc_path
, "w", newline
="\n") as f
:
1660 produce_version_header()
1665 if __name__
== "__main__":