blob: 0384d32558087e3f7120b53126ecd22f81b39008 [file] [log] [blame]
Eric Fiselier32784a72019-01-16 01:37:43 +00001#!/usr/bin/env python
2
3import os
4import tempfile
5
6def get_libcxx_paths():
Eric Fiselier508da412019-02-02 23:13:49 +00007 utils_path = os.path.dirname(os.path.abspath(__file__))
Eric Fiselier973eab82019-01-16 05:43:02 +00008 script_name = os.path.basename(__file__)
Eric Fiselier508da412019-02-02 23:13:49 +00009 assert os.path.exists(utils_path)
10 src_root = os.path.dirname(utils_path)
Eric Fiselier32784a72019-01-16 01:37:43 +000011 include_path = os.path.join(src_root, 'include')
12 assert os.path.exists(include_path)
13 docs_path = os.path.join(src_root, 'docs')
14 assert os.path.exists(docs_path)
Eric Fiselier508da412019-02-02 23:13:49 +000015 macro_test_path = os.path.join(src_root, 'test', 'std', 'language.support',
16 'support.limits', 'support.limits.general')
17 assert os.path.exists(macro_test_path)
18 assert os.path.exists(os.path.join(macro_test_path, 'version.version.pass.cpp'))
19 return script_name, src_root, include_path, docs_path, macro_test_path
Eric Fiselier32784a72019-01-16 01:37:43 +000020
21
Eric Fiselier508da412019-02-02 23:13:49 +000022script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths()
Eric Fiselier32784a72019-01-16 01:37:43 +000023
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 = sorted([ add_version_header(x) for x in [
33 # C++14 macros
34 {"name": "__cpp_lib_integer_sequence",
35 "values": {
36 "c++14": 201304L
37 },
38 "headers": ["utility"],
39 },
40 {"name": "__cpp_lib_exchange_function",
41 "values": {
42 "c++14": 201304L
43 },
44 "headers": ["utility"],
45 },
46 {"name": "__cpp_lib_tuples_by_type",
47 "values": {
48 "c++14": 201304L
49 },
50 "headers": ["utility", "tuple"],
51 },
52 {"name": "__cpp_lib_tuple_element_t",
53 "values": {
54 "c++14": 201402L
55 },
56 "headers": ["tuple"],
57 },
58 {"name": "__cpp_lib_make_unique",
59 "values": {
60 "c++14": 201304L
61 },
62 "headers": ["memory"],
63 },
64 {"name": "__cpp_lib_transparent_operators",
65 "values": {
66 "c++14": 201210L,
67 "c++17": 201510L,
68 },
69 "headers": ["functional"],
70 },
71 {"name": "__cpp_lib_integral_constant_callable",
72 "values": {
73 "c++14": 201304L
74 },
75 "headers": ["type_traits"],
76 },
77 {"name": "__cpp_lib_transformation_trait_aliases",
78 "values": {
79 "c++14": 201304L,
80 },
81 "headers": ["type_traits"]
82 },
83 {"name": "__cpp_lib_result_of_sfinae",
84 "values": {
85 "c++14": 201210L,
86 },
87 "headers": ["functional", "type_traits"]
88 },
89 {"name": "__cpp_lib_is_final",
90 "values": {
91 "c++14": 201402L,
92 },
93 "headers": ["type_traits"]
94 },
95 {"name": "__cpp_lib_is_null_pointer",
96 "values": {
97 "c++14": 201309L,
98 },
99 "headers": ["type_traits"]
100 },
101 {"name": "__cpp_lib_chrono_udls",
102 "values": {
103 "c++14": 201304L,
104 },
105 "headers": ["chrono"]
106 },
107 {"name": "__cpp_lib_string_udls",
108 "values": {
109 "c++14": 201304L,
110 },
111 "headers": ["string"]
112 },
113 {"name": "__cpp_lib_generic_associative_lookup",
114 "values": {
115 "c++14": 201304L,
116 },
117 "headers": ["map", "set"]
118 },
119 {"name": "__cpp_lib_null_iterators",
120 "values": {
121 "c++14": 201304L,
122 },
123 "headers": ["iterator"]
124 },
125 {"name": "__cpp_lib_make_reverse_iterator",
126 "values": {
127 "c++14": 201402L,
128 },
129 "headers": ["iterator"]
130 },
131 {"name": "__cpp_lib_robust_nonmodifying_seq_ops",
132 "values": {
133 "c++14": 201304L,
134 },
135 "headers": ["algorithm"]
136 },
137 {"name": "__cpp_lib_complex_udls",
138 "values": {
139 "c++14": 201309L,
140 },
141 "headers": ["complex"]
142 },
143 {"name": "__cpp_lib_quoted_string_io",
144 "values": {
145 "c++14": 201304L,
146 },
147 "headers": ["iomanip"]
148 },
149 {"name": "__cpp_lib_shared_timed_mutex",
150 "values": {
151 "c++14": 201402L,
152 },
Eric Fiselier05019eb2019-01-16 02:10:28 +0000153 "headers": ["shared_mutex"],
154 "depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
155 "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
Eric Fiselier32784a72019-01-16 01:37:43 +0000156 },
157 # C++17 macros
158 {"name": "__cpp_lib_atomic_is_always_lock_free",
159 "values": {
160 "c++17": 201603L,
161 },
Eric Fiselier05019eb2019-01-16 02:10:28 +0000162 "headers": ["atomic"],
163 "depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
164 "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
Eric Fiselier32784a72019-01-16 01:37:43 +0000165 },
166 {"name": "__cpp_lib_filesystem",
167 "values": {
168 "c++17": 201703L,
169 },
170 "headers": ["filesystem"]
171 },
172 {"name": "__cpp_lib_invoke",
173 "values": {
174 "c++17": 201411L,
175 },
176 "headers": ["functional"]
177 },
178 {"name": "__cpp_lib_void_t",
179 "values": {
180 "c++17": 201411L,
181 },
182 "headers": ["type_traits"]
183 },
184 {"name": "__cpp_lib_node_extract",
185 "values": {
186 "c++17": 201606L,
187 },
188 "headers": ["map", "set", "unordered_map", "unordered_set"]
189 },
190 {"name": "__cpp_lib_byte",
191 "values": {
192 "c++17": 201603L,
193 },
194 "headers": ["cstddef"],
195 },
196 {"name": "__cpp_lib_hardware_interference_size",
197 "values": {
198 "c++17": 201703L,
199 },
200 "headers": ["new"],
201 },
202 {"name": "__cpp_lib_launder",
203 "values": {
204 "c++17": 201606L,
205 },
206 "headers": ["new"],
207 },
208 {"name": "__cpp_lib_uncaught_exceptions",
209 "values": {
210 "c++17": 201411L,
211 },
212 "headers": ["exception"],
213 },
214 {"name": "__cpp_lib_as_const",
215 "values": {
216 "c++17": 201510L,
217 },
218 "headers": ["utility"],
219 },
220 {"name": "__cpp_lib_make_from_tuple",
221 "values": {
222 "c++17": 201606L,
223 },
224 "headers": ["tuple"],
225 },
226 {"name": "__cpp_lib_apply",
227 "values": {
228 "c++17": 201603L,
229 },
230 "headers": ["tuple"],
231 },
232 {"name": "__cpp_lib_optional",
233 "values": {
234 "c++17": 201606L,
235 },
236 "headers": ["optional"],
237 },
238 {"name": "__cpp_lib_variant",
239 "values": {
240 "c++17": 201606L,
241 },
242 "headers": ["variant"],
243 },
244 {"name": "__cpp_lib_any",
245 "values": {
246 "c++17": 201606L,
247 },
248 "headers": ["any"],
249 },
250 {"name": "__cpp_lib_addressof_constexpr",
251 "values": {
252 "c++17": 201603L,
253 },
254 "headers": ["memory"],
255 "depends": "TEST_HAS_BUILTIN(__builtin_addressof) || TEST_GCC_VER >= 700",
256 "internal_depends": "!defined(_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF)",
257 },
258 {"name": "__cpp_lib_raw_memory_algorithms",
259 "values": {
260 "c++17": 201606L,
261 },
262 "headers": ["memory"],
263 },
264 {"name": "__cpp_lib_enable_shared_from_this",
265 "values": {
266 "c++17": 201603L,
267 },
268 "headers": ["memory"],
269 },
270 {"name": "__cpp_lib_shared_ptr_weak_type",
271 "values": {
272 "c++17": 201606L,
273 },
274 "headers": ["memory"],
275 },
276 {"name": "__cpp_lib_shared_ptr_arrays",
277 "values": {
278 "c++17": 201611L,
279 },
280 "headers": ["memory"],
281 "unimplemented": True,
282 },
283 {"name": "__cpp_lib_memory_resource",
284 "values": {
285 "c++17": 201603L,
286 },
287 "headers": ["memory_resource"],
288 "unimplemented": True,
289 },
290 {"name": "__cpp_lib_boyer_moore_searcher",
291 "values": {
292 "c++17": 201603L,
293 },
294 "headers": ["functional"],
295 "unimplemented": True,
296 },
297 {"name": "__cpp_lib_not_fn",
298 "values": {
299 "c++17": 201603L,
300 },
301 "headers": ["functional"],
302 },
303 {"name": "__cpp_lib_bool_constant",
304 "values": {
305 "c++17": 201505L,
306 },
307 "headers": ["type_traits"],
308 },
309 {"name": "__cpp_lib_type_trait_variable_templates",
310 "values": {
311 "c++17": 201510L,
312 },
313 "headers": ["type_traits"],
314 },
315 {"name": "__cpp_lib_logical_traits",
316 "values": {
317 "c++17": 201510L,
318 },
319 "headers": ["type_traits"],
320 },
321 {"name": "__cpp_lib_is_swappable",
322 "values": {
323 "c++17": 201603L,
324 },
325 "headers": ["type_traits"],
326 },
327 {"name": "__cpp_lib_is_invocable",
328 "values": {
329 "c++17": 201703L,
330 },
331 "headers": ["type_traits"],
332 },
333 {"name": "__cpp_lib_has_unique_object_representations",
334 "values": {
335 "c++17": 201606L,
336 },
337 "headers": ["type_traits"],
338 "depends": "TEST_HAS_BUILTIN_IDENTIFIER(__has_unique_object_representations) || TEST_GCC_VER >= 700",
339 "internal_depends": "defined(_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS)",
340 },
341 {"name": "__cpp_lib_is_aggregate",
342 "values": {
343 "c++17": 201703L,
344 },
345 "headers": ["type_traits"],
346 "depends": "TEST_HAS_BUILTIN_IDENTIFIER(__is_aggregate) || TEST_GCC_VER_NEW >= 7001",
347 "internal_depends": "!defined(_LIBCPP_HAS_NO_IS_AGGREGATE)",
348 },
349 {"name": "__cpp_lib_chrono",
350 "values": {
351 "c++17": 201611L,
352 },
353 "headers": ["chrono"],
354 },
355 {"name": "__cpp_lib_execution",
356 "values": {
357 "c++17": 201603L,
358 },
359 "headers": ["execution"],
360 "unimplemented": True
361 },
362 {"name": "__cpp_lib_parallel_algorithm",
363 "values": {
364 "c++17": 201603L,
365 },
366 "headers": ["algorithm", "numeric"],
367 "unimplemented": True,
368 },
369 {"name": "__cpp_lib_to_chars",
370 "values": {
371 "c++17": 201611L,
372 },
373 "headers": ["utility"],
374 "unimplemented": True,
375 },
376 {"name": "__cpp_lib_string_view",
377 "values": {
378 "c++17": 201606L,
379 },
380 "headers": ["string", "string_view"],
381 },
382 {"name": "__cpp_lib_allocator_traits_is_always_equal",
383 "values": {
384 "c++17": 201411L,
385 },
386 "headers": ["memory", "scoped_allocator", "string", "deque", "forward_list", "list", "vector", "map", "set", "unordered_map", "unordered_set"],
387 },
388 {"name": "__cpp_lib_incomplete_container_elements",
389 "values": {
390 "c++17": 201505L,
391 },
392 "headers": ["forward_list", "list", "vector"],
393 },
394 {"name": "__cpp_lib_map_try_emplace",
395 "values": {
396 "c++17": 201411L,
397 },
398 "headers": ["map"],
399 },
400 {"name": "__cpp_lib_unordered_map_try_emplace",
401 "values": {
402 "c++17": 201411L,
403 },
404 "headers": ["unordered_map"],
405 },
406 {"name": "__cpp_lib_array_constexpr",
407 "values": {
408 "c++17": 201603L,
409 },
410 "headers": ["iterator", "array"],
411 },
412 {"name": "__cpp_lib_nonmember_container_access",
413 "values": {
414 "c++17": 201411L,
415 },
416 "headers": ["iterator", "array", "deque", "forward_list", "list", "map", "regex",
417 "set", "string", "unordered_map", "unordered_set", "vector"],
418 },
419 {"name": "__cpp_lib_sample",
420 "values": {
421 "c++17": 201603L,
422 },
423 "headers": ["algorithm"],
424 },
425 {"name": "__cpp_lib_clamp",
426 "values": {
427 "c++17": 201603L,
428 },
429 "headers": ["algorithm"],
430 },
431 {"name": "__cpp_lib_gcd_lcm",
432 "values": {
433 "c++17": 201606L,
434 },
435 "headers": ["numeric"],
436 },
437 {"name": "__cpp_lib_hypot",
438 "values": {
439 "c++17": 201603L,
440 },
441 "headers": ["cmath"],
442 },
443 {"name": "__cpp_lib_math_special_functions",
444 "values": {
445 "c++17": 201603L,
446 },
447 "headers": ["cmath"],
448 "unimplemented": True,
449 },
450 {"name": "__cpp_lib_shared_mutex",
451 "values": {
452 "c++17": 201505L,
453 },
454 "headers": ["shared_mutex"],
Eric Fiselier05019eb2019-01-16 02:10:28 +0000455 "depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
456 "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
Eric Fiselier32784a72019-01-16 01:37:43 +0000457 },
458 {"name": "__cpp_lib_scoped_lock",
459 "values": {
460 "c++17": 201703L,
461 },
462 "headers": ["mutex"],
463 },
464 # C++2a
465 {"name": "__cpp_lib_char8_t",
466 "values": {
467 "c++2a": 201811L,
468 },
469 "headers": ["atomic", "filesystem", "istream", "limits", "locale", "ostream",
470 "string", "string_view"],
471 "depends": "defined(__cpp_char8_t)",
472 "internal_depends": "!defined(_LIBCPP_NO_HAS_CHAR8_T)",
473 },
474 {"name": "__cpp_lib_erase_if",
475 "values": {
476 "c++2a": 201811L,
477 },
478 "headers": ["string", "deque", "forward_list", "list", "vector", "map",
479 "set", "unordered_map", "unordered_set"]
480 },
481 {"name": "__cpp_lib_destroying_delete",
482 "values": {
483 "c++2a": 201806L,
484 },
485 "headers": ["new"],
Eric Fiselierae02e892019-05-23 23:46:44 +0000486 "depends":
487 "TEST_STD_VER > 17"
488 " && defined(__cpp_impl_destroying_delete)"
489 " && __cpp_impl_destroying_delete >= 201806L",
490 "internal_depends":
491 "_LIBCPP_STD_VER > 17"
492 " && defined(__cpp_impl_destroying_delete)"
493 " && __cpp_impl_destroying_delete >= 201806L",
Eric Fiselier32784a72019-01-16 01:37:43 +0000494 },
495 {"name": "__cpp_lib_three_way_comparison",
496 "values": {
497 "c++2a": 201711L,
498 },
499 "headers": ["compare"],
500 "unimplemented": True,
501 },
502 {"name": "__cpp_lib_concepts",
503 "values": {
504 "c++2a": 201806L,
505 },
506 "headers": ["concepts"],
507 "unimplemented": True,
508 },
509 {"name": "__cpp_lib_constexpr_swap_algorithms",
510 "values": {
511 "c++2a": 201806L,
512 },
513 "headers": ["algorithm"],
514 "unimplemented": True,
515 },
516 {"name": "__cpp_lib_constexpr_misc",
517 "values": {
518 "c++2a": 201811L,
519 },
520 "headers": ["array", "functional", "iterator", "string_view", "tuple", "utility"],
521 "unimplemented": True,
522 },
523 {"name": "__cpp_lib_bind_front",
524 "values": {
525 "c++2a": 201811L,
526 },
527 "headers": ["functional"],
528 "unimplemented": True,
529 },
530 {"name": "__cpp_lib_is_constant_evaluated",
531 "values": {
532 "c++2a": 201811L,
533 },
534 "headers": ["type_traits"],
Eric Fiselier2fc5a782019-04-24 17:54:25 +0000535 "depends": "TEST_HAS_BUILTIN(__builtin_is_constant_evaluated) || TEST_GCC_VER >= 900",
536 "internal_depends": "!defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED)",
Eric Fiselier32784a72019-01-16 01:37:43 +0000537 },
538 {"name": "__cpp_lib_list_remove_return_type",
539 "values": {
540 "c++2a": 201806L,
541 },
542 "headers": ["forward_list", "list"],
543 "unimplemented": True,
544 },
545 {"name": "__cpp_lib_generic_unordered_lookup",
546 "values": {
547 "c++2a": 201811L,
548 },
549 "headers": ["unordered_map", "unordered_set"],
550 "unimplemented": True,
551 },
552 {"name": "__cpp_lib_ranges",
553 "values": {
554 "c++2a": 201811L,
555 },
556 "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
557 "unimplemented": True,
558 },
559 {"name": "__cpp_lib_bit_cast",
560 "values": {
561 "c++2a": 201806L,
562 },
563 "headers": ["bit"],
564 "unimplemented": True,
565 },
566 {"name": "__cpp_lib_atomic_ref",
567 "values": {
568 "c++2a": 201806L,
569 },
570 "headers": ["atomic"],
571 "unimplemented": True,
Eric Fiselier05019eb2019-01-16 02:10:28 +0000572 "depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
573 "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
Eric Fiselier32784a72019-01-16 01:37:43 +0000574 },
Marshall Clowd3d0ecb2019-04-25 12:11:43 +0000575 {"name": "__cpp_lib_interpolate",
576 "values": {
577 "c++2a": 201902L,
578 },
579 "headers": ["numeric"],
580 },
Eric Fiselier32784a72019-01-16 01:37:43 +0000581]], key=lambda tc: tc["name"])
582
583def get_std_dialects():
584 std_dialects = ['c++14', 'c++17', 'c++2a']
585 return list(std_dialects)
586
587def get_first_std(d):
588 for s in get_std_dialects():
589 if s in d.keys():
590 return s
591 return None
592
593def get_last_std(d):
594 rev_dialects = get_std_dialects()
595 rev_dialects.reverse()
596 for s in rev_dialects:
597 if s in d.keys():
598 return s
599 return None
600
601def get_std_before(d, std):
602 std_dialects = get_std_dialects()
603 candidates = std_dialects[0:std_dialects.index(std)]
604 candidates.reverse()
605 for cand in candidates:
606 if cand in d.keys():
607 return cand
608 return None
609
610def get_value_before(d, std):
611 new_std = get_std_before(d, std)
612 if new_std is None:
613 return None
614 return d[new_std]
615
616def get_for_std(d, std):
617 # This catches the C++11 case for which there should be no defined feature
618 # test macros.
619 std_dialects = get_std_dialects()
620 if std not in std_dialects:
621 return None
622 # Find the value for the newest C++ dialect between C++14 and std
623 std_list = list(std_dialects[0:std_dialects.index(std)+1])
624 std_list.reverse()
625 for s in std_list:
626 if s in d.keys():
627 return d[s]
628 return None
629
630
631"""
632 Functions to produce the <version> header
633"""
634
635def produce_macros_definition_for_std(std):
636 result = ""
637 indent = 56
638 for tc in feature_test_macros:
639 if std not in tc["values"]:
640 continue
641 inner_indent = 1
642 if 'depends' in tc.keys():
643 assert 'internal_depends' in tc.keys()
644 result += "# if %s\n" % tc["internal_depends"]
645 inner_indent += 2
646 if get_value_before(tc["values"], std) is not None:
647 assert 'depends' not in tc.keys()
648 result += "# undef %s\n" % tc["name"]
649 line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])
650 line += " " * (indent - len(line))
651 line += "%sL" % tc["values"][std]
652 if 'unimplemented' in tc.keys():
653 line = "// " + line
654 result += line
655 result += "\n"
656 if 'depends' in tc.keys():
657 result += "# endif\n"
658 return result
659
660def chunks(l, n):
661 """Yield successive n-sized chunks from l."""
662 for i in range(0, len(l), n):
663 yield l[i:i + n]
664
665def produce_version_synopsis():
666 indent = 56
667 header_indent = 56 + len("20XXYYL ")
668 result = ""
669 def indent_to(s, val):
670 if len(s) >= val:
671 return s
672 s += " " * (val - len(s))
673 return s
674 line = indent_to("Macro name", indent) + "Value"
675 line = indent_to(line, header_indent) + "Headers"
676 result += line + "\n"
677 for tc in feature_test_macros:
678 prev_defined_std = get_last_std(tc["values"])
679 line = "{name: <{indent}}{value}L ".format(name=tc['name'], indent=indent,
680 value=tc["values"][prev_defined_std])
681 headers = list(tc["headers"])
682 headers.remove("version")
683 for chunk in chunks(headers, 3):
684 line = indent_to(line, header_indent)
685 chunk = ['<%s>' % header for header in chunk]
686 line += ' '.join(chunk)
687 result += line
688 result += "\n"
689 line = ""
690 while True:
691 prev_defined_std = get_std_before(tc["values"], prev_defined_std)
692 if prev_defined_std is None:
693 break
694 result += "%s%sL // %s\n" % (indent_to("", indent), tc["values"][prev_defined_std],
695 prev_defined_std.replace("c++", "C++"))
696 return result
697
698
699def produce_version_header():
700 template="""// -*- C++ -*-
701//===--------------------------- version ----------------------------------===//
702//
Chandler Carruth57b08b02019-01-19 10:56:40 +0000703// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
704// See https://llvm.org/LICENSE.txt for license information.
705// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Eric Fiselier32784a72019-01-16 01:37:43 +0000706//
707//===----------------------------------------------------------------------===//
708
709#ifndef _LIBCPP_VERSIONH
710#define _LIBCPP_VERSIONH
711
712/*
713 version synopsis
714
715{synopsis}
716
717*/
718
719#include <__config>
720
721#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
722#pragma GCC system_header
723#endif
724
725#if _LIBCPP_STD_VER > 11
726{cxx14_macros}
727#endif
728
729#if _LIBCPP_STD_VER > 14
730{cxx17_macros}
731#endif
732
733#if _LIBCPP_STD_VER > 17
734{cxx2a_macros}
735#endif
736
737#endif // _LIBCPP_VERSIONH
738"""
739 return template.format(
740 synopsis=produce_version_synopsis().strip(),
741 cxx14_macros=produce_macros_definition_for_std('c++14').strip(),
742 cxx17_macros=produce_macros_definition_for_std('c++17').strip(),
743 cxx2a_macros=produce_macros_definition_for_std('c++2a').strip())
744
745"""
746 Functions to produce test files
747"""
748
749test_types = {
750 "undefined": """
751# ifdef {name}
752# error "{name} should not be defined before {std_first}"
753# endif
754""",
755
756 "depends": """
757# if {depends}
758# ifndef {name}
759# error "{name} should be defined in {std}"
760# endif
761# if {name} != {value}
762# error "{name} should have the value {value} in {std}"
763# endif
764# else
765# ifdef {name}
766# error "{name} should not be defined when {depends} is not defined!"
767# endif
768# endif
769""",
770
771 "unimplemented": """
772# if !defined(_LIBCPP_VERSION)
773# ifndef {name}
774# error "{name} should be defined in {std}"
775# endif
776# if {name} != {value}
777# error "{name} should have the value {value} in {std}"
778# endif
779# else // _LIBCPP_VERSION
780# ifdef {name}
781# error "{name} should not be defined because it is unimplemented in libc++!"
782# endif
783# endif
784""",
785
786 "defined":"""
787# ifndef {name}
788# error "{name} should be defined in {std}"
789# endif
790# if {name} != {value}
791# error "{name} should have the value {value} in {std}"
792# endif
793"""
794}
795
796def generate_std_test(test_list, std):
797 result = ""
798 for tc in test_list:
799 val = get_for_std(tc["values"], std)
800 if val is not None:
801 val = "%sL" % val
802 if val is None:
803 result += test_types["undefined"].format(name=tc["name"], std_first=get_first_std(tc["values"]))
804 elif 'unimplemented' in tc.keys():
805 result += test_types["unimplemented"].format(name=tc["name"], value=val, std=std)
806 elif "depends" in tc.keys():
807 result += test_types["depends"].format(name=tc["name"], value=val, std=std, depends=tc["depends"])
808 else:
809 result += test_types["defined"].format(name=tc["name"], value=val, std=std)
810 return result
811
812def generate_synopsis(test_list):
813 max_name_len = max([len(tc["name"]) for tc in test_list])
814 indent = max_name_len + 8
815 def mk_line(prefix, suffix):
816 return "{prefix: <{max_len}}{suffix}\n".format(prefix=prefix, suffix=suffix,
817 max_len=indent)
818 result = ""
819 result += mk_line("/* Constant", "Value")
820 for tc in test_list:
821 prefix = " %s" % tc["name"]
822 for std in [s for s in get_std_dialects() if s in tc["values"].keys()]:
823 result += mk_line(prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++")))
824 prefix = ""
825 result += "*/"
826 return result
827
Eric Fiselier05019eb2019-01-16 02:10:28 +0000828def is_threading_header_unsafe_to_include(h):
829 # NOTE: "<mutex>" does not blow up when included without threads.
830 return h in ['atomic', 'shared_mutex']
831
Eric Fiselier32784a72019-01-16 01:37:43 +0000832def produce_tests():
833 headers = set([h for tc in feature_test_macros for h in tc["headers"]])
834 for h in headers:
835 test_list = [tc for tc in feature_test_macros if h in tc["headers"]]
836 if not has_header(h):
837 for tc in test_list:
838 assert 'unimplemented' in tc.keys()
839 continue
Eric Fiselier05019eb2019-01-16 02:10:28 +0000840 test_tags = ""
841 if is_threading_header_unsafe_to_include(h):
842 test_tags += '\n// UNSUPPORTED: libcpp-has-no-threads\n'
Eric Fiselier32784a72019-01-16 01:37:43 +0000843 test_body = \
844"""//===----------------------------------------------------------------------===//
845//
Chandler Carruthb3ee4192019-01-19 11:38:40 +0000846// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
847// See https://llvm.org/LICENSE.txt for license information.
848// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Eric Fiselier32784a72019-01-16 01:37:43 +0000849//
850//===----------------------------------------------------------------------===//
851//
Eric Fiselier973eab82019-01-16 05:43:02 +0000852// WARNING: This test was generated by {script_name}
853// and should not be edited manually.
Eric Fiselier05019eb2019-01-16 02:10:28 +0000854{test_tags}
Eric Fiselier32784a72019-01-16 01:37:43 +0000855// <{header}>
856
857// Test the feature test macros defined by <{header}>
858
859{synopsis}
860
861#include <{header}>
862#include "test_macros.h"
863
864#if TEST_STD_VER < 14
865
866{cxx11_tests}
867
868#elif TEST_STD_VER == 14
869
870{cxx14_tests}
871
872#elif TEST_STD_VER == 17
873
874{cxx17_tests}
875
876#elif TEST_STD_VER > 17
877
878{cxx2a_tests}
879
880#endif // TEST_STD_VER > 17
881
JF Bastien73f49972019-02-05 05:34:12 +0000882int main(int, char**) {{ return 0; }}
Eric Fiselier973eab82019-01-16 05:43:02 +0000883""".format(script_name=script_name,
884 header=h,
Eric Fiselier05019eb2019-01-16 02:10:28 +0000885 test_tags=test_tags,
Eric Fiselier32784a72019-01-16 01:37:43 +0000886 synopsis=generate_synopsis(test_list),
887 cxx11_tests=generate_std_test(test_list, 'c++11').strip(),
888 cxx14_tests=generate_std_test(test_list, 'c++14').strip(),
889 cxx17_tests=generate_std_test(test_list, 'c++17').strip(),
890 cxx2a_tests=generate_std_test(test_list, 'c++2a').strip())
891 test_name = "{header}.version.pass.cpp".format(header=h)
Eric Fiselier508da412019-02-02 23:13:49 +0000892 out_path = os.path.join(macro_test_path, test_name)
Eric Fiselier32784a72019-01-16 01:37:43 +0000893 with open(out_path, 'w') as f:
894 f.write(test_body)
895
896"""
897 Produce documentation for the feature test macros
898"""
899
900def make_widths(grid):
901 widths = []
902 for i in range(0, len(grid[0])):
903 cell_width = 2 + max(reduce(lambda x,y: x+y, [[len(row[i])] for row in grid], []))
904 widths += [cell_width]
905 return widths
906
907def create_table(grid, indent):
908 indent_str = ' '*indent
909 col_widths = make_widths(grid)
910 num_cols = len(grid[0])
911 result = indent_str + add_divider(col_widths, 2)
912 header_flag = 2
913 for row_i in xrange(0, len(grid)):
914 row = grid[row_i]
915 result = result + indent_str + ' '.join([pad_cell(row[i], col_widths[i]) for i in range(0, len(row))]) + '\n'
916 is_cxx_header = row[0].startswith('**')
917 if row_i == len(grid) - 1:
918 header_flag = 2
919 result = result + indent_str + add_divider(col_widths, 1 if is_cxx_header else header_flag)
920 header_flag = 0
921 return result
922
923def add_divider(widths, header_flag):
924 if header_flag == 2:
925 return ' '.join(['='*w for w in widths]) + '\n'
926 if header_flag == 1:
927 return '-'.join(['-'*w for w in widths]) + '\n'
928 else:
929 return ' '.join(['-'*w for w in widths]) + '\n'
930
931def pad_cell(s, length, left_align=True):
932 padding = ((length - len(s)) * ' ')
933 return s + padding
934
935
936def get_status_table():
937 table = [["Macro Name", "Value"]]
938 for std in get_std_dialects():
939 table += [["**" + std.replace("c++", "C++ ") + "**", ""]]
940 for tc in feature_test_macros:
941 if std not in tc["values"].keys():
942 continue
943 value = "``%sL``" % tc["values"][std]
944 if 'unimplemented' in tc.keys():
945 value = '*unimplemented*'
946 table += [["``%s``" % tc["name"], value]]
947 return table
948
949def produce_docs():
950 doc_str = """.. _FeatureTestMacroTable:
951
952==========================
953Feature Test Macro Support
954==========================
955
956.. contents::
957 :local:
958
959Overview
960========
961
962This file documents the feature test macros currently supported by libc++.
963
964.. _feature-status:
965
966Status
967======
968
969.. table:: Current Status
970 :name: feature-status-table
971 :widths: auto
972
973{status_tables}
974
975""".format(status_tables=create_table(get_status_table(), 4))
976
977 table_doc_path = os.path.join(docs_path, 'FeatureTestMacroTable.rst')
978 with open(table_doc_path, 'w') as f:
979 f.write(doc_str)
980
981def main():
982 with tempfile.NamedTemporaryFile(mode='w', prefix='version.', delete=False) as tmp_file:
983 print("producing new <version> header as %s" % tmp_file.name)
984 tmp_file.write(produce_version_header())
985 produce_tests()
986 produce_docs()
987
988
989if __name__ == '__main__':
990 main()