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