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