1#!/usr/bin/env python
2
3import os
4from builtins import range
5from functools import reduce
6
7def get_libcxx_paths():
8  utils_path = os.path.dirname(os.path.abspath(__file__))
9  script_name = os.path.basename(__file__)
10  assert os.path.exists(utils_path)
11  src_root = os.path.dirname(utils_path)
12  include_path = os.path.join(src_root, 'include')
13  assert os.path.exists(include_path)
14  docs_path = os.path.join(src_root, 'docs')
15  assert os.path.exists(docs_path)
16  macro_test_path = os.path.join(src_root, 'test', 'std', 'language.support',
17                            'support.limits', 'support.limits.general')
18  assert os.path.exists(macro_test_path)
19  assert os.path.exists(os.path.join(macro_test_path, 'version.version.compile.pass.cpp'))
20  return script_name, src_root, include_path, docs_path, macro_test_path
21
22script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths()
23
24def has_header(h):
25  h_path = os.path.join(include_path, h)
26  return os.path.exists(h_path)
27
28def add_version_header(tc):
29  tc["headers"].append("version")
30  return tc
31
32# ================  ============================================================
33# Field             Description
34# ================  ============================================================
35# name              The name of the feature-test macro.
36# values            A dict whose keys are C++ versions and whose values are the
37#                   value of the feature-test macro for that C++ version.
38#                   (TODO: This isn't a very clean model for feature-test
39#                   macros affected by multiple papers.)
40# headers           An array with the headers that should provide the
41#                   feature-test macro.
42# test_suite_guard  An optional string field. When this field is provided,
43#                   `libcxx_guard` must also be provided. This field is used
44#                   only to generate the unit tests for the feature-test macros.
45#                   It can't depend on macros defined in <__config> because the
46#                   `test/std/` parts of the test suite are intended to be
47#                   portable to any C++ standard library implementation, not
48#                   just libc++. It may depend on
49#                    * macros defined by the compiler itself, or
50#                    * macros generated by CMake.
51#                   In some cases we add
52#                   `&& !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM_...)`
53#                   in order to make libc++ pass the tests on OSX; see D94983.
54# libcxx_guard      An optional string field. When this field is provided,
55#                   `test_suite_guard` must also be provided. This field is used
56#                   only to guard the feature-test macro in <version>. It may
57#                   be the same as `test_suite_guard`, or it may depend on
58#                   macros defined in <__config>.
59# unimplemented     An optional Boolean field with the value `True`. This field
60#                   is only used when a feature isn't fully implemented. Once
61#                   you've fully implemented the feature, you should remove
62#                   this field.
63# ================  ============================================================
64feature_test_macros = [ add_version_header(x) for x in [
65  {
66    "name": "__cpp_lib_adaptor_iterator_pair_constructor",
67    "values": { "c++2b": 202106 },
68    "headers": ["queue", "stack"],
69  }, {
70    "name": "__cpp_lib_addressof_constexpr",
71    "values": { "c++17": 201603 },
72    "headers": ["memory"],
73  }, {
74    "name": "__cpp_lib_allocate_at_least",
75    "values": { "c++2b": 202106 },
76    "headers": ["memory"],
77  }, {
78    "name": "__cpp_lib_allocator_traits_is_always_equal",
79    "values": { "c++17": 201411 },
80    "headers": ["deque", "forward_list", "list", "map", "memory", "scoped_allocator", "set", "string", "unordered_map", "unordered_set", "vector"],
81  }, {
82    "name": "__cpp_lib_any",
83    "values": { "c++17": 201606 },
84    "headers": ["any"],
85  }, {
86    "name": "__cpp_lib_apply",
87    "values": { "c++17": 201603 },
88    "headers": ["tuple"],
89  }, {
90    "name": "__cpp_lib_array_constexpr",
91    "values": { "c++17": 201603, "c++20": 201811 },
92    "headers": ["array", "iterator"],
93  }, {
94    "name": "__cpp_lib_as_const",
95    "values": { "c++17": 201510 },
96    "headers": ["utility"],
97  }, {
98    "name": "__cpp_lib_associative_heterogeneous_erasure",
99    "values": { "c++2b": 202110 },
100    "headers": ["map", "set", "unordered_map", "unordered_set"],
101    "unimplemented": True,
102  }, {
103    "name": "__cpp_lib_assume_aligned",
104    "values": { "c++20": 201811 },
105    "headers": ["memory"],
106  }, {
107    "name": "__cpp_lib_atomic_flag_test",
108    "values": { "c++20": 201907 },
109    "headers": ["atomic"],
110  }, {
111    "name": "__cpp_lib_atomic_float",
112    "values": { "c++20": 201711 },
113    "headers": ["atomic"],
114    "unimplemented": True,
115  }, {
116    "name": "__cpp_lib_atomic_is_always_lock_free",
117    "values": { "c++17": 201603 },
118    "headers": ["atomic"],
119  }, {
120    "name": "__cpp_lib_atomic_lock_free_type_aliases",
121    "values": { "c++20": 201907 },
122    "headers": ["atomic"],
123  }, {
124    "name": "__cpp_lib_atomic_ref",
125    "values": { "c++20": 201806 },
126    "headers": ["atomic"],
127    "unimplemented": True,
128  }, {
129    "name": "__cpp_lib_atomic_shared_ptr",
130    "values": { "c++20": 201711 },
131    "headers": ["atomic"],
132    "unimplemented": True,
133  }, {
134    "name": "__cpp_lib_atomic_value_initialization",
135    "values": { "c++20": 201911 },
136    "headers": ["atomic", "memory"],
137  }, {
138    "name": "__cpp_lib_atomic_wait",
139    "values": { "c++20": 201907 },
140    "headers": ["atomic"],
141    "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_atomic_wait)",
142    "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_atomic_wait)",
143  }, {
144    "name": "__cpp_lib_barrier",
145    "values": { "c++20": 201907 },
146    "headers": ["barrier"],
147    "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_barrier)",
148    "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_barrier)",
149  }, {
150    "name": "__cpp_lib_bind_back",
151    "values": { "c++2b": 202202 },
152    "headers": ["functional"],
153    "unimplemented": True,
154  }, {
155    "name": "__cpp_lib_bind_front",
156    "values": { "c++20": 201907 },
157    "headers": ["functional"],
158  }, {
159    "name": "__cpp_lib_bit_cast",
160    "values": { "c++20": 201806 },
161    "headers": ["bit"],
162  }, {
163    "name": "__cpp_lib_bitops",
164    "values": { "c++20": 201907 },
165    "headers": ["bit"],
166    "unimplemented": True,
167  }, {
168    "name": "__cpp_lib_bool_constant",
169    "values": { "c++17": 201505 },
170    "headers": ["type_traits"],
171  }, {
172    "name": "__cpp_lib_bounded_array_traits",
173    "values": { "c++20": 201902 },
174    "headers": ["type_traits"],
175  }, {
176    "name": "__cpp_lib_boyer_moore_searcher",
177    "values": { "c++17": 201603 },
178    "headers": ["functional"],
179    "unimplemented": True,
180  }, {
181    "name": "__cpp_lib_byte",
182    "values": { "c++17": 201603 },
183    "headers": ["cstddef"],
184  }, {
185    "name": "__cpp_lib_byteswap",
186    "values": { "c++2b": 202110 },
187    "headers": ["bit"],
188  }, {
189    "name": "__cpp_lib_char8_t",
190    "values": { "c++20": 201811 },
191    "headers": ["atomic", "filesystem", "istream", "limits", "locale", "ostream", "string", "string_view"],
192    "test_suite_guard": "defined(__cpp_char8_t)",
193    "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CHAR8_T)",
194  }, {
195    "name": "__cpp_lib_chrono",
196    "values": { "c++17": 201611 },
197    "headers": ["chrono"],
198  }, {
199    "name": "__cpp_lib_chrono_udls",
200    "values": { "c++14": 201304 },
201    "headers": ["chrono"],
202  }, {
203    "name": "__cpp_lib_clamp",
204    "values": { "c++17": 201603 },
205    "headers": ["algorithm"],
206  }, {
207    "name": "__cpp_lib_complex_udls",
208    "values": { "c++14": 201309 },
209    "headers": ["complex"],
210  }, {
211    "name": "__cpp_lib_concepts",
212    "values": { "c++20": 202002 },
213    "headers": ["concepts"],
214  }, {
215    "name": "__cpp_lib_constexpr_algorithms",
216    "values": { "c++20": 201806 },
217    "headers": ["algorithm"],
218  }, {
219    "name": "__cpp_lib_constexpr_cmath",
220    "values": { "c++2b": 202202 },
221    "headers": ["cmath", "cstdlib"],
222    "unimplemented": True,
223  }, {
224    "name": "__cpp_lib_constexpr_complex",
225    "values": { "c++20": 201711 },
226    "headers": ["complex"],
227    "unimplemented": True,
228  }, {
229    "name": "__cpp_lib_constexpr_dynamic_alloc",
230    "values": { "c++20": 201907 },
231    "headers": ["memory"],
232  }, {
233    "name": "__cpp_lib_constexpr_functional",
234    "values": { "c++20": 201907 },
235    "headers": ["functional"],
236  }, {
237    "name": "__cpp_lib_constexpr_iterator",
238    "values": { "c++20": 201811 },
239    "headers": ["iterator"],
240  }, {
241    "name": "__cpp_lib_constexpr_memory",
242    "values": { "c++20": 201811 },
243    "headers": ["memory"],
244  }, {
245    "name": "__cpp_lib_constexpr_numeric",
246    "values": { "c++20": 201911 },
247    "headers": ["numeric"],
248  }, {
249    "name": "__cpp_lib_constexpr_string",
250    "values": { "c++20": 201907 },
251    "headers": ["string"],
252  }, {
253    "name": "__cpp_lib_constexpr_string_view",
254    "values": { "c++20": 201811 },
255    "headers": ["string_view"],
256  }, {
257    "name": "__cpp_lib_constexpr_tuple",
258    "values": { "c++20": 201811 },
259    "headers": ["tuple"],
260  }, {
261    "name": "__cpp_lib_constexpr_typeinfo",
262    "values": { "c++2b": 202106 },
263    "headers": ["typeinfo"],
264    "unimplemented": True,
265  }, {
266    "name": "__cpp_lib_constexpr_utility",
267    "values": { "c++20": 201811 },
268    "headers": ["utility"],
269  }, {
270    "name": "__cpp_lib_constexpr_vector",
271    "values": { "c++20": 201907 },
272    "headers": ["vector"],
273    "unimplemented": True,
274  }, {
275    "name": "__cpp_lib_coroutine",
276    "values": { "c++20": 201902 },
277    "headers": ["coroutine"],
278  }, {
279    "name": "__cpp_lib_destroying_delete",
280    "values": { "c++20": 201806 },
281    "headers": ["new"],
282    "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
283    "libcxx_guard": "_LIBCPP_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L",
284  }, {
285    "name": "__cpp_lib_enable_shared_from_this",
286    "values": { "c++17": 201603 },
287    "headers": ["memory"],
288  }, {
289    "name": "__cpp_lib_endian",
290    "values": { "c++20": 201907 },
291    "headers": ["bit"],
292  }, {
293    "name": "__cpp_lib_erase_if",
294    "values": { "c++20": 202002 },
295    "headers": ["deque", "forward_list", "list", "map", "set", "string", "unordered_map", "unordered_set", "vector"],
296  }, {
297    "name": "__cpp_lib_exchange_function",
298    "values": { "c++14": 201304 },
299    "headers": ["utility"],
300  }, {
301    "name": "__cpp_lib_execution",
302    "values": { "c++17": 201603, "c++20": 201902 },
303    "headers": ["execution"],
304    "unimplemented": True,
305  }, {
306    "name": "__cpp_lib_filesystem",
307    "values": { "c++17": 201703 },
308    "headers": ["filesystem"],
309    "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem)",
310    "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem)"
311  }, {
312    "name": "__cpp_lib_format",
313    "values": { "c++20": 202106 },
314    "headers": ["format"],
315    "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format)",
316    "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format)",
317    "unimplemented": True,
318  }, {
319    "name": "__cpp_lib_gcd_lcm",
320    "values": { "c++17": 201606 },
321    "headers": ["numeric"],
322  }, {
323    "name": "__cpp_lib_generic_associative_lookup",
324    "values": { "c++14": 201304 },
325    "headers": ["map", "set"],
326  }, {
327    "name": "__cpp_lib_generic_unordered_lookup",
328    "values": { "c++20": 201811 },
329    "headers": ["unordered_map", "unordered_set"],
330  }, {
331    "name": "__cpp_lib_hardware_interference_size",
332    "values": { "c++17": 201703 },
333    "headers": ["new"],
334    "unimplemented": True,
335  }, {
336    "name": "__cpp_lib_has_unique_object_representations",
337    "values": { "c++17": 201606 },
338    "headers": ["type_traits"],
339  }, {
340    "name": "__cpp_lib_hypot",
341    "values": { "c++17": 201603 },
342    "headers": ["cmath"],
343  }, {
344    "name": "__cpp_lib_incomplete_container_elements",
345    "values": { "c++17": 201505 },
346    "headers": ["forward_list", "list", "vector"],
347  }, {
348    "name": "__cpp_lib_int_pow2",
349    "values": { "c++20": 202002 },
350    "headers": ["bit"],
351  }, {
352    "name": "__cpp_lib_integer_comparison_functions",
353    "values": { "c++20": 202002 },
354    "headers": ["utility"],
355  }, {
356    "name": "__cpp_lib_integer_sequence",
357    "values": { "c++14": 201304 },
358    "headers": ["utility"],
359  }, {
360    "name": "__cpp_lib_integral_constant_callable",
361    "values": { "c++14": 201304 },
362    "headers": ["type_traits"],
363  }, {
364    "name": "__cpp_lib_interpolate",
365    "values": { "c++20": 201902 },
366    "headers": ["cmath", "numeric"],
367  }, {
368    "name": "__cpp_lib_invoke",
369    "values": { "c++17": 201411 },
370    "headers": ["functional"],
371  }, {
372    "name": "__cpp_lib_invoke_r",
373    "values": { "c++2b": 202106 },
374    "headers": ["functional"],
375    "unimplemented": True,
376  }, {
377    "name": "__cpp_lib_is_aggregate",
378    "values": { "c++17": 201703 },
379    "headers": ["type_traits"],
380  }, {
381    "name": "__cpp_lib_is_constant_evaluated",
382    "values": { "c++20": 201811 },
383    "headers": ["type_traits"],
384  }, {
385    "name": "__cpp_lib_is_final",
386    "values": { "c++14": 201402 },
387    "headers": ["type_traits"],
388  }, {
389    "name": "__cpp_lib_is_invocable",
390    "values": { "c++17": 201703 },
391    "headers": ["type_traits"],
392  }, {
393    "name": "__cpp_lib_is_layout_compatible",
394    "values": { "c++20": 201907 },
395    "headers": ["type_traits"],
396    "unimplemented": True,
397  }, {
398    "name": "__cpp_lib_is_nothrow_convertible",
399    "values": { "c++20": 201806 },
400    "headers": ["type_traits"],
401  }, {
402    "name": "__cpp_lib_is_null_pointer",
403    "values": { "c++14": 201309 },
404    "headers": ["type_traits"],
405  }, {
406    "name": "__cpp_lib_is_pointer_interconvertible",
407    "values": { "c++20": 201907 },
408    "headers": ["type_traits"],
409    "unimplemented": True,
410  }, {
411    "name": "__cpp_lib_is_scoped_enum",
412    "values": { "c++2b": 202011 },
413    "headers": ["type_traits"],
414  }, {
415    "name": "__cpp_lib_is_swappable",
416    "values": { "c++17": 201603 },
417    "headers": ["type_traits"],
418  }, {
419    "name": "__cpp_lib_jthread",
420    "values": { "c++20": 201911 },
421    "headers": ["stop_token", "thread"],
422    "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
423    "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)",
424    "unimplemented": True,
425  }, {
426    "name": "__cpp_lib_latch",
427    "values": { "c++20": 201907 },
428    "headers": ["latch"],
429    "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_latch)",
430    "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_latch)",
431  }, {
432    "name": "__cpp_lib_launder",
433    "values": { "c++17": 201606 },
434    "headers": ["new"],
435  }, {
436    "name": "__cpp_lib_list_remove_return_type",
437    "values": { "c++20": 201806 },
438    "headers": ["forward_list", "list"],
439  }, {
440    "name": "__cpp_lib_logical_traits",
441    "values": { "c++17": 201510 },
442    "headers": ["type_traits"],
443  }, {
444    "name": "__cpp_lib_make_from_tuple",
445    "values": { "c++17": 201606 },
446    "headers": ["tuple"],
447  }, {
448    "name": "__cpp_lib_make_reverse_iterator",
449    "values": { "c++14": 201402 },
450    "headers": ["iterator"],
451  }, {
452    "name": "__cpp_lib_make_unique",
453    "values": { "c++14": 201304 },
454    "headers": ["memory"],
455  }, {
456    "name": "__cpp_lib_map_try_emplace",
457    "values": { "c++17": 201411 },
458    "headers": ["map"],
459  }, {
460    "name": "__cpp_lib_math_constants",
461    "values": { "c++20": 201907 },
462    "headers": ["numbers"],
463  }, {
464    "name": "__cpp_lib_math_special_functions",
465    "values": { "c++17": 201603 },
466    "headers": ["cmath"],
467    "unimplemented": True,
468  }, {
469    "name": "__cpp_lib_memory_resource",
470    "values": { "c++17": 201603 },
471    "headers": ["memory_resource"],
472    "unimplemented": True,
473  }, {
474    "name": "__cpp_lib_monadic_optional",
475    "values": { "c++2b": 202110 },
476    "headers": ["optional"],
477  }, {
478    "name": "__cpp_lib_move_only_function",
479    "values": { "c++2b": 202110 },
480    "headers": ["functional"],
481    "unimplemented": True,
482  }, {
483    "name": "__cpp_lib_node_extract",
484    "values": { "c++17": 201606 },
485    "headers": ["map", "set", "unordered_map", "unordered_set"],
486  }, {
487    "name": "__cpp_lib_nonmember_container_access",
488    "values": { "c++17": 201411 },
489    "headers": ["array", "deque", "forward_list", "iterator", "list", "map", "regex", "set", "string", "unordered_map", "unordered_set", "vector"],
490  }, {
491    "name": "__cpp_lib_not_fn",
492    "values": { "c++17": 201603 },
493    "headers": ["functional"],
494  }, {
495    "name": "__cpp_lib_null_iterators",
496    "values": { "c++14": 201304 },
497    "headers": ["iterator"],
498  }, {
499    "name": "__cpp_lib_optional",
500    "values": { "c++17": 201606 },
501    "headers": ["optional"],
502  }, {
503    "name": "__cpp_lib_out_ptr",
504    "values": { "c++2b": 202106 },
505    "headers": ["memory"],
506    "unimplemented": True,
507  }, {
508    "name": "__cpp_lib_parallel_algorithm",
509    "values": { "c++17": 201603 },
510    "headers": ["algorithm", "numeric"],
511    "unimplemented": True,
512  }, {
513    "name": "__cpp_lib_polymorphic_allocator",
514    "values": { "c++20": 201902 },
515    "headers": ["memory_resource"],
516    "unimplemented": True,
517  }, {
518    "name": "__cpp_lib_quoted_string_io",
519    "values": { "c++14": 201304 },
520    "headers": ["iomanip"],
521  }, {
522    "name": "__cpp_lib_ranges",
523    "values": { "c++20": 201811 },
524    "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
525    "unimplemented": True,
526  }, {
527    "name": "__cpp_lib_ranges_chunk",
528    "values": { "c++2b": 202202 },
529    "headers": ["ranges"],
530    "unimplemented": True,
531  }, {
532    "name": "__cpp_lib_ranges_chunk_by",
533    "values": { "c++2b": 202202 },
534    "headers": ["ranges"],
535    "unimplemented": True,
536  }, {
537    "name": "__cpp_lib_ranges_iota",
538    "values": { "c++2b": 202202 },
539    "headers": ["numeric"],
540    "unimplemented": True,
541  }, {
542    "name": "__cpp_lib_ranges_join_with",
543    "values": { "c++2b": 202202 },
544    "headers": ["ranges"],
545    "unimplemented": True,
546  }, {
547    "name": "__cpp_lib_ranges_slide",
548    "values": { "c++2b": 202202 },
549    "headers": ["ranges"],
550    "unimplemented": True,
551  }, {
552    "name": "__cpp_lib_ranges_starts_ends_with",
553    "values": { "c++2b": 202106 },
554    "headers": ["algorithm"],
555    "unimplemented": True,
556  }, {
557    "name": "__cpp_lib_ranges_to_container",
558    "values": { "c++2b": 202202 },
559    "headers": ["deque", "forward_list", "list", "map", "priority_queue", "queue", "set", "stack", "string", "unordered_map", "unordered_set", "vector"],
560    "unimplemented": True,
561  }, {
562    "name": "__cpp_lib_ranges_zip",
563    "values": { "c++2b": 202110 },
564    "headers": ["ranges", "tuple", "utility"],
565    "unimplemented": True,
566  }, {
567    "name": "__cpp_lib_raw_memory_algorithms",
568    "values": { "c++17": 201606 },
569    "headers": ["memory"],
570  }, {
571    "name": "__cpp_lib_reference_from_temporary",
572    "values": { "c++2b": 202202 },
573    "headers": ["type_traits"],
574    "unimplemented": True,
575  }, {
576    "name": "__cpp_lib_remove_cvref",
577    "values": { "c++20": 201711 },
578    "headers": ["type_traits"],
579  }, {
580    "name": "__cpp_lib_result_of_sfinae",
581    "values": { "c++14": 201210 },
582    "headers": ["functional", "type_traits"],
583  }, {
584    "name": "__cpp_lib_robust_nonmodifying_seq_ops",
585    "values": { "c++14": 201304 },
586    "headers": ["algorithm"],
587  }, {
588    "name": "__cpp_lib_sample",
589    "values": { "c++17": 201603 },
590    "headers": ["algorithm"],
591  }, {
592    "name": "__cpp_lib_scoped_lock",
593    "values": { "c++17": 201703 },
594    "headers": ["mutex"],
595  }, {
596    "name": "__cpp_lib_semaphore",
597    "values": { "c++20": 201907 },
598    "headers": ["semaphore"],
599    "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore)",
600    "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore)",
601  }, {
602    "name": "__cpp_lib_shared_mutex",
603    "values": { "c++17": 201505 },
604    "headers": ["shared_mutex"],
605    "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_mutex)",
606    "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_mutex)",
607  }, {
608    "name": "__cpp_lib_shared_ptr_arrays",
609    "values": { "c++17": 201611, "c++20": 201707 },
610    "headers": ["memory"],
611  }, {
612    "name": "__cpp_lib_shared_ptr_weak_type",
613    "values": { "c++17": 201606 },
614    "headers": ["memory"],
615  }, {
616    "name": "__cpp_lib_shared_timed_mutex",
617    "values": { "c++14": 201402 },
618    "headers": ["shared_mutex"],
619    "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_timed_mutex)",
620    "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_timed_mutex)",
621  }, {
622    "name": "__cpp_lib_shift",
623    "values": { "c++20": 201806 },
624    "headers": ["algorithm"],
625  }, {
626    "name": "__cpp_lib_smart_ptr_for_overwrite",
627    "values": { "c++20": 202002 },
628    "headers": ["memory"],
629    "unimplemented": True,
630  }, {
631    "name": "__cpp_lib_source_location",
632    "values": { "c++20": 201907 },
633    "headers": ["source_location"],
634    "unimplemented": True,
635  }, {
636    "name": "__cpp_lib_span",
637    "values": { "c++20": 202002 },
638    "headers": ["span"],
639  }, {
640    "name": "__cpp_lib_spanstream",
641    "values": { "c++2b": 202106 },
642    "headers": ["spanstream"],
643    "unimplemented": True,
644  }, {
645    "name": "__cpp_lib_ssize",
646    "values": { "c++20": 201902 },
647    "headers": ["iterator"],
648  }, {
649    "name": "__cpp_lib_stacktrace",
650    "values": { "c++2b": 202011 },
651    "headers": ["stacktrace"],
652    "unimplemented": True,
653  }, {
654    "name": "__cpp_lib_starts_ends_with",
655    "values": { "c++20": 201711 },
656    "headers": ["string", "string_view"],
657  }, {
658    "name": "__cpp_lib_stdatomic_h",
659    "values": { "c++2b": 202011 },
660    "headers": ["stdatomic.h"],
661    "unimplemented": True,
662  }, {
663    "name": "__cpp_lib_string_contains",
664    "values": { "c++2b": 202011 },
665    "headers": ["string", "string_view"],
666  }, {
667    "name": "__cpp_lib_string_resize_and_overwrite",
668    "values": { "c++2b": 202110 },
669    "headers": ["string"],
670  }, {
671    "name": "__cpp_lib_string_udls",
672    "values": { "c++14": 201304 },
673    "headers": ["string"],
674  }, {
675    "name": "__cpp_lib_string_view",
676    "values": { "c++17": 201606, "c++20": 201803 },
677    "headers": ["string", "string_view"],
678  }, {
679    "name": "__cpp_lib_syncbuf",
680    "values": { "c++20": 201803 },
681    "headers": ["syncstream"],
682    "unimplemented": True,
683  }, {
684    "name": "__cpp_lib_three_way_comparison",
685    "values": { "c++20": 201907 },
686    "headers": ["compare"],
687    "unimplemented": True,
688  }, {
689    "name": "__cpp_lib_to_address",
690    "values": { "c++20": 201711 },
691    "headers": ["memory"],
692  }, {
693    "name": "__cpp_lib_to_array",
694    "values": { "c++20": 201907 },
695    "headers": ["array"],
696  }, {
697    "name": "__cpp_lib_to_chars",
698    "values": { "c++17": 201611 },
699    "headers": ["charconv"],
700    "unimplemented": True,
701  }, {
702    "name": "__cpp_lib_to_underlying",
703    "values": { "c++2b": 202102 },
704    "headers": ["utility"],
705  }, {
706    "name": "__cpp_lib_transformation_trait_aliases",
707    "values": { "c++14": 201304 },
708    "headers": ["type_traits"],
709  }, {
710    "name": "__cpp_lib_transparent_operators",
711    "values": { "c++14": 201210, "c++17": 201510 },
712    "headers": ["functional", "memory"],
713  }, {
714    "name": "__cpp_lib_tuple_element_t",
715    "values": { "c++14": 201402 },
716    "headers": ["tuple"],
717  }, {
718    "name": "__cpp_lib_tuples_by_type",
719    "values": { "c++14": 201304 },
720    "headers": ["tuple", "utility"],
721  }, {
722    "name": "__cpp_lib_type_identity",
723    "values": { "c++20": 201806 },
724    "headers": ["type_traits"],
725  }, {
726    "name": "__cpp_lib_type_trait_variable_templates",
727    "values": { "c++17": 201510 },
728    "headers": ["type_traits"],
729  }, {
730    "name": "__cpp_lib_uncaught_exceptions",
731    "values": { "c++17": 201411 },
732    "headers": ["exception"],
733  }, {
734    "name": "__cpp_lib_unordered_map_try_emplace",
735    "values": { "c++17": 201411 },
736    "headers": ["unordered_map"],
737  }, {
738    "name": "__cpp_lib_unreachable",
739    "values": { "c++2b": 202202 },
740    "headers": ["utility"],
741  }, {
742    "name": "__cpp_lib_unwrap_ref",
743    "values": { "c++20": 201811 },
744    "headers": ["functional"],
745  }, {
746    "name": "__cpp_lib_variant",
747    "values": { "c++17": 202102 },
748    "headers": ["variant"],
749  }, {
750    "name": "__cpp_lib_void_t",
751    "values": { "c++17": 201411 },
752    "headers": ["type_traits"],
753  }
754]]
755
756assert feature_test_macros == sorted(feature_test_macros, key=lambda tc: tc["name"])
757assert all(tc["headers"] == sorted(tc["headers"]) for tc in feature_test_macros)
758assert all(("libcxx_guard" in tc) == ("test_suite_guard" in tc) for tc in feature_test_macros)
759assert all(all(key in ["name", "values", "headers", "libcxx_guard", "test_suite_guard", "unimplemented"] for key in tc.keys()) for tc in feature_test_macros)
760
761# Map from each header to the Lit annotations that should be used for
762# tests that include that header.
763#
764# For example, when threads are not supported, any test that includes
765# <thread> should be marked as UNSUPPORTED, because including <thread>
766# is a hard error in that case.
767lit_markup = {
768  "barrier": ["UNSUPPORTED: libcpp-has-no-threads"],
769  "filesystem": ["UNSUPPORTED: libcpp-has-no-filesystem-library"],
770  "format": ["UNSUPPORTED: libcpp-has-no-incomplete-format"],
771  "iomanip": ["UNSUPPORTED: libcpp-has-no-localization"],
772  "ios": ["UNSUPPORTED: libcpp-has-no-localization"],
773  "iostream": ["UNSUPPORTED: libcpp-has-no-localization"],
774  "istream": ["UNSUPPORTED: libcpp-has-no-localization"],
775  "latch": ["UNSUPPORTED: libcpp-has-no-threads"],
776  "locale": ["UNSUPPORTED: libcpp-has-no-localization"],
777  "mutex": ["UNSUPPORTED: libcpp-has-no-threads"],
778  "ostream": ["UNSUPPORTED: libcpp-has-no-localization"],
779  "ranges": ["UNSUPPORTED: libcpp-has-no-incomplete-ranges"],
780  "regex": ["UNSUPPORTED: libcpp-has-no-localization"],
781  "semaphore": ["UNSUPPORTED: libcpp-has-no-threads"],
782  "shared_mutex": ["UNSUPPORTED: libcpp-has-no-threads"],
783  "thread": ["UNSUPPORTED: libcpp-has-no-threads"]
784}
785
786def get_std_dialects():
787  std_dialects = ['c++14', 'c++17', 'c++20', 'c++2b']
788  return list(std_dialects)
789
790def get_first_std(d):
791    for s in get_std_dialects():
792        if s in d.keys():
793            return s
794    return None
795
796def get_last_std(d):
797  rev_dialects = get_std_dialects()
798  rev_dialects.reverse()
799  for s in rev_dialects:
800    if s in d.keys():
801      return s
802  return None
803
804def get_std_before(d, std):
805  std_dialects = get_std_dialects()
806  candidates = std_dialects[0:std_dialects.index(std)]
807  candidates.reverse()
808  for cand in candidates:
809    if cand in d.keys():
810      return cand
811  return None
812
813def get_value_before(d, std):
814  new_std = get_std_before(d, std)
815  if new_std is None:
816    return None
817  return d[new_std]
818
819def get_for_std(d, std):
820  # This catches the C++11 case for which there should be no defined feature
821  # test macros.
822  std_dialects = get_std_dialects()
823  if std not in std_dialects:
824    return None
825  # Find the value for the newest C++ dialect between C++14 and std
826  std_list = list(std_dialects[0:std_dialects.index(std)+1])
827  std_list.reverse()
828  for s in std_list:
829    if s in d.keys():
830      return d[s]
831  return None
832
833def get_std_number(std):
834    return std.replace('c++', '')
835
836"""
837  Functions to produce the <version> header
838"""
839
840def produce_macros_definition_for_std(std):
841  result = ""
842  indent = 55
843  for tc in feature_test_macros:
844    if std not in tc["values"]:
845      continue
846    inner_indent = 1
847    if 'test_suite_guard' in tc.keys():
848      result += "# if %s\n" % tc["libcxx_guard"]
849      inner_indent += 2
850    if get_value_before(tc["values"], std) is not None:
851      assert 'test_suite_guard' not in tc.keys()
852      result += "# undef  %s\n" % tc["name"]
853    line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])
854    line += " " * (indent - len(line))
855    line += " %sL" % tc["values"][std]
856    if 'unimplemented' in tc.keys():
857      line = "// " + line
858    result += line
859    result += "\n"
860    if 'test_suite_guard' in tc.keys():
861      result += "# endif\n"
862  return result.strip()
863
864def produce_macros_definitions():
865  macro_definition_template = """#if _LIBCPP_STD_VER > {previous_std_number}
866{macro_definition}
867#endif"""
868
869  macros_definitions = []
870  previous_std_number = '11'
871  for std in get_std_dialects():
872    macros_definitions.append(
873      macro_definition_template.format(previous_std_number=previous_std_number,
874                                       macro_definition=produce_macros_definition_for_std(std)))
875    previous_std_number = get_std_number(std)
876
877  return '\n\n'.join(macros_definitions)
878
879def chunks(l, n):
880  """Yield successive n-sized chunks from l."""
881  for i in range(0, len(l), n):
882    yield l[i:i + n]
883
884def produce_version_synopsis():
885  indent = 56
886  header_indent = 56 + len("20XXYYL ")
887  result = ""
888  def indent_to(s, val):
889    if len(s) >= val:
890      return s
891    s += " " * (val - len(s))
892    return s
893  line = indent_to("Macro name", indent) + "Value"
894  line = indent_to(line, header_indent) + "Headers"
895  result += line + "\n"
896  for tc in feature_test_macros:
897    prev_defined_std = get_last_std(tc["values"])
898    line = "{name: <{indent}}{value}L ".format(name=tc['name'], indent=indent,
899                                               value=tc["values"][prev_defined_std])
900    headers = list(tc["headers"])
901    headers.remove("version")
902    for chunk in chunks(headers, 3):
903      line = indent_to(line, header_indent)
904      chunk = ['<%s>' % header for header in chunk]
905      line += ' '.join(chunk)
906      result += line
907      result += "\n"
908      line = ""
909    while True:
910      prev_defined_std = get_std_before(tc["values"], prev_defined_std)
911      if prev_defined_std is None:
912        break
913      result += "%s%sL // %s\n" % (indent_to("", indent), tc["values"][prev_defined_std],
914                                prev_defined_std.replace("c++", "C++"))
915  return result
916
917
918def produce_version_header():
919  template="""// -*- C++ -*-
920//===----------------------------------------------------------------------===//
921//
922// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
923// See https://llvm.org/LICENSE.txt for license information.
924// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
925//
926//===----------------------------------------------------------------------===//
927
928#ifndef _LIBCPP_VERSIONH
929#define _LIBCPP_VERSIONH
930
931/*
932  version synopsis
933
934{synopsis}
935
936*/
937
938#include <__assert> // all public C++ headers provide the assertion handler
939#include <__config>
940
941#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
942#  pragma GCC system_header
943#endif
944
945// clang-format off
946
947{cxx_macros}
948
949// clang-format on
950
951#endif // _LIBCPP_VERSIONH
952"""
953
954  version_str = template.format(
955      synopsis=produce_version_synopsis().strip(),
956      cxx_macros=produce_macros_definitions())
957  version_header_path = os.path.join(include_path, 'version')
958  with open(version_header_path, 'w', newline='\n') as f:
959    f.write(version_str)
960
961
962"""
963    Functions to produce test files
964"""
965
966test_types = {
967  "undefined": """
968# ifdef {name}
969#   error "{name} should not be defined before {std_first}"
970# endif
971""",
972
973  "test_suite_guard": """
974# if {test_suite_guard}
975#   ifndef {name}
976#     error "{name} should be defined in {std}"
977#   endif
978#   if {name} != {value}
979#     error "{name} should have the value {value} in {std}"
980#   endif
981# else
982#   ifdef {name}
983#     error "{name} should not be defined when {test_suite_guard} is not defined!"
984#   endif
985# endif
986""",
987
988  "unimplemented": """
989# if !defined(_LIBCPP_VERSION)
990#   ifndef {name}
991#     error "{name} should be defined in {std}"
992#   endif
993#   if {name} != {value}
994#     error "{name} should have the value {value} in {std}"
995#   endif
996# else // _LIBCPP_VERSION
997#   ifdef {name}
998#     error "{name} should not be defined because it is unimplemented in libc++!"
999#   endif
1000# endif
1001""",
1002
1003  "defined": """
1004# ifndef {name}
1005#   error "{name} should be defined in {std}"
1006# endif
1007# if {name} != {value}
1008#   error "{name} should have the value {value} in {std}"
1009# endif
1010"""
1011}
1012
1013def generate_std_test(test_list, std):
1014  result = ""
1015  for tc in test_list:
1016    val = get_for_std(tc["values"], std)
1017    if val is not None:
1018      val = "%sL" % val
1019    if val is None:
1020      result += test_types["undefined"].format(name=tc["name"], std_first=get_first_std(tc["values"]))
1021    elif 'unimplemented' in tc.keys():
1022      result += test_types["unimplemented"].format(name=tc["name"], value=val, std=std)
1023    elif "test_suite_guard" in tc.keys():
1024      result += test_types["test_suite_guard"].format(name=tc["name"], value=val, std=std, test_suite_guard=tc["test_suite_guard"])
1025    else:
1026      result +=  test_types["defined"].format(name=tc["name"], value=val, std=std)
1027  return result.strip()
1028
1029def generate_std_tests(test_list):
1030  std_tests_template = """#if TEST_STD_VER < {first_std_number}
1031
1032{pre_std_test}
1033
1034{other_std_tests}
1035
1036#elif TEST_STD_VER > {penultimate_std_number}
1037
1038{last_std_test}
1039
1040#endif // TEST_STD_VER > {penultimate_std_number}"""
1041
1042  std_dialects = get_std_dialects()
1043  assert not get_std_number(std_dialects[-1]).isnumeric()
1044
1045  other_std_tests = []
1046  for std in std_dialects[:-1]:
1047    other_std_tests.append('#elif TEST_STD_VER == ' + get_std_number(std))
1048    other_std_tests.append(generate_std_test(test_list, std))
1049
1050  std_tests = std_tests_template.format(first_std_number=get_std_number(std_dialects[0]),
1051                                        pre_std_test=generate_std_test(test_list, 'c++11'),
1052                                        other_std_tests='\n\n'.join(other_std_tests),
1053                                        penultimate_std_number=get_std_number(std_dialects[-2]),
1054                                        last_std_test=generate_std_test(test_list, std_dialects[-1]))
1055
1056  return std_tests
1057
1058def generate_synopsis(test_list):
1059    max_name_len = max([len(tc["name"]) for tc in test_list])
1060    indent = max_name_len + 8
1061    def mk_line(prefix, suffix):
1062        return "{prefix: <{max_len}}{suffix}\n".format(prefix=prefix, suffix=suffix,
1063        max_len=indent)
1064    result = ""
1065    result += mk_line("/*  Constant", "Value")
1066    for tc in test_list:
1067        prefix = "    %s" % tc["name"]
1068        for std in [s for s in get_std_dialects() if s in tc["values"].keys()]:
1069            result += mk_line(prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++")))
1070            prefix = ""
1071    result += "*/"
1072    return result
1073
1074def produce_tests():
1075  headers = set([h for tc in feature_test_macros for h in tc["headers"]])
1076  for h in headers:
1077    test_list = [tc for tc in feature_test_macros if h in tc["headers"]]
1078    if not has_header(h):
1079      for tc in test_list:
1080        assert 'unimplemented' in tc.keys()
1081      continue
1082    markup = '\n'.join('// ' + tag for tag in lit_markup.get(h, []))
1083    test_body = \
1084"""//===----------------------------------------------------------------------===//
1085//
1086// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1087// See https://llvm.org/LICENSE.txt for license information.
1088// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
1089//
1090//===----------------------------------------------------------------------===//
1091//
1092// WARNING: This test was generated by {script_name}
1093// and should not be edited manually.
1094//
1095// clang-format off
1096{markup}
1097// <{header}>
1098
1099// Test the feature test macros defined by <{header}>
1100
1101{synopsis}
1102
1103#include <{header}>
1104#include "test_macros.h"
1105
1106{cxx_tests}
1107
1108""".format(script_name=script_name,
1109           header=h,
1110           markup=('\n{}\n'.format(markup) if markup else ''),
1111           synopsis=generate_synopsis(test_list),
1112           cxx_tests=generate_std_tests(test_list))
1113    test_name = "{header}.version.compile.pass.cpp".format(header=h)
1114    out_path = os.path.join(macro_test_path, test_name)
1115    with open(out_path, 'w', newline='\n') as f:
1116      f.write(test_body)
1117
1118"""
1119    Produce documentation for the feature test macros
1120"""
1121
1122def make_widths(grid):
1123  widths = []
1124  for i in range(0, len(grid[0])):
1125    cell_width = 2 + max(reduce(lambda x,y: x+y, [[len(row[i])] for row in grid], []))
1126    widths += [cell_width]
1127  return widths
1128
1129def create_table(grid, indent):
1130  indent_str = ' '*indent
1131  col_widths = make_widths(grid)
1132  result = [indent_str + add_divider(col_widths, 2)]
1133  header_flag = 2
1134  for row_i in range(0, len(grid)):
1135    row = grid[row_i]
1136    line = indent_str + ' '.join([pad_cell(row[i], col_widths[i]) for i in range(0, len(row))])
1137    result.append(line.rstrip())
1138    is_cxx_header = row[0].startswith('**')
1139    if row_i == len(grid) - 1:
1140      header_flag = 2
1141    separator = indent_str + add_divider(col_widths, 1 if is_cxx_header else header_flag)
1142    result.append(separator.rstrip())
1143    header_flag = 0
1144  return '\n'.join(result)
1145
1146def add_divider(widths, header_flag):
1147  if header_flag == 2:
1148    return ' '.join(['='*w for w in widths])
1149  if header_flag == 1:
1150    return '-'.join(['-'*w for w in widths])
1151  else:
1152    return ' '.join(['-'*w for w in widths])
1153
1154def pad_cell(s, length, left_align=True):
1155  padding = ((length - len(s)) * ' ')
1156  return s + padding
1157
1158
1159def get_status_table():
1160  table = [["Macro Name", "Value"]]
1161  for std in get_std_dialects():
1162    table += [["**" + std.replace("c++", "C++ ") + "**", ""]]
1163    for tc in feature_test_macros:
1164      if std not in tc["values"].keys():
1165        continue
1166      value = "``%sL``" % tc["values"][std]
1167      if 'unimplemented' in tc.keys():
1168        value = '*unimplemented*'
1169      table += [["``%s``" % tc["name"], value]]
1170  return table
1171
1172def produce_docs():
1173  doc_str = """.. _FeatureTestMacroTable:
1174
1175==========================
1176Feature Test Macro Support
1177==========================
1178
1179.. contents::
1180   :local:
1181
1182Overview
1183========
1184
1185This file documents the feature test macros currently supported by libc++.
1186
1187.. _feature-status:
1188
1189Status
1190======
1191
1192.. table:: Current Status
1193    :name: feature-status-table
1194    :widths: auto
1195
1196{status_tables}
1197
1198""".format(status_tables=create_table(get_status_table(), 4))
1199
1200  table_doc_path = os.path.join(docs_path, 'FeatureTestMacroTable.rst')
1201  with open(table_doc_path, 'w', newline='\n') as f:
1202    f.write(doc_str)
1203
1204def main():
1205  produce_version_header()
1206  produce_tests()
1207  produce_docs()
1208
1209
1210if __name__ == '__main__':
1211  main()
1212