Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / utils / generate_feature_test_macro_components.py
blob76faa275d2d7e2f9e776c1964f963172562dbb63
1 #!/usr/bin/env python
3 import os
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(
18 src_root,
19 "test",
20 "std",
21 "language.support",
22 "support.limits",
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()
35 def has_header(h):
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")
42 return tc
45 # ================ ============================================================
46 # Field Description
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
54 # feature-test macro.
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
73 # this field.
74 # ================ ============================================================
75 feature_test_macros = [
76 add_version_header(x)
77 for x in [
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",
90 "values": {
91 "c++23": 202106,
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},
100 "headers": [
101 "deque",
102 "forward_list",
103 "list",
104 "map",
105 "memory",
106 "scoped_allocator",
107 "set",
108 "string",
109 "unordered_map",
110 "unordered_set",
111 "vector",
115 "name": "__cpp_lib_any",
116 "values": {"c++17": 201606},
117 "headers": ["any"],
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",
205 "values": {
206 "c++23": 202202,
207 "c++26": 202306, # P2714R1 Bind front and back to NTTP callables
209 "headers": ["functional"],
210 "unimplemented": True,
213 "name": "__cpp_lib_bind_front",
214 "values": {
215 "c++20": 201907,
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},
223 "headers": ["bit"],
226 "name": "__cpp_lib_bitops",
227 "values": {"c++20": 201907},
228 "headers": ["bit"],
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},
258 "headers": ["bit"],
261 "name": "__cpp_lib_char8_t",
262 "values": {"c++20": 201907},
263 "headers": [
264 "atomic",
265 "filesystem",
266 "istream",
267 "limits",
268 "locale",
269 "ostream",
270 "string",
271 "string_view",
273 "test_suite_guard": "defined(__cpp_char8_t)",
274 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CHAR8_T)",
277 "name": "__cpp_lib_chrono",
278 "values": {
279 "c++17": 201611,
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",
306 "values": {
307 "c++20": 201806,
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},
402 "headers": ["new"],
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},
414 "headers": ["bit"],
417 "name": "__cpp_lib_erase_if",
418 "values": {"c++20": 202002},
419 "headers": [
420 "deque",
421 "forward_list",
422 "list",
423 "map",
424 "set",
425 "string",
426 "unordered_map",
427 "unordered_set",
428 "vector",
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",
456 "values": {
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
460 "c++20": 202106,
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)",
518 "headers": ["new"],
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},
544 "headers": ["bit"],
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},
645 "headers": ["new"],
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},
675 "headers": ["map"],
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},
719 "headers": [
720 "array",
721 "deque",
722 "forward_list",
723 "iterator",
724 "list",
725 "map",
726 "regex",
727 "set",
728 "string",
729 "unordered_map",
730 "unordered_set",
731 "vector",
735 "name": "__cpp_lib_not_fn",
736 "values": {
737 "c++17": 201603,
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},
835 "headers": [
836 "deque",
837 "forward_list",
838 "list",
839 "map",
840 "queue",
841 "ranges",
842 "set",
843 "stack",
844 "string",
845 "unordered_map",
846 "unordered_set",
847 "vector",
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},
961 "headers": ["span"],
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",
1052 "values": {
1053 "c++17": 201611,
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)
1141 assert all(
1142 ("libcxx_guard" in tc) == ("test_suite_guard" in tc) for tc in feature_test_macros
1144 assert all(
1145 all(
1147 in [
1148 "name",
1149 "values",
1150 "headers",
1151 "libcxx_guard",
1152 "test_suite_guard",
1153 "unimplemented",
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.
1166 lit_markup = {
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():
1196 if s in d.keys():
1197 return s
1198 return None
1201 def get_last_std(d):
1202 rev_dialects = get_std_dialects()
1203 rev_dialects.reverse()
1204 for s in rev_dialects:
1205 if s in d.keys():
1206 return s
1207 return None
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():
1216 return cand
1217 return None
1220 def get_value_before(d, std):
1221 new_std = get_std_before(d, std)
1222 if new_std is None:
1223 return None
1224 return d[new_std]
1227 def get_for_std(d, std):
1228 # This catches the C++11 case for which there should be no defined feature
1229 # test macros.
1230 std_dialects = get_std_dialects()
1231 if std not in std_dialects:
1232 return None
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])
1235 std_list.reverse()
1236 for s in std_list:
1237 if s in d.keys():
1238 return d[s]
1239 return None
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):
1252 result = ""
1253 indent = 55
1254 for tc in feature_test_macros:
1255 if std not in tc["values"]:
1256 continue
1257 inner_indent = 1
1258 if "test_suite_guard" in tc.keys():
1259 result += "# if %s\n" % tc["libcxx_guard"]
1260 inner_indent += 2
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():
1268 line = "// " + line
1269 result += line
1270 result += "\n"
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}
1278 {macro_definition}
1279 #endif"""
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)
1293 def chunks(l, n):
1294 """Yield successive n-sized chunks from l."""
1295 for i in range(0, len(l), n):
1296 yield l[i : i + n]
1299 def produce_version_synopsis():
1300 indent = 56
1301 header_indent = 56 + len("20XXYYL ")
1302 result = ""
1304 def indent_to(s, val):
1305 if len(s) >= val:
1306 return s
1307 s += " " * (val - len(s))
1308 return 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)
1324 result += line
1325 result += "\n"
1326 line = ""
1327 while True:
1328 prev_defined_std = get_std_before(tc["values"], prev_defined_std)
1329 if prev_defined_std is None:
1330 break
1331 result += "%s%sL // %s\n" % (
1332 indent_to("", indent),
1333 tc["values"][prev_defined_std],
1334 prev_defined_std.replace("c++", "C++"),
1336 return result
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
1353 version synopsis
1355 {synopsis}
1359 #include <__assert> // all public C++ headers provide the assertion handler
1360 #include <__config>
1362 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1363 # pragma GCC system_header
1364 #endif
1366 // clang-format off
1368 {cxx_macros}
1370 // clang-format on
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
1388 test_types = {
1389 "undefined": """
1390 # ifdef {name}
1391 # error "{name} should not be defined before {std_first}"
1392 # endif
1393 """,
1394 "test_suite_guard": """
1395 # if {test_suite_guard}
1396 # ifndef {name}
1397 # error "{name} should be defined in {std}"
1398 # endif
1399 # if {name} != {value}
1400 # error "{name} should have the value {value} in {std}"
1401 # endif
1402 # else
1403 # ifdef {name}
1404 # error "{name} should not be defined when the requirement '{test_suite_guard}' is not met!"
1405 # endif
1406 # endif
1407 """,
1408 "unimplemented": """
1409 # if !defined(_LIBCPP_VERSION)
1410 # ifndef {name}
1411 # error "{name} should be defined in {std}"
1412 # endif
1413 # if {name} != {value}
1414 # error "{name} should have the value {value} in {std}"
1415 # endif
1416 # else // _LIBCPP_VERSION
1417 # ifdef {name}
1418 # error "{name} should not be defined because it is unimplemented in libc++!"
1419 # endif
1420 # endif
1421 """,
1422 "defined": """
1423 # ifndef {name}
1424 # error "{name} should be defined in {std}"
1425 # endif
1426 # if {name} != {value}
1427 # error "{name} should have the value {value} in {std}"
1428 # endif
1429 """,
1433 def generate_std_test(test_list, std):
1434 result = ""
1435 for tc in test_list:
1436 val = get_for_std(tc["values"], std)
1437 if val is not None:
1438 val = "%sL" % val
1439 if val is None:
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(
1449 name=tc["name"],
1450 value=val,
1451 std=std,
1452 test_suite_guard=tc["test_suite_guard"],
1454 else:
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}
1462 {pre_std_test}
1464 {other_std_tests}
1466 #elif TEST_STD_VER > {penultimate_std_number}
1468 {last_std_test}
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]),
1487 return std_tests
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
1499 result = ""
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()]:
1504 result += mk_line(
1505 prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++"))
1507 prefix = ""
1508 result += "*/"
1509 return result
1512 def produce_tests():
1513 headers = set([h for tc in feature_test_macros for h in tc["headers"]])
1514 for h in 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()
1519 continue
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.
1532 // clang-format off
1533 {markup}
1534 // <{header}>
1536 // Test the feature test macros defined by <{header}>
1538 {synopsis}
1540 #include <{header}>
1541 #include "test_macros.h"
1543 {cxx_tests}
1545 """.format(
1546 script_name=script_name,
1547 header=h,
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:
1555 f.write(test_body)
1559 Produce documentation for the feature test macros
1563 def make_widths(grid):
1564 widths = []
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]
1570 return widths
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)]
1577 header_flag = 2
1578 for row_i in range(0, len(grid)):
1579 row = grid[row_i]
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:
1585 header_flag = 2
1586 if row[0].startswith("**"):
1587 header_flag += 1
1588 separator = indent_str + add_divider(col_widths, header_flag)
1589 result.append(separator.rstrip())
1590 header_flag = 0
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])
1601 else:
1602 return " ".join(["-" * w for w in widths])
1605 def pad_cell(s, length, left_align=True):
1606 padding = (length - len(s)) * " "
1607 return s + padding
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():
1616 continue
1617 value = "``%sL``" % tc["values"][std]
1618 if "unimplemented" in tc.keys():
1619 value = "*unimplemented*"
1620 table += [["``%s``" % tc["name"], value]]
1621 return table
1624 def produce_docs():
1625 doc_str = """.. _FeatureTestMacroTable:
1627 ==========================
1628 Feature Test Macro Support
1629 ==========================
1631 .. contents::
1632 :local:
1634 Overview
1635 ========
1637 This file documents the feature test macros currently supported by libc++.
1639 .. _feature-status:
1641 Status
1642 ======
1644 .. table:: Current Status
1645 :name: feature-status-table
1646 :widths: auto
1648 {status_tables}
1650 """.format(
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:
1656 f.write(doc_str)
1659 def main():
1660 produce_version_header()
1661 produce_tests()
1662 produce_docs()
1665 if __name__ == "__main__":
1666 main()