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