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