xref: /aosp_15_r20/external/cronet/third_party/libc++/src/utils/generate_feature_test_macro_components.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1#!/usr/bin/env python
2
3import os
4from builtins import range
5from functools import reduce
6
7
8def 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",
24    )
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")
28    )
29    return script_name, src_root, include_path, docs_path, macro_test_path
30
31
32script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths()
33
34
35def has_header(h):
36    h_path = os.path.join(include_path, h)
37    return os.path.exists(h_path)
38
39
40def add_version_header(tc):
41    tc["headers"].append("version")
42    return tc
43
44
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# ================  ============================================================
75feature_test_macros = [
76    add_version_header(x)
77    for x in [
78        {
79            "name": "__cpp_lib_adaptor_iterator_pair_constructor",
80            "values": {"c++23": 202106},
81            "headers": ["queue", "stack"],
82        },
83        {
84            "name": "__cpp_lib_addressof_constexpr",
85            "values": {"c++17": 201603},
86            "headers": ["memory"],
87        },
88        {
89            "name": "__cpp_lib_allocate_at_least",
90            "values": {
91                # Note LWG3887 Version macro for allocate_at_least
92                "c++23": 202302,  # P2652R2 Disallow User Specialization of allocator_traits
93            },
94            "headers": ["memory"],
95        },
96        {
97            "name": "__cpp_lib_allocator_traits_is_always_equal",
98            "values": {"c++17": 201411},
99            "headers": [
100                "deque",
101                "forward_list",
102                "list",
103                "map",
104                "memory",
105                "scoped_allocator",
106                "set",
107                "string",
108                "unordered_map",
109                "unordered_set",
110                "vector",
111            ],
112        },
113        {
114            "name": "__cpp_lib_any",
115            "values": {"c++17": 201606},
116            "headers": ["any"],
117        },
118        {
119            "name": "__cpp_lib_apply",
120            "values": {"c++17": 201603},
121            "headers": ["tuple"],
122        },
123        {
124            "name": "__cpp_lib_array_constexpr",
125            "values": {"c++17": 201603, "c++20": 201811},
126            "headers": ["array", "iterator"],
127        },
128        {
129            "name": "__cpp_lib_as_const",
130            "values": {"c++17": 201510},
131            "headers": ["utility"],
132        },
133        {
134            "name": "__cpp_lib_associative_heterogeneous_erasure",
135            "values": {"c++23": 202110},
136            "headers": ["map", "set", "unordered_map", "unordered_set"],
137            "unimplemented": True,
138        },
139        {
140            "name": "__cpp_lib_associative_heterogeneous_insertion",
141            "values": {
142                "c++26": 202306  # P2363R5 Extending associative containers with the remaining heterogeneous overloads
143            },
144            "headers": ["map", "set", "unordered_map", "unordered_set"],
145            "unimplemented": True,
146        },
147        {
148            "name": "__cpp_lib_assume_aligned",
149            "values": {"c++20": 201811},
150            "headers": ["memory"],
151        },
152        {
153            "name": "__cpp_lib_atomic_flag_test",
154            "values": {"c++20": 201907},
155            "headers": ["atomic"],
156        },
157        {
158            "name": "__cpp_lib_atomic_float",
159            "values": {"c++20": 201711},
160            "headers": ["atomic"],
161            "unimplemented": True,
162        },
163        {
164            "name": "__cpp_lib_atomic_is_always_lock_free",
165            "values": {"c++17": 201603},
166            "headers": ["atomic"],
167        },
168        {
169            "name": "__cpp_lib_atomic_lock_free_type_aliases",
170            "values": {"c++20": 201907},
171            "headers": ["atomic"],
172        },
173        {
174            "name": "__cpp_lib_atomic_ref",
175            "values": {"c++20": 201806},
176            "headers": ["atomic"],
177            "unimplemented": True,
178        },
179        {
180            "name": "__cpp_lib_atomic_shared_ptr",
181            "values": {"c++20": 201711},
182            "headers": ["atomic"],
183            "unimplemented": True,
184        },
185        {
186            "name": "__cpp_lib_atomic_value_initialization",
187            "values": {"c++20": 201911},
188            "headers": ["atomic", "memory"],
189        },
190        {
191            "name": "__cpp_lib_atomic_wait",
192            "values": {"c++20": 201907},
193            "headers": ["atomic"],
194            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC",
195            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_SYNC",
196        },
197        {
198            "name": "__cpp_lib_barrier",
199            "values": {"c++20": 201907},
200            "headers": ["barrier"],
201            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
202            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
203        },
204        {
205            "name": "__cpp_lib_bind_back",
206            "values": {
207                "c++23": 202202,
208                "c++26": 202306,  # P2714R1 Bind front and back to NTTP callables
209            },
210            "headers": ["functional"],
211            "unimplemented": True,
212        },
213        {
214            "name": "__cpp_lib_bind_front",
215            "values": {
216                "c++20": 201907,
217                "c++26": 202306,  # P2714R1 Bind front and back to NTTP callables
218            },
219            "headers": ["functional"],
220        },
221        {
222            "name": "__cpp_lib_bit_cast",
223            "values": {"c++20": 201806},
224            "headers": ["bit"],
225        },
226        {
227            "name": "__cpp_lib_bitops",
228            "values": {"c++20": 201907},
229            "headers": ["bit"],
230        },
231        {
232            "name": "__cpp_lib_bitset",
233            "values": {"c++26": 202306},  # P2697R1 Interfacing bitset with string_view
234            "headers": ["bitset"],
235        },
236        {
237            "name": "__cpp_lib_bool_constant",
238            "values": {"c++17": 201505},
239            "headers": ["type_traits"],
240        },
241        {
242            "name": "__cpp_lib_bounded_array_traits",
243            "values": {"c++20": 201902},
244            "headers": ["type_traits"],
245        },
246        {
247            "name": "__cpp_lib_boyer_moore_searcher",
248            "values": {"c++17": 201603},
249            "headers": ["functional"],
250        },
251        {
252            "name": "__cpp_lib_byte",
253            "values": {"c++17": 201603},
254            "headers": ["cstddef"],
255        },
256        {
257            "name": "__cpp_lib_byteswap",
258            "values": {"c++23": 202110},
259            "headers": ["bit"],
260        },
261        {
262            "name": "__cpp_lib_char8_t",
263            "values": {"c++20": 201907},
264            "headers": [
265                "atomic",
266                "filesystem",
267                "istream",
268                "limits",
269                "locale",
270                "ostream",
271                "string",
272                "string_view",
273            ],
274            "test_suite_guard": "defined(__cpp_char8_t)",
275            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CHAR8_T)",
276        },
277        {
278            "name": "__cpp_lib_chrono",
279            "values": {
280                "c++17": 201611,
281                # "c++26": 202306, # P2592R3 Hashing support for std::chrono value classes
282            },
283            "headers": ["chrono"],
284        },
285        {
286            "name": "__cpp_lib_chrono_udls",
287            "values": {"c++14": 201304},
288            "headers": ["chrono"],
289        },
290        {
291            "name": "__cpp_lib_clamp",
292            "values": {"c++17": 201603},
293            "headers": ["algorithm"],
294        },
295        {
296            "name": "__cpp_lib_complex_udls",
297            "values": {"c++14": 201309},
298            "headers": ["complex"],
299        },
300        {
301            "name": "__cpp_lib_concepts",
302            "values": {"c++20": 202002},
303            "headers": ["concepts"],
304        },
305        {
306            "name": "__cpp_lib_constexpr_algorithms",
307            "values": {
308                "c++20": 201806,
309                # "c++26": 202306, # P2562R1 constexpr Stable Sorting
310            },
311            "headers": ["algorithm", "utility"],
312        },
313        {
314            "name": "__cpp_lib_constexpr_bitset",
315            "values": {"c++23": 202207},
316            "headers": ["bitset"],
317        },
318        {
319            "name": "__cpp_lib_constexpr_charconv",
320            "values": {"c++23": 202207},
321            "headers": ["charconv"],
322        },
323        {
324            "name": "__cpp_lib_constexpr_cmath",
325            "values": {"c++23": 202202},
326            "headers": ["cmath", "cstdlib"],
327            "unimplemented": True,
328        },
329        {
330            "name": "__cpp_lib_constexpr_complex",
331            "values": {"c++20": 201711},
332            "headers": ["complex"],
333        },
334        {
335            "name": "__cpp_lib_constexpr_dynamic_alloc",
336            "values": {"c++20": 201907},
337            "headers": ["memory"],
338        },
339        {
340            "name": "__cpp_lib_constexpr_functional",
341            "values": {"c++20": 201907},
342            "headers": ["functional"],
343        },
344        {
345            "name": "__cpp_lib_constexpr_iterator",
346            "values": {"c++20": 201811},
347            "headers": ["iterator"],
348        },
349        {
350            "name": "__cpp_lib_constexpr_memory",
351            "values": {"c++20": 201811, "c++23": 202202},
352            "headers": ["memory"],
353        },
354        {
355            "name": "__cpp_lib_constexpr_numeric",
356            "values": {"c++20": 201911},
357            "headers": ["numeric"],
358        },
359        {
360            "name": "__cpp_lib_constexpr_string",
361            "values": {"c++20": 201907},
362            "headers": ["string"],
363        },
364        {
365            "name": "__cpp_lib_constexpr_string_view",
366            "values": {"c++20": 201811},
367            "headers": ["string_view"],
368        },
369        {
370            "name": "__cpp_lib_constexpr_tuple",
371            "values": {"c++20": 201811},
372            "headers": ["tuple"],
373        },
374        {
375            "name": "__cpp_lib_constexpr_typeinfo",
376            "values": {"c++23": 202106},
377            "headers": ["typeinfo"],
378        },
379        {
380            "name": "__cpp_lib_constexpr_utility",
381            "values": {"c++20": 201811},
382            "headers": ["utility"],
383        },
384        {
385            "name": "__cpp_lib_constexpr_vector",
386            "values": {"c++20": 201907},
387            "headers": ["vector"],
388        },
389        {
390            "name": "__cpp_lib_copyable_function",
391            "values": {"c++26": 202306},  # P2548R6 copyable_function
392            "headers": ["functional"],
393            "unimplemented": True,
394        },
395        {
396            "name": "__cpp_lib_coroutine",
397            "values": {"c++20": 201902},
398            "headers": ["coroutine"],
399        },
400        {
401            "name": "__cpp_lib_debugging",
402            "values": {"c++26": 202311},  # P2546R5 Debugging Support
403            "headers": ["debugging"],
404            "unimplemented": True,
405        },
406        {
407            "name": "__cpp_lib_destroying_delete",
408            "values": {"c++20": 201806},
409            "headers": ["new"],
410            "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
411            "libcxx_guard": "_LIBCPP_STD_VER >= 20 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
412        },
413        {
414            "name": "__cpp_lib_enable_shared_from_this",
415            "values": {"c++17": 201603},
416            "headers": ["memory"],
417        },
418        {
419            "name": "__cpp_lib_endian",
420            "values": {"c++20": 201907},
421            "headers": ["bit"],
422        },
423        {
424            "name": "__cpp_lib_erase_if",
425            "values": {"c++20": 202002},
426            "headers": [
427                "deque",
428                "forward_list",
429                "list",
430                "map",
431                "set",
432                "string",
433                "unordered_map",
434                "unordered_set",
435                "vector",
436            ],
437        },
438        {
439            "name": "__cpp_lib_exchange_function",
440            "values": {"c++14": 201304},
441            "headers": ["utility"],
442        },
443        {
444            "name": "__cpp_lib_execution",
445            "values": {"c++17": 201603, "c++20": 201902},
446            "headers": ["execution"],
447            "unimplemented": True,
448        },
449        {
450            "name": "__cpp_lib_expected",
451            "values": {"c++23": 202211},
452            "headers": ["expected"],
453        },
454        {
455            "name": "__cpp_lib_filesystem",
456            "values": {"c++17": 201703},
457            "headers": ["filesystem"],
458            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (!defined(_LIBCPP_HAS_NO_FILESYSTEM) && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)",
459            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_FILESYSTEM) && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY",
460        },
461        {
462            "name": "__cpp_lib_format",
463            "values": {
464                # "c++20": 201907 Not implemented P1361R2 Integration of chrono with text formatting
465                # "c++20": 202106 Fully implemented
466                # "c++20": 202110 Not implemented P2372R3 Fixing locale handling in chrono formatters
467                "c++20": 202106,
468                # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types
469                # "c++26": 202306, P2637R3 Member Visit (implemented)
470                # "c++26": 202311, P2918R2 Runtime format strings II (implemented)
471            },
472            # Note these three papers are adopted at the June 2023 meeting and have sequential numbering
473            # 202304 P2510R3 Formatting pointers (Implemented)
474            # 202305 P2757R3 Type-checking format args
475            # 202306 P2637R3 Member Visit
476            "headers": ["format"],
477            "unimplemented": True,
478        },
479        {
480            "name": "__cpp_lib_format_ranges",
481            "values": {"c++23": 202207},
482            "headers": ["format"],
483        },
484        {
485            "name": "__cpp_lib_format_uchar",
486            "values": {
487                "c++20": 202311  # DR P2909R4 Fix formatting of code units as integers
488            },
489            "headers": [
490                "format"  # TODO verify this entry since the paper was underspecified.
491            ],
492        },
493        {
494            "name": "__cpp_lib_formatters",
495            "values": {"c++23": 202302},
496            "headers": ["stacktrace", "thread"],
497            "unimplemented": True,
498        },
499        {
500            "name": "__cpp_lib_forward_like",
501            "values": {"c++23": 202207},
502            "headers": ["utility"],
503        },
504        {
505            "name": "__cpp_lib_freestanding_algorithm",
506            "values": {
507                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
508            },
509            "headers": ["algorithm"],
510            "unimplemented": True,
511        },
512        {
513            "name": "__cpp_lib_freestanding_array",
514            "values": {
515                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
516            },
517            "headers": ["array"],
518            "unimplemented": True,
519        },
520        {
521            "name": "__cpp_lib_freestanding_cstring",
522            "values": {
523                "c++26": 202306  # P2338R4 Freestanding Library: Character primitives and the C library
524                #        202311  # P2407R5 Freestanding Library: Partial Classes
525            },
526            "headers": ["cstring"],
527            "unimplemented": True,
528        },
529        {
530            "name": "__cpp_lib_freestanding_expected",
531            "values": {
532                "c++26": 202311  # P2833R2 Freestanding Library: inout expected span
533            },
534            "headers": ["expected"],
535            "unimplemented": True,
536        },
537        {
538            "name": "__cpp_lib_freestanding_mdspan",
539            "values": {
540                "c++26": 202311  # P2833R2 Freestanding Library: inout expected span
541            },
542            "headers": ["mdspan"],
543            "unimplemented": True,
544        },
545        {
546            "name": "__cpp_lib_freestanding_optional",
547            "values": {
548                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
549            },
550            "headers": ["optional"],
551            "unimplemented": True,
552        },
553        {
554            "name": "__cpp_lib_freestanding_string_view",
555            "values": {
556                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
557            },
558            "headers": ["string_view"],
559            "unimplemented": True,
560        },
561        {
562            "name": "__cpp_lib_freestanding_variant",
563            "values": {
564                "c++26": 202311  # P2407R5 Freestanding Library: Partial Classes
565            },
566            "headers": ["variant"],
567            "unimplemented": True,
568        },
569        {
570            "name": "__cpp_lib_fstream_native_handle",
571            "values": {"c++26": 202306},  # P1759R6 Native handles and file streams
572            "headers": ["fstream"],
573            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (!defined(_LIBCPP_HAS_NO_FILESYSTEM) && !defined(_LIBCPP_HAS_NO_LOCALIZATION))",
574            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_FILESYSTEM) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)",
575        },
576        {
577            "name": "__cpp_lib_function_ref",
578            "values": {
579                "c++26": 202306  # P0792R14 function_ref: a type-erased callable reference
580            },
581            "headers": ["functional"],
582            "unimplemented": True,
583        },
584        {
585            "name": "__cpp_lib_gcd_lcm",
586            "values": {"c++17": 201606},
587            "headers": ["numeric"],
588        },
589        {
590            "name": "__cpp_lib_generic_associative_lookup",
591            "values": {"c++14": 201304},
592            "headers": ["map", "set"],
593        },
594        {
595            "name": "__cpp_lib_generic_unordered_lookup",
596            "values": {"c++20": 201811},
597            "headers": ["unordered_map", "unordered_set"],
598        },
599        {
600            "name": "__cpp_lib_hardware_interference_size",
601            "values": {"c++17": 201703},
602            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE))",
603            "libcxx_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)",
604            "headers": ["new"],
605        },
606        {
607            "name": "__cpp_lib_has_unique_object_representations",
608            "values": {"c++17": 201606},
609            "headers": ["type_traits"],
610        },
611        {
612            "name": "__cpp_lib_hazard_pointer",
613            "values": {"c++26": 202306},  # P2530R3 Hazard Pointers for C++26
614            "headers": [
615                "hazard_pointer"  # TODO verify this entry since the paper was underspecified.
616            ],
617            "unimplemented": True,
618        },
619        {
620            "name": "__cpp_lib_hypot",
621            "values": {"c++17": 201603},
622            "headers": ["cmath"],
623        },
624        {
625            "name": "__cpp_lib_incomplete_container_elements",
626            "values": {"c++17": 201505},
627            "headers": ["forward_list", "list", "vector"],
628        },
629        {
630            "name": "__cpp_lib_int_pow2",
631            "values": {"c++20": 202002},
632            "headers": ["bit"],
633        },
634        {
635            "name": "__cpp_lib_integer_comparison_functions",
636            "values": {"c++20": 202002},
637            "headers": ["utility"],
638        },
639        {
640            "name": "__cpp_lib_integer_sequence",
641            "values": {"c++14": 201304},
642            "headers": ["utility"],
643        },
644        {
645            "name": "__cpp_lib_integral_constant_callable",
646            "values": {"c++14": 201304},
647            "headers": ["type_traits"],
648        },
649        {
650            "name": "__cpp_lib_interpolate",
651            "values": {"c++20": 201902},
652            "headers": ["cmath", "numeric"],
653        },
654        {
655            "name": "__cpp_lib_invoke",
656            "values": {"c++17": 201411},
657            "headers": ["functional"],
658        },
659        {
660            "name": "__cpp_lib_invoke_r",
661            "values": {"c++23": 202106},
662            "headers": ["functional"],
663        },
664        {
665            "name": "__cpp_lib_ios_noreplace",
666            "values": {"c++23": 202207},
667            "headers": ["ios"],
668        },
669        {
670            "name": "__cpp_lib_is_aggregate",
671            "values": {"c++17": 201703},
672            "headers": ["type_traits"],
673        },
674        {
675            "name": "__cpp_lib_is_constant_evaluated",
676            "values": {"c++20": 201811},
677            "headers": ["type_traits"],
678        },
679        {
680            "name": "__cpp_lib_is_final",
681            "values": {"c++14": 201402},
682            "headers": ["type_traits"],
683        },
684        {
685            "name": "__cpp_lib_is_invocable",
686            "values": {"c++17": 201703},
687            "headers": ["type_traits"],
688        },
689        {
690            "name": "__cpp_lib_is_layout_compatible",
691            "values": {"c++20": 201907},
692            "headers": ["type_traits"],
693            "unimplemented": True,
694        },
695        {
696            "name": "__cpp_lib_is_nothrow_convertible",
697            "values": {"c++20": 201806},
698            "headers": ["type_traits"],
699        },
700        {
701            "name": "__cpp_lib_is_null_pointer",
702            "values": {"c++14": 201309},
703            "headers": ["type_traits"],
704        },
705        {
706            "name": "__cpp_lib_is_pointer_interconvertible",
707            "values": {"c++20": 201907},
708            "headers": ["type_traits"],
709            "unimplemented": True,
710        },
711        {
712            "name": "__cpp_lib_is_scoped_enum",
713            "values": {"c++23": 202011},
714            "headers": ["type_traits"],
715        },
716        {
717            "name": "__cpp_lib_is_swappable",
718            "values": {"c++17": 201603},
719            "headers": ["type_traits"],
720        },
721        {
722            "name": "__cpp_lib_jthread",
723            "values": {"c++20": 201911},
724            "headers": ["stop_token", "thread"],
725            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
726            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN) && _LIBCPP_AVAILABILITY_HAS_SYNC",
727        },
728        {
729            "name": "__cpp_lib_latch",
730            "values": {"c++20": 201907},
731            "headers": ["latch"],
732            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
733            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
734        },
735        {
736            "name": "__cpp_lib_launder",
737            "values": {"c++17": 201606},
738            "headers": ["new"],
739        },
740        {
741            "name": "__cpp_lib_linalg",
742            "values": {
743                "c++26": 202311  # P1673 A free function linear algebra interface based on the BLAS
744            },
745            "headers": ["linalg"],
746            "unimplemented": True,
747        },
748        {
749            "name": "__cpp_lib_list_remove_return_type",
750            "values": {"c++20": 201806},
751            "headers": ["forward_list", "list"],
752        },
753        {
754            "name": "__cpp_lib_logical_traits",
755            "values": {"c++17": 201510},
756            "headers": ["type_traits"],
757        },
758        {
759            "name": "__cpp_lib_make_from_tuple",
760            "values": {"c++17": 201606},
761            "headers": ["tuple"],
762        },
763        {
764            "name": "__cpp_lib_make_reverse_iterator",
765            "values": {"c++14": 201402},
766            "headers": ["iterator"],
767        },
768        {
769            "name": "__cpp_lib_make_unique",
770            "values": {"c++14": 201304},
771            "headers": ["memory"],
772        },
773        {
774            "name": "__cpp_lib_map_try_emplace",
775            "values": {"c++17": 201411},
776            "headers": ["map"],
777        },
778        {
779            "name": "__cpp_lib_math_constants",
780            "values": {"c++20": 201907},
781            "headers": ["numbers"],
782        },
783        {
784            "name": "__cpp_lib_math_special_functions",
785            "values": {"c++17": 201603},
786            "headers": ["cmath"],
787            "unimplemented": True,
788        },
789        {
790            "name": "__cpp_lib_mdspan",
791            "values": {"c++23": 202207},
792            "headers": ["mdspan"],
793        },
794        {
795            "name": "__cpp_lib_memory_resource",
796            "values": {"c++17": 201603},
797            "headers": ["memory_resource"],
798            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",
799            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",
800        },
801        {
802            "name": "__cpp_lib_move_iterator_concept",
803            "values": {"c++20": 202207},
804            "headers": ["iterator"],
805        },
806        {
807            "name": "__cpp_lib_move_only_function",
808            "values": {"c++23": 202110},
809            "headers": ["functional"],
810            "unimplemented": True,
811        },
812        {
813            "name": "__cpp_lib_node_extract",
814            "values": {"c++17": 201606},
815            "headers": ["map", "set", "unordered_map", "unordered_set"],
816        },
817        {
818            "name": "__cpp_lib_nonmember_container_access",
819            "values": {"c++17": 201411},
820            "headers": [
821                "array",
822                "deque",
823                "forward_list",
824                "iterator",
825                "list",
826                "map",
827                "regex",
828                "set",
829                "string",
830                "unordered_map",
831                "unordered_set",
832                "vector",
833            ],
834        },
835        {
836            "name": "__cpp_lib_not_fn",
837            "values": {
838                "c++17": 201603,
839                # "c++26": 202306, # P2714R1 Bind front and back to NTTP callables
840            },
841            "headers": ["functional"],
842        },
843        {
844            "name": "__cpp_lib_null_iterators",
845            "values": {"c++14": 201304},
846            "headers": ["iterator"],
847        },
848        {
849            "name": "__cpp_lib_optional",
850            "values": {"c++17": 201606, "c++23": 202110},
851            "headers": ["optional"],
852        },
853        {
854            "name": "__cpp_lib_out_ptr",
855            "values": {
856                "c++23": 202106,
857                "c++26": 202311,  # P2833R2 Freestanding Library: inout expected span
858            },
859            "headers": ["memory"],
860            "unimplemented": True,
861        },
862        {
863            "name": "__cpp_lib_parallel_algorithm",
864            "values": {"c++17": 201603},
865            "headers": ["algorithm", "numeric"],
866            "unimplemented": True,
867        },
868        {
869            "name": "__cpp_lib_polymorphic_allocator",
870            "values": {"c++20": 201902},
871            "headers": ["memory_resource"],
872            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR",
873            "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR",
874        },
875        {
876            "name": "__cpp_lib_print",
877            "values": {"c++23": 202207},
878            "headers": ["ostream", "print"],
879        },
880        {
881            "name": "__cpp_lib_quoted_string_io",
882            "values": {"c++14": 201304},
883            "headers": ["iomanip"],
884            "test_suite_guard": "!defined(_LIBCPP_VERSION) || !defined(_LIBCPP_HAS_NO_LOCALIZATION)",
885            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
886        },
887        {
888            "name": "__cpp_lib_ranges",
889            "values": {"c++20": 202207},
890            "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
891        },
892        {
893            "name": "__cpp_lib_ranges_as_const",
894            "values": {
895                "c++23": 202207  # P2278R4 cbegin should always return a constant iterator
896                #        202311  # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility
897            },
898            "headers": ["ranges"],
899            "unimplemented": True,
900        },
901        {
902            "name": "__cpp_lib_ranges_as_rvalue",
903            "values": {"c++23": 202207},
904            "headers": ["ranges"],
905        },
906        {
907            "name": "__cpp_lib_ranges_chunk",
908            "values": {"c++23": 202202},
909            "headers": ["ranges"],
910            "unimplemented": True,
911        },
912        {
913            "name": "__cpp_lib_ranges_chunk_by",
914            "values": {"c++23": 202202},
915            "headers": ["ranges"],
916        },
917        {
918            "name": "__cpp_lib_ranges_contains",
919            "values": {"c++23": 202207},
920            "headers": ["algorithm"],
921        },
922        {
923            "name": "__cpp_lib_ranges_iota",
924            "values": {"c++23": 202202},
925            "headers": ["numeric"],
926            "unimplemented": True,
927        },
928        {
929            "name": "__cpp_lib_ranges_join_with",
930            "values": {"c++23": 202202},
931            "headers": ["ranges"],
932            "unimplemented": True,
933        },
934        {
935            "name": "__cpp_lib_ranges_repeat",
936            "values": {"c++23": 202207},
937            "headers": ["ranges"],
938        },
939        {
940            "name": "__cpp_lib_ranges_slide",
941            "values": {"c++23": 202202},
942            "headers": ["ranges"],
943            "unimplemented": True,
944        },
945        {
946            "name": "__cpp_lib_ranges_starts_ends_with",
947            "values": {"c++23": 202106},
948            "headers": ["algorithm"],
949        },
950        {
951            "name": "__cpp_lib_ranges_to_container",
952            "values": {"c++23": 202202},
953            "headers": [
954                "deque",
955                "forward_list",
956                "list",
957                "map",
958                "queue",
959                "ranges",
960                "set",
961                "stack",
962                "string",
963                "unordered_map",
964                "unordered_set",
965                "vector",
966            ],
967        },
968        {
969            "name": "__cpp_lib_ranges_zip",
970            "values": {"c++23": 202110},
971            "headers": ["ranges", "tuple", "utility"],
972            "unimplemented": True,
973        },
974        {
975            "name": "__cpp_lib_ratio",
976            "values": {"c++26": 202306},  # P2734R0 Adding the new SI prefixes
977            "headers": ["ratio"],
978        },
979        {
980            "name": "__cpp_lib_raw_memory_algorithms",
981            "values": {"c++17": 201606},
982            "headers": ["memory"],
983        },
984        {
985            "name": "__cpp_lib_rcu",
986            "values": {"c++26": 202306},  # P2545R4 Read-Copy Update (RCU)
987            "headers": [
988                "rcu"  # TODO verify this entry since the paper was underspecified.
989            ],
990            "unimplemented": True,
991        },
992        {
993            "name": "__cpp_lib_reference_from_temporary",
994            "values": {"c++23": 202202},
995            "headers": ["type_traits"],
996            "unimplemented": True,
997        },
998        {
999            "name": "__cpp_lib_remove_cvref",
1000            "values": {"c++20": 201711},
1001            "headers": ["type_traits"],
1002        },
1003        {
1004            "name": "__cpp_lib_result_of_sfinae",
1005            "values": {"c++14": 201210},
1006            "headers": ["functional", "type_traits"],
1007        },
1008        {
1009            "name": "__cpp_lib_robust_nonmodifying_seq_ops",
1010            "values": {"c++14": 201304},
1011            "headers": ["algorithm"],
1012        },
1013        {
1014            "name": "__cpp_lib_sample",
1015            "values": {"c++17": 201603},
1016            "headers": ["algorithm"],
1017        },
1018        {
1019            "name": "__cpp_lib_saturation_arithmetic",
1020            "values": {"c++26": 202311},  # P0543R3 Saturation arithmetic
1021            "headers": ["numeric"],
1022        },
1023        {
1024            "name": "__cpp_lib_scoped_lock",
1025            "values": {"c++17": 201703},
1026            "headers": ["mutex"],
1027            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1028            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1029        },
1030        {
1031            "name": "__cpp_lib_semaphore",
1032            "values": {"c++20": 201907},
1033            "headers": ["semaphore"],
1034            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
1035            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
1036        },
1037        {
1038            "name": "__cpp_lib_shared_mutex",
1039            "values": {"c++17": 201505},
1040            "headers": ["shared_mutex"],
1041            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1042            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1043        },
1044        {
1045            "name": "__cpp_lib_shared_ptr_arrays",
1046            "values": {"c++17": 201611, "c++20": 201707},
1047            "headers": ["memory"],
1048        },
1049        {
1050            "name": "__cpp_lib_shared_ptr_weak_type",
1051            "values": {"c++17": 201606},
1052            "headers": ["memory"],
1053        },
1054        {
1055            "name": "__cpp_lib_shared_timed_mutex",
1056            "values": {"c++14": 201402},
1057            "headers": ["shared_mutex"],
1058            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1059            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
1060        },
1061        {
1062            "name": "__cpp_lib_shift",
1063            "values": {"c++20": 201806},
1064            "headers": ["algorithm"],
1065        },
1066        {
1067            "name": "__cpp_lib_smart_ptr_for_overwrite",
1068            "values": {"c++20": 202002},
1069            "headers": ["memory"],
1070            "unimplemented": True,
1071        },
1072        {
1073            "name": "__cpp_lib_smart_ptr_owner_equality",
1074            "values": {
1075                "c++26": 202306  # P1901R2 Enabling the Use of weak_ptr as Keys in Unordered Associative Containers
1076            },
1077            "headers": ["memory"],
1078            "unimplemented": True,
1079        },
1080        {
1081            "name": "__cpp_lib_source_location",
1082            "values": {"c++20": 201907},
1083            "headers": ["source_location"],
1084        },
1085        {
1086            "name": "__cpp_lib_span",
1087            "values": {
1088                "c++20": 202002,
1089                # "c++26": 202311,  # P2821R5 span.at()
1090                #          202311   # P2833R2 Freestanding Library: inout expected span
1091            },
1092            "headers": ["span"],
1093        },
1094        {
1095            "name": "__cpp_lib_span_at",
1096            "values": {"c++26": 202311},  # P2821R3 span.at()
1097            "headers": ["span"],
1098        },
1099        {
1100            "name": "__cpp_lib_span_initializer_list",
1101            "values": {"c++26": 202311},  # P2447R6 std::span over an initializer list
1102            "headers": ["span"],
1103        },
1104        {
1105            "name": "__cpp_lib_spanstream",
1106            "values": {"c++23": 202106},
1107            "headers": ["spanstream"],
1108            "unimplemented": True,
1109        },
1110        {
1111            "name": "__cpp_lib_ssize",
1112            "values": {"c++20": 201902},
1113            "headers": ["iterator"],
1114        },
1115        {
1116            "name": "__cpp_lib_sstream_from_string_view",
1117            "values": {
1118                "c++26": 202306  # P2495R3 Interfacing stringstreams with string_view
1119            },
1120            "headers": ["sstream"],
1121        },
1122        {
1123            "name": "__cpp_lib_stacktrace",
1124            "values": {"c++23": 202011},
1125            "headers": ["stacktrace"],
1126            "unimplemented": True,
1127        },
1128        {
1129            "name": "__cpp_lib_starts_ends_with",
1130            "values": {"c++20": 201711},
1131            "headers": ["string", "string_view"],
1132        },
1133        {
1134            "name": "__cpp_lib_stdatomic_h",
1135            "values": {"c++23": 202011},
1136            "headers": ["stdatomic.h"],
1137        },
1138        {
1139            "name": "__cpp_lib_string_contains",
1140            "values": {"c++23": 202011},
1141            "headers": ["string", "string_view"],
1142        },
1143        {
1144            "name": "__cpp_lib_string_resize_and_overwrite",
1145            "values": {"c++23": 202110},
1146            "headers": ["string"],
1147        },
1148        {
1149            "name": "__cpp_lib_string_udls",
1150            "values": {"c++14": 201304},
1151            "headers": ["string"],
1152        },
1153        {
1154            "name": "__cpp_lib_string_view",
1155            "values": {"c++17": 201606, "c++20": 201803},
1156            "headers": ["string", "string_view"],
1157        },
1158        {
1159            "name": "__cpp_lib_submdspan",
1160            "values": {"c++26": 202306},  # P2630R4 submdspan
1161            "headers": ["mdspan"],
1162            "unimplemented": True,
1163        },
1164        {
1165            "name": "__cpp_lib_syncbuf",
1166            "values": {"c++20": 201803},
1167            "headers": ["syncstream"],
1168            "test_suite_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)",
1169            "libcxx_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)",
1170        },
1171        {
1172            "name": "__cpp_lib_text_encoding",
1173            "values": {
1174                "c++26": 202306  # P1885R12 Naming Text Encodings to Demystify Them
1175            },
1176            "headers": ["text_encoding"],
1177            "unimplemented": True,
1178        },
1179        {
1180            "name": "__cpp_lib_three_way_comparison",
1181            "values": {"c++20": 201907},
1182            "headers": ["compare"],
1183            "unimplemented": True,
1184        },
1185        {
1186            "name": "__cpp_lib_to_address",
1187            "values": {"c++20": 201711},
1188            "headers": ["memory"],
1189        },
1190        {
1191            "name": "__cpp_lib_to_array",
1192            "values": {"c++20": 201907},
1193            "headers": ["array"],
1194        },
1195        {
1196            "name": "__cpp_lib_to_chars",
1197            "values": {
1198                "c++17": 201611,
1199                "c++26": 202306,  # P2497R0 Testing for success or failure of <charconv> functions
1200            },
1201            "headers": ["charconv"],
1202            "unimplemented": True,
1203        },
1204        {
1205            "name": "__cpp_lib_to_string",
1206            "values": {"c++23": 202306},  # P2587R3 to_string or not to_string
1207            "headers": ["string"],
1208            "unimplemented": True,
1209        },
1210        {
1211            "name": "__cpp_lib_to_underlying",
1212            "values": {"c++23": 202102},
1213            "headers": ["utility"],
1214        },
1215        {
1216            "name": "__cpp_lib_transformation_trait_aliases",
1217            "values": {"c++14": 201304},
1218            "headers": ["type_traits"],
1219        },
1220        {
1221            "name": "__cpp_lib_transparent_operators",
1222            "values": {"c++14": 201210, "c++17": 201510},
1223            "headers": ["functional", "memory"],
1224        },
1225        {
1226            "name": "__cpp_lib_tuple_element_t",
1227            "values": {"c++14": 201402},
1228            "headers": ["tuple"],
1229        },
1230        {
1231            "name": "__cpp_lib_tuple_like",
1232            "values": {
1233                "c++23": 202207,  # P2165R4 Compatibility between tuple, pair and tuple-like objects
1234                "c++26": 202311,  # P2819R2 Add tuple protocol to complex (implemented)
1235            },
1236            "headers": ["map", "tuple", "unordered_map", "utility"],
1237            "unimplemented": True,
1238        },
1239        {
1240            "name": "__cpp_lib_tuples_by_type",
1241            "values": {"c++14": 201304},
1242            "headers": ["tuple", "utility"],
1243        },
1244        {
1245            "name": "__cpp_lib_type_identity",
1246            "values": {"c++20": 201806},
1247            "headers": ["type_traits"],
1248        },
1249        {
1250            "name": "__cpp_lib_type_trait_variable_templates",
1251            "values": {"c++17": 201510},
1252            "headers": ["type_traits"],
1253        },
1254        {
1255            "name": "__cpp_lib_uncaught_exceptions",
1256            "values": {"c++17": 201411},
1257            "headers": ["exception"],
1258        },
1259        {
1260            "name": "__cpp_lib_unordered_map_try_emplace",
1261            "values": {"c++17": 201411},
1262            "headers": ["unordered_map"],
1263        },
1264        {
1265            "name": "__cpp_lib_unreachable",
1266            "values": {"c++23": 202202},
1267            "headers": ["utility"],
1268        },
1269        {
1270            "name": "__cpp_lib_unwrap_ref",
1271            "values": {"c++20": 201811},
1272            "headers": ["functional"],
1273        },
1274        {
1275            "name": "__cpp_lib_variant",
1276            "values": {
1277                "c++17": 202102,  # std::visit for classes derived from std::variant
1278                # "c++20": 202106,  # Fully constexpr std::variant
1279                # "c++26": 202306,  # Member visit (implemented)
1280            },
1281            "headers": ["variant"],
1282        },
1283        {
1284            "name": "__cpp_lib_void_t",
1285            "values": {"c++17": 201411},
1286            "headers": ["type_traits"],
1287        },
1288        {
1289            "name": "__cpp_lib_within_lifetime",
1290            "values": {
1291                "c++26": 202306  # P2641R4 Checking if a union alternative is active
1292            },
1293            "headers": ["type_traits"],
1294            "unimplemented": True,
1295        },
1296    ]
1297]
1298
1299assert feature_test_macros == sorted(feature_test_macros, key=lambda tc: tc["name"])
1300assert all(tc["headers"] == sorted(tc["headers"]) for tc in feature_test_macros)
1301assert all(
1302    ("libcxx_guard" in tc) == ("test_suite_guard" in tc) for tc in feature_test_macros
1303)
1304assert all(
1305    all(
1306        key
1307        in [
1308            "name",
1309            "values",
1310            "headers",
1311            "libcxx_guard",
1312            "test_suite_guard",
1313            "unimplemented",
1314        ]
1315        for key in tc.keys()
1316    )
1317    for tc in feature_test_macros
1318)
1319
1320# Map from each header to the Lit annotations that should be used for
1321# tests that include that header.
1322#
1323# For example, when threads are not supported, any test that includes
1324# <thread> should be marked as UNSUPPORTED, because including <thread>
1325# is a hard error in that case.
1326lit_markup = {
1327    "barrier": ["UNSUPPORTED: no-threads"],
1328    "filesystem": ["UNSUPPORTED: no-filesystem"],
1329    "fstream": ["UNSUPPORTED: no-localization"],
1330    "iomanip": ["UNSUPPORTED: no-localization"],
1331    "ios": ["UNSUPPORTED: no-localization"],
1332    "iostream": ["UNSUPPORTED: no-localization"],
1333    "istream": ["UNSUPPORTED: no-localization"],
1334    "latch": ["UNSUPPORTED: no-threads"],
1335    "locale": ["UNSUPPORTED: no-localization"],
1336    "mutex": ["UNSUPPORTED: no-threads"],
1337    "ostream": ["UNSUPPORTED: no-localization"],
1338    "print": ["UNSUPPORTED: no-filesystem"],
1339    "regex": ["UNSUPPORTED: no-localization"],
1340    "semaphore": ["UNSUPPORTED: no-threads"],
1341    "shared_mutex": ["UNSUPPORTED: no-threads"],
1342    "sstream": ["UNSUPPORTED: no-localization"],
1343    "syncstream": ["UNSUPPORTED: no-localization"],
1344    "stdatomic.h": ["UNSUPPORTED: no-threads"],
1345    "stop_token": ["UNSUPPORTED: no-threads"],
1346    "thread": ["UNSUPPORTED: no-threads"],
1347}
1348
1349
1350def get_std_dialects():
1351    std_dialects = ["c++14", "c++17", "c++20", "c++23", "c++26"]
1352    return list(std_dialects)
1353
1354
1355def get_first_std(d):
1356    for s in get_std_dialects():
1357        if s in d.keys():
1358            return s
1359    return None
1360
1361
1362def get_last_std(d):
1363    rev_dialects = get_std_dialects()
1364    rev_dialects.reverse()
1365    for s in rev_dialects:
1366        if s in d.keys():
1367            return s
1368    return None
1369
1370
1371def get_std_before(d, std):
1372    std_dialects = get_std_dialects()
1373    candidates = std_dialects[0 : std_dialects.index(std)]
1374    candidates.reverse()
1375    for cand in candidates:
1376        if cand in d.keys():
1377            return cand
1378    return None
1379
1380
1381def get_value_before(d, std):
1382    new_std = get_std_before(d, std)
1383    if new_std is None:
1384        return None
1385    return d[new_std]
1386
1387
1388def get_for_std(d, std):
1389    # This catches the C++11 case for which there should be no defined feature
1390    # test macros.
1391    std_dialects = get_std_dialects()
1392    if std not in std_dialects:
1393        return None
1394    # Find the value for the newest C++ dialect between C++14 and std
1395    std_list = list(std_dialects[0 : std_dialects.index(std) + 1])
1396    std_list.reverse()
1397    for s in std_list:
1398        if s in d.keys():
1399            return d[s]
1400    return None
1401
1402
1403def get_std_number(std):
1404    return std.replace("c++", "")
1405
1406
1407"""
1408  Functions to produce the <version> header
1409"""
1410
1411
1412def produce_macros_definition_for_std(std):
1413    result = ""
1414    indent = 55
1415    for tc in feature_test_macros:
1416        if std not in tc["values"]:
1417            continue
1418        inner_indent = 1
1419        if "test_suite_guard" in tc.keys():
1420            result += "# if %s\n" % tc["libcxx_guard"]
1421            inner_indent += 2
1422        if get_value_before(tc["values"], std) is not None:
1423            assert "test_suite_guard" not in tc.keys()
1424            result += "# undef  %s\n" % tc["name"]
1425        line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])
1426        line += " " * (indent - len(line))
1427        line += " %sL" % tc["values"][std]
1428        if "unimplemented" in tc.keys():
1429            line = "// " + line
1430        result += line
1431        result += "\n"
1432        if "test_suite_guard" in tc.keys():
1433            result += "# endif\n"
1434    return result.strip()
1435
1436
1437def produce_macros_definitions():
1438    macro_definition_template = """#if _LIBCPP_STD_VER >= {std_number}
1439{macro_definition}
1440#endif"""
1441
1442    macros_definitions = []
1443    for std in get_std_dialects():
1444        macros_definitions.append(
1445            macro_definition_template.format(
1446                std_number=get_std_number(std),
1447                macro_definition=produce_macros_definition_for_std(std),
1448            )
1449        )
1450
1451    return "\n\n".join(macros_definitions)
1452
1453
1454def chunks(l, n):
1455    """Yield successive n-sized chunks from l."""
1456    for i in range(0, len(l), n):
1457        yield l[i : i + n]
1458
1459
1460def produce_version_synopsis():
1461    indent = 56
1462    header_indent = 56 + len("20XXYYL ")
1463    result = ""
1464
1465    def indent_to(s, val):
1466        if len(s) >= val:
1467            return s
1468        s += " " * (val - len(s))
1469        return s
1470
1471    line = indent_to("Macro name", indent) + "Value"
1472    line = indent_to(line, header_indent) + "Headers"
1473    result += line + "\n"
1474    for tc in feature_test_macros:
1475        prev_defined_std = get_last_std(tc["values"])
1476        line = "{name: <{indent}}{value}L ".format(
1477            name=tc["name"], indent=indent, value=tc["values"][prev_defined_std]
1478        )
1479        headers = list(tc["headers"])
1480        headers.remove("version")
1481        for chunk in chunks(headers, 3):
1482            line = indent_to(line, header_indent)
1483            chunk = ["<%s>" % header for header in chunk]
1484            line += " ".join(chunk)
1485            result += line
1486            result += "\n"
1487            line = ""
1488        while True:
1489            prev_defined_std = get_std_before(tc["values"], prev_defined_std)
1490            if prev_defined_std is None:
1491                break
1492            result += "%s%sL // %s\n" % (
1493                indent_to("", indent),
1494                tc["values"][prev_defined_std],
1495                prev_defined_std.replace("c++", "C++"),
1496            )
1497    return result
1498
1499
1500def produce_version_header():
1501    template = """// -*- C++ -*-
1502//===----------------------------------------------------------------------===//
1503//
1504// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1505// See https://llvm.org/LICENSE.txt for license information.
1506// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1507//
1508//===----------------------------------------------------------------------===//
1509
1510#ifndef _LIBCPP_VERSIONH
1511#define _LIBCPP_VERSIONH
1512
1513/*
1514  version synopsis
1515
1516{synopsis}
1517
1518*/
1519
1520#include <__availability>
1521#include <__config>
1522
1523#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1524#  pragma GCC system_header
1525#endif
1526
1527// clang-format off
1528
1529{cxx_macros}
1530
1531// clang-format on
1532
1533#endif // _LIBCPP_VERSIONH
1534"""
1535
1536    version_str = template.format(
1537        synopsis=produce_version_synopsis().strip(),
1538        cxx_macros=produce_macros_definitions(),
1539    )
1540    version_header_path = os.path.join(include_path, "version")
1541    with open(version_header_path, "w", newline="\n") as f:
1542        f.write(version_str)
1543
1544
1545"""
1546    Functions to produce test files
1547"""
1548
1549test_types = {
1550    "undefined": """
1551# ifdef {name}
1552#   error "{name} should not be defined before {std_first}"
1553# endif
1554""",
1555    "test_suite_guard": """
1556# if {test_suite_guard}
1557#   ifndef {name}
1558#     error "{name} should be defined in {std}"
1559#   endif
1560#   if {name} != {value}
1561#     error "{name} should have the value {value} in {std}"
1562#   endif
1563# else
1564#   ifdef {name}
1565#     error "{name} should not be defined when the requirement '{test_suite_guard}' is not met!"
1566#   endif
1567# endif
1568""",
1569    "unimplemented": """
1570# if !defined(_LIBCPP_VERSION)
1571#   ifndef {name}
1572#     error "{name} should be defined in {std}"
1573#   endif
1574#   if {name} != {value}
1575#     error "{name} should have the value {value} in {std}"
1576#   endif
1577# else // _LIBCPP_VERSION
1578#   ifdef {name}
1579#     error "{name} should not be defined because it is unimplemented in libc++!"
1580#   endif
1581# endif
1582""",
1583    "defined": """
1584# ifndef {name}
1585#   error "{name} should be defined in {std}"
1586# endif
1587# if {name} != {value}
1588#   error "{name} should have the value {value} in {std}"
1589# endif
1590""",
1591}
1592
1593
1594def generate_std_test(test_list, std):
1595    result = ""
1596    for tc in test_list:
1597        val = get_for_std(tc["values"], std)
1598        if val is not None:
1599            val = "%sL" % val
1600        if val is None:
1601            result += test_types["undefined"].format(
1602                name=tc["name"], std_first=get_first_std(tc["values"])
1603            )
1604        elif "unimplemented" in tc.keys():
1605            result += test_types["unimplemented"].format(
1606                name=tc["name"], value=val, std=std
1607            )
1608        elif "test_suite_guard" in tc.keys():
1609            result += test_types["test_suite_guard"].format(
1610                name=tc["name"],
1611                value=val,
1612                std=std,
1613                test_suite_guard=tc["test_suite_guard"],
1614            )
1615        else:
1616            result += test_types["defined"].format(name=tc["name"], value=val, std=std)
1617    return result.strip()
1618
1619
1620def generate_std_tests(test_list):
1621    std_tests_template = """#if TEST_STD_VER < {first_std_number}
1622
1623{pre_std_test}
1624
1625{other_std_tests}
1626
1627#elif TEST_STD_VER > {penultimate_std_number}
1628
1629{last_std_test}
1630
1631#endif // TEST_STD_VER > {penultimate_std_number}"""
1632
1633    std_dialects = get_std_dialects()
1634
1635    other_std_tests = []
1636    for std in std_dialects[:-1]:
1637        other_std_tests.append("#elif TEST_STD_VER == " + get_std_number(std))
1638        other_std_tests.append(generate_std_test(test_list, std))
1639
1640    std_tests = std_tests_template.format(
1641        first_std_number=get_std_number(std_dialects[0]),
1642        pre_std_test=generate_std_test(test_list, "c++11"),
1643        other_std_tests="\n\n".join(other_std_tests),
1644        penultimate_std_number=get_std_number(std_dialects[-2]),
1645        last_std_test=generate_std_test(test_list, std_dialects[-1]),
1646    )
1647
1648    return std_tests
1649
1650
1651def generate_synopsis(test_list):
1652    max_name_len = max([len(tc["name"]) for tc in test_list])
1653    indent = max_name_len + 8
1654
1655    def mk_line(prefix, suffix):
1656        return "{prefix: <{max_len}}{suffix}\n".format(
1657            prefix=prefix, suffix=suffix, max_len=indent
1658        )
1659
1660    result = ""
1661    result += mk_line("/*  Constant", "Value")
1662    for tc in test_list:
1663        prefix = "    %s" % tc["name"]
1664        for std in [s for s in get_std_dialects() if s in tc["values"].keys()]:
1665            result += mk_line(
1666                prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++"))
1667            )
1668            prefix = ""
1669    result += "*/"
1670    return result
1671
1672
1673def produce_tests():
1674    headers = set([h for tc in feature_test_macros for h in tc["headers"]])
1675    for h in headers:
1676        test_list = [tc for tc in feature_test_macros if h in tc["headers"]]
1677        if not has_header(h):
1678            for tc in test_list:
1679                assert "unimplemented" in tc.keys()
1680            continue
1681        markup = "\n".join("// " + tag for tag in lit_markup.get(h, []))
1682        test_body = """//===----------------------------------------------------------------------===//
1683//
1684// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1685// See https://llvm.org/LICENSE.txt for license information.
1686// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1687//
1688//===----------------------------------------------------------------------===//
1689//
1690// WARNING: This test was generated by {script_name}
1691// and should not be edited manually.
1692//
1693// clang-format off
1694{markup}
1695// <{header}>
1696
1697// Test the feature test macros defined by <{header}>
1698
1699{synopsis}
1700
1701#include <{header}>
1702#include "test_macros.h"
1703
1704{cxx_tests}
1705
1706""".format(
1707            script_name=script_name,
1708            header=h,
1709            markup=("\n{}\n".format(markup) if markup else ""),
1710            synopsis=generate_synopsis(test_list),
1711            cxx_tests=generate_std_tests(test_list),
1712        )
1713        test_name = "{header}.version.compile.pass.cpp".format(header=h)
1714        out_path = os.path.join(macro_test_path, test_name)
1715        with open(out_path, "w", newline="\n") as f:
1716            f.write(test_body)
1717
1718
1719"""
1720    Produce documentation for the feature test macros
1721"""
1722
1723
1724def make_widths(grid):
1725    widths = []
1726    for i in range(0, len(grid[0])):
1727        cell_width = 2 + max(
1728            reduce(lambda x, y: x + y, [[len(row[i])] for row in grid], [])
1729        )
1730        widths += [cell_width]
1731    return widths
1732
1733
1734def create_table(grid, indent):
1735    indent_str = " " * indent
1736    col_widths = make_widths(grid)
1737    result = [indent_str + add_divider(col_widths, 2)]
1738    header_flag = 2
1739    for row_i in range(0, len(grid)):
1740        row = grid[row_i]
1741        line = indent_str + " ".join(
1742            [pad_cell(row[i], col_widths[i]) for i in range(0, len(row))]
1743        )
1744        result.append(line.rstrip())
1745        if row_i == len(grid) - 1:
1746            header_flag = 2
1747        if row[0].startswith("**"):
1748            header_flag += 1
1749        separator = indent_str + add_divider(col_widths, header_flag)
1750        result.append(separator.rstrip())
1751        header_flag = 0
1752    return "\n".join(result)
1753
1754
1755def add_divider(widths, header_flag):
1756    if header_flag == 3:
1757        return "=".join(["=" * w for w in widths])
1758    if header_flag == 2:
1759        return " ".join(["=" * w for w in widths])
1760    if header_flag == 1:
1761        return "-".join(["-" * w for w in widths])
1762    else:
1763        return " ".join(["-" * w for w in widths])
1764
1765
1766def pad_cell(s, length, left_align=True):
1767    padding = (length - len(s)) * " "
1768    return s + padding
1769
1770
1771def get_status_table():
1772    table = [["Macro Name", "Value"]]
1773    for std in get_std_dialects():
1774        table += [["**" + std.replace("c++", "C++") + "**", ""]]
1775        for tc in feature_test_macros:
1776            if std not in tc["values"].keys():
1777                continue
1778            value = "``%sL``" % tc["values"][std]
1779            if "unimplemented" in tc.keys():
1780                value = "*unimplemented*"
1781            table += [["``%s``" % tc["name"], value]]
1782    return table
1783
1784
1785def produce_docs():
1786    doc_str = """.. _FeatureTestMacroTable:
1787
1788==========================
1789Feature Test Macro Support
1790==========================
1791
1792.. contents::
1793   :local:
1794
1795Overview
1796========
1797
1798This file documents the feature test macros currently supported by libc++.
1799
1800.. _feature-status:
1801
1802Status
1803======
1804
1805.. table:: Current Status
1806    :name: feature-status-table
1807    :widths: auto
1808
1809{status_tables}
1810
1811""".format(
1812        status_tables=create_table(get_status_table(), 4)
1813    )
1814
1815    table_doc_path = os.path.join(docs_path, "FeatureTestMacroTable.rst")
1816    with open(table_doc_path, "w", newline="\n") as f:
1817        f.write(doc_str)
1818
1819
1820def main():
1821    produce_version_header()
1822    produce_tests()
1823    produce_docs()
1824
1825
1826if __name__ == "__main__":
1827    main()
1828