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