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 {"name": "__cpp_lib_to_array", 590 "values": { 591 "c++2a": 201907L, 592 }, 593 "headers": ["array"], 594 }, 595]], key=lambda tc: tc["name"]) 596 597def get_std_dialects(): 598 std_dialects = ['c++14', 'c++17', 'c++2a'] 599 return list(std_dialects) 600 601def get_first_std(d): 602 for s in get_std_dialects(): 603 if s in d.keys(): 604 return s 605 return None 606 607def get_last_std(d): 608 rev_dialects = get_std_dialects() 609 rev_dialects.reverse() 610 for s in rev_dialects: 611 if s in d.keys(): 612 return s 613 return None 614 615def get_std_before(d, std): 616 std_dialects = get_std_dialects() 617 candidates = std_dialects[0:std_dialects.index(std)] 618 candidates.reverse() 619 for cand in candidates: 620 if cand in d.keys(): 621 return cand 622 return None 623 624def get_value_before(d, std): 625 new_std = get_std_before(d, std) 626 if new_std is None: 627 return None 628 return d[new_std] 629 630def get_for_std(d, std): 631 # This catches the C++11 case for which there should be no defined feature 632 # test macros. 633 std_dialects = get_std_dialects() 634 if std not in std_dialects: 635 return None 636 # Find the value for the newest C++ dialect between C++14 and std 637 std_list = list(std_dialects[0:std_dialects.index(std)+1]) 638 std_list.reverse() 639 for s in std_list: 640 if s in d.keys(): 641 return d[s] 642 return None 643 644 645""" 646 Functions to produce the <version> header 647""" 648 649def produce_macros_definition_for_std(std): 650 result = "" 651 indent = 56 652 for tc in feature_test_macros: 653 if std not in tc["values"]: 654 continue 655 inner_indent = 1 656 if 'depends' in tc.keys(): 657 assert 'internal_depends' in tc.keys() 658 result += "# if %s\n" % tc["internal_depends"] 659 inner_indent += 2 660 if get_value_before(tc["values"], std) is not None: 661 assert 'depends' not in tc.keys() 662 result += "# undef %s\n" % tc["name"] 663 line = "#%sdefine %s" % ((" " * inner_indent), tc["name"]) 664 line += " " * (indent - len(line)) 665 line += "%sL" % tc["values"][std] 666 if 'unimplemented' in tc.keys(): 667 line = "// " + line 668 result += line 669 result += "\n" 670 if 'depends' in tc.keys(): 671 result += "# endif\n" 672 return result 673 674def chunks(l, n): 675 """Yield successive n-sized chunks from l.""" 676 for i in range(0, len(l), n): 677 yield l[i:i + n] 678 679def produce_version_synopsis(): 680 indent = 56 681 header_indent = 56 + len("20XXYYL ") 682 result = "" 683 def indent_to(s, val): 684 if len(s) >= val: 685 return s 686 s += " " * (val - len(s)) 687 return s 688 line = indent_to("Macro name", indent) + "Value" 689 line = indent_to(line, header_indent) + "Headers" 690 result += line + "\n" 691 for tc in feature_test_macros: 692 prev_defined_std = get_last_std(tc["values"]) 693 line = "{name: <{indent}}{value}L ".format(name=tc['name'], indent=indent, 694 value=tc["values"][prev_defined_std]) 695 headers = list(tc["headers"]) 696 headers.remove("version") 697 for chunk in chunks(headers, 3): 698 line = indent_to(line, header_indent) 699 chunk = ['<%s>' % header for header in chunk] 700 line += ' '.join(chunk) 701 result += line 702 result += "\n" 703 line = "" 704 while True: 705 prev_defined_std = get_std_before(tc["values"], prev_defined_std) 706 if prev_defined_std is None: 707 break 708 result += "%s%sL // %s\n" % (indent_to("", indent), tc["values"][prev_defined_std], 709 prev_defined_std.replace("c++", "C++")) 710 return result 711 712 713def produce_version_header(): 714 template="""// -*- C++ -*- 715//===--------------------------- version ----------------------------------===// 716// 717// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 718// See https://llvm.org/LICENSE.txt for license information. 719// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 720// 721//===----------------------------------------------------------------------===// 722 723#ifndef _LIBCPP_VERSIONH 724#define _LIBCPP_VERSIONH 725 726/* 727 version synopsis 728 729{synopsis} 730 731*/ 732 733#include <__config> 734 735#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 736#pragma GCC system_header 737#endif 738 739#if _LIBCPP_STD_VER > 11 740{cxx14_macros} 741#endif 742 743#if _LIBCPP_STD_VER > 14 744{cxx17_macros} 745#endif 746 747#if _LIBCPP_STD_VER > 17 748{cxx2a_macros} 749#endif 750 751#endif // _LIBCPP_VERSIONH 752""" 753 return template.format( 754 synopsis=produce_version_synopsis().strip(), 755 cxx14_macros=produce_macros_definition_for_std('c++14').strip(), 756 cxx17_macros=produce_macros_definition_for_std('c++17').strip(), 757 cxx2a_macros=produce_macros_definition_for_std('c++2a').strip()) 758 759""" 760 Functions to produce test files 761""" 762 763test_types = { 764 "undefined": """ 765# ifdef {name} 766# error "{name} should not be defined before {std_first}" 767# endif 768""", 769 770 "depends": """ 771# if {depends} 772# ifndef {name} 773# error "{name} should be defined in {std}" 774# endif 775# if {name} != {value} 776# error "{name} should have the value {value} in {std}" 777# endif 778# else 779# ifdef {name} 780# error "{name} should not be defined when {depends} is not defined!" 781# endif 782# endif 783""", 784 785 "unimplemented": """ 786# if !defined(_LIBCPP_VERSION) 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 // _LIBCPP_VERSION 794# ifdef {name} 795# error "{name} should not be defined because it is unimplemented in libc++!" 796# endif 797# endif 798""", 799 800 "defined":""" 801# ifndef {name} 802# error "{name} should be defined in {std}" 803# endif 804# if {name} != {value} 805# error "{name} should have the value {value} in {std}" 806# endif 807""" 808} 809 810def generate_std_test(test_list, std): 811 result = "" 812 for tc in test_list: 813 val = get_for_std(tc["values"], std) 814 if val is not None: 815 val = "%sL" % val 816 if val is None: 817 result += test_types["undefined"].format(name=tc["name"], std_first=get_first_std(tc["values"])) 818 elif 'unimplemented' in tc.keys(): 819 result += test_types["unimplemented"].format(name=tc["name"], value=val, std=std) 820 elif "depends" in tc.keys(): 821 result += test_types["depends"].format(name=tc["name"], value=val, std=std, depends=tc["depends"]) 822 else: 823 result += test_types["defined"].format(name=tc["name"], value=val, std=std) 824 return result 825 826def generate_synopsis(test_list): 827 max_name_len = max([len(tc["name"]) for tc in test_list]) 828 indent = max_name_len + 8 829 def mk_line(prefix, suffix): 830 return "{prefix: <{max_len}}{suffix}\n".format(prefix=prefix, suffix=suffix, 831 max_len=indent) 832 result = "" 833 result += mk_line("/* Constant", "Value") 834 for tc in test_list: 835 prefix = " %s" % tc["name"] 836 for std in [s for s in get_std_dialects() if s in tc["values"].keys()]: 837 result += mk_line(prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++"))) 838 prefix = "" 839 result += "*/" 840 return result 841 842def is_threading_header_unsafe_to_include(h): 843 # NOTE: "<mutex>" does not blow up when included without threads. 844 return h in ['atomic', 'shared_mutex'] 845 846def produce_tests(): 847 headers = set([h for tc in feature_test_macros for h in tc["headers"]]) 848 for h in headers: 849 test_list = [tc for tc in feature_test_macros if h in tc["headers"]] 850 if not has_header(h): 851 for tc in test_list: 852 assert 'unimplemented' in tc.keys() 853 continue 854 test_tags = "" 855 if is_threading_header_unsafe_to_include(h): 856 test_tags += '\n// UNSUPPORTED: libcpp-has-no-threads\n' 857 test_body = \ 858"""//===----------------------------------------------------------------------===// 859// 860// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 861// See https://llvm.org/LICENSE.txt for license information. 862// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 863// 864//===----------------------------------------------------------------------===// 865// 866// WARNING: This test was generated by {script_name} 867// and should not be edited manually. 868{test_tags} 869// <{header}> 870 871// Test the feature test macros defined by <{header}> 872 873{synopsis} 874 875#include <{header}> 876#include "test_macros.h" 877 878#if TEST_STD_VER < 14 879 880{cxx11_tests} 881 882#elif TEST_STD_VER == 14 883 884{cxx14_tests} 885 886#elif TEST_STD_VER == 17 887 888{cxx17_tests} 889 890#elif TEST_STD_VER > 17 891 892{cxx2a_tests} 893 894#endif // TEST_STD_VER > 17 895 896int main(int, char**) {{ return 0; }} 897""".format(script_name=script_name, 898 header=h, 899 test_tags=test_tags, 900 synopsis=generate_synopsis(test_list), 901 cxx11_tests=generate_std_test(test_list, 'c++11').strip(), 902 cxx14_tests=generate_std_test(test_list, 'c++14').strip(), 903 cxx17_tests=generate_std_test(test_list, 'c++17').strip(), 904 cxx2a_tests=generate_std_test(test_list, 'c++2a').strip()) 905 test_name = "{header}.version.pass.cpp".format(header=h) 906 out_path = os.path.join(macro_test_path, test_name) 907 with open(out_path, 'w') as f: 908 f.write(test_body) 909 910""" 911 Produce documentation for the feature test macros 912""" 913 914def make_widths(grid): 915 widths = [] 916 for i in range(0, len(grid[0])): 917 cell_width = 2 + max(reduce(lambda x,y: x+y, [[len(row[i])] for row in grid], [])) 918 widths += [cell_width] 919 return widths 920 921def create_table(grid, indent): 922 indent_str = ' '*indent 923 col_widths = make_widths(grid) 924 num_cols = len(grid[0]) 925 result = indent_str + add_divider(col_widths, 2) 926 header_flag = 2 927 for row_i in range(0, len(grid)): 928 row = grid[row_i] 929 result = result + indent_str + ' '.join([pad_cell(row[i], col_widths[i]) for i in range(0, len(row))]) + '\n' 930 is_cxx_header = row[0].startswith('**') 931 if row_i == len(grid) - 1: 932 header_flag = 2 933 result = result + indent_str + add_divider(col_widths, 1 if is_cxx_header else header_flag) 934 header_flag = 0 935 return result 936 937def add_divider(widths, header_flag): 938 if header_flag == 2: 939 return ' '.join(['='*w for w in widths]) + '\n' 940 if header_flag == 1: 941 return '-'.join(['-'*w for w in widths]) + '\n' 942 else: 943 return ' '.join(['-'*w for w in widths]) + '\n' 944 945def pad_cell(s, length, left_align=True): 946 padding = ((length - len(s)) * ' ') 947 return s + padding 948 949 950def get_status_table(): 951 table = [["Macro Name", "Value"]] 952 for std in get_std_dialects(): 953 table += [["**" + std.replace("c++", "C++ ") + "**", ""]] 954 for tc in feature_test_macros: 955 if std not in tc["values"].keys(): 956 continue 957 value = "``%sL``" % tc["values"][std] 958 if 'unimplemented' in tc.keys(): 959 value = '*unimplemented*' 960 table += [["``%s``" % tc["name"], value]] 961 return table 962 963def produce_docs(): 964 doc_str = """.. _FeatureTestMacroTable: 965 966========================== 967Feature Test Macro Support 968========================== 969 970.. contents:: 971 :local: 972 973Overview 974======== 975 976This file documents the feature test macros currently supported by libc++. 977 978.. _feature-status: 979 980Status 981====== 982 983.. table:: Current Status 984 :name: feature-status-table 985 :widths: auto 986 987{status_tables} 988 989""".format(status_tables=create_table(get_status_table(), 4)) 990 991 table_doc_path = os.path.join(docs_path, 'FeatureTestMacroTable.rst') 992 with open(table_doc_path, 'w') as f: 993 f.write(doc_str) 994 995def main(): 996 with tempfile.NamedTemporaryFile(mode='w', prefix='version.', delete=False) as tmp_file: 997 print("producing new <version> header as %s" % tmp_file.name) 998 tmp_file.write(produce_version_header()) 999 produce_tests() 1000 produce_docs() 1001 1002 1003if __name__ == '__main__': 1004 main() 1005