1#!/usr/bin/env python 2 3import os 4from builtins import range 5from functools import reduce 6 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( 18 src_root, 19 "test", 20 "std", 21 "language.support", 22 "support.limits", 23 "support.limits.general", 24 ) 25 assert os.path.exists(macro_test_path) 26 assert os.path.exists( 27 os.path.join(macro_test_path, "version.version.compile.pass.cpp") 28 ) 29 return script_name, src_root, include_path, docs_path, macro_test_path 30 31 32script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths() 33 34 35def has_header(h): 36 h_path = os.path.join(include_path, h) 37 return os.path.exists(h_path) 38 39 40def add_version_header(tc): 41 tc["headers"].append("version") 42 return tc 43 44 45# ================ ============================================================ 46# Field Description 47# ================ ============================================================ 48# name The name of the feature-test macro. 49# values A dict whose keys are C++ versions and whose values are the 50# value of the feature-test macro for that C++ version. 51# (TODO: This isn't a very clean model for feature-test 52# macros affected by multiple papers.) 53# headers An array with the headers that should provide the 54# feature-test macro. 55# test_suite_guard An optional string field. When this field is provided, 56# `libcxx_guard` must also be provided. This field is used 57# only to generate the unit tests for the feature-test macros. 58# It can't depend on macros defined in <__config> because the 59# `test/std/` parts of the test suite are intended to be 60# portable to any C++ standard library implementation, not 61# just libc++. It may depend on 62# * macros defined by the compiler itself, or 63# * macros generated by CMake. 64# In some cases we add also depend on macros defined in <__availability>. 65# libcxx_guard An optional string field. When this field is provided, 66# `test_suite_guard` must also be provided. This field is used 67# only to guard the feature-test macro in <version>. It may 68# be the same as `test_suite_guard`, or it may depend on 69# macros defined in <__config>. 70# unimplemented An optional Boolean field with the value `True`. This field 71# is only used when a feature isn't fully implemented. Once 72# you've fully implemented the feature, you should remove 73# this field. 74# ================ ============================================================ 75feature_test_macros = [ 76 add_version_header(x) 77 for x in [ 78 { 79 "name": "__cpp_lib_adaptor_iterator_pair_constructor", 80 "values": {"c++23": 202106}, 81 "headers": ["queue", "stack"], 82 }, 83 { 84 "name": "__cpp_lib_addressof_constexpr", 85 "values": {"c++17": 201603}, 86 "headers": ["memory"], 87 }, 88 { 89 "name": "__cpp_lib_allocate_at_least", 90 "values": { 91 "c++23": 202106, 92 # Note LWG3887 Version macro for allocate_at_least 93 # "c++26": 202302, # P2652R2 Disallow User Specialization of allocator_traits 94 }, 95 "headers": ["memory"], 96 }, 97 { 98 "name": "__cpp_lib_allocator_traits_is_always_equal", 99 "values": {"c++17": 201411}, 100 "headers": [ 101 "deque", 102 "forward_list", 103 "list", 104 "map", 105 "memory", 106 "scoped_allocator", 107 "set", 108 "string", 109 "unordered_map", 110 "unordered_set", 111 "vector", 112 ], 113 }, 114 { 115 "name": "__cpp_lib_any", 116 "values": {"c++17": 201606}, 117 "headers": ["any"], 118 }, 119 { 120 "name": "__cpp_lib_apply", 121 "values": {"c++17": 201603}, 122 "headers": ["tuple"], 123 }, 124 { 125 "name": "__cpp_lib_array_constexpr", 126 "values": {"c++17": 201603, "c++20": 201811}, 127 "headers": ["array", "iterator"], 128 }, 129 { 130 "name": "__cpp_lib_as_const", 131 "values": {"c++17": 201510}, 132 "headers": ["utility"], 133 }, 134 { 135 "name": "__cpp_lib_associative_heterogeneous_erasure", 136 "values": {"c++23": 202110}, 137 "headers": ["map", "set", "unordered_map", "unordered_set"], 138 "unimplemented": True, 139 }, 140 { 141 "name": "__cpp_lib_associative_heterogeneous_insertion", 142 "values": { 143 "c++26": 202306 # P2363R5 Extending associative containers with the remaining heterogeneous overloads 144 }, 145 "headers": ["map", "set", "unordered_map", "unordered_set"], 146 "unimplemented": True, 147 }, 148 { 149 "name": "__cpp_lib_assume_aligned", 150 "values": {"c++20": 201811}, 151 "headers": ["memory"], 152 }, 153 { 154 "name": "__cpp_lib_atomic_flag_test", 155 "values": {"c++20": 201907}, 156 "headers": ["atomic"], 157 }, 158 { 159 "name": "__cpp_lib_atomic_float", 160 "values": {"c++20": 201711}, 161 "headers": ["atomic"], 162 "unimplemented": True, 163 }, 164 { 165 "name": "__cpp_lib_atomic_is_always_lock_free", 166 "values": {"c++17": 201603}, 167 "headers": ["atomic"], 168 }, 169 { 170 "name": "__cpp_lib_atomic_lock_free_type_aliases", 171 "values": {"c++20": 201907}, 172 "headers": ["atomic"], 173 }, 174 { 175 "name": "__cpp_lib_atomic_ref", 176 "values": {"c++20": 201806}, 177 "headers": ["atomic"], 178 "unimplemented": True, 179 }, 180 { 181 "name": "__cpp_lib_atomic_shared_ptr", 182 "values": {"c++20": 201711}, 183 "headers": ["atomic"], 184 "unimplemented": True, 185 }, 186 { 187 "name": "__cpp_lib_atomic_value_initialization", 188 "values": {"c++20": 201911}, 189 "headers": ["atomic", "memory"], 190 }, 191 { 192 "name": "__cpp_lib_atomic_wait", 193 "values": {"c++20": 201907}, 194 "headers": ["atomic"], 195 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC", 196 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_SYNC", 197 }, 198 { 199 "name": "__cpp_lib_barrier", 200 "values": {"c++20": 201907}, 201 "headers": ["barrier"], 202 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)", 203 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC", 204 }, 205 { 206 "name": "__cpp_lib_bind_back", 207 "values": { 208 "c++23": 202202, 209 "c++26": 202306, # P2714R1 Bind front and back to NTTP callables 210 }, 211 "headers": ["functional"], 212 "unimplemented": True, 213 }, 214 { 215 "name": "__cpp_lib_bind_front", 216 "values": { 217 "c++20": 201907, 218 "c++26": 202306, # P2714R1 Bind front and back to NTTP callables 219 }, 220 "headers": ["functional"], 221 }, 222 { 223 "name": "__cpp_lib_bit_cast", 224 "values": {"c++20": 201806}, 225 "headers": ["bit"], 226 }, 227 { 228 "name": "__cpp_lib_bitops", 229 "values": {"c++20": 201907}, 230 "headers": ["bit"], 231 }, 232 { 233 "name": "__cpp_lib_bitset", 234 "values": {"c++26": 202306}, # P2697R1 Interfacing bitset with string_view 235 "headers": ["bitset"], 236 }, 237 { 238 "name": "__cpp_lib_bool_constant", 239 "values": {"c++17": 201505}, 240 "headers": ["type_traits"], 241 }, 242 { 243 "name": "__cpp_lib_bounded_array_traits", 244 "values": {"c++20": 201902}, 245 "headers": ["type_traits"], 246 }, 247 { 248 "name": "__cpp_lib_boyer_moore_searcher", 249 "values": {"c++17": 201603}, 250 "headers": ["functional"], 251 }, 252 { 253 "name": "__cpp_lib_byte", 254 "values": {"c++17": 201603}, 255 "headers": ["cstddef"], 256 }, 257 { 258 "name": "__cpp_lib_byteswap", 259 "values": {"c++23": 202110}, 260 "headers": ["bit"], 261 }, 262 { 263 "name": "__cpp_lib_char8_t", 264 "values": {"c++20": 201907}, 265 "headers": [ 266 "atomic", 267 "filesystem", 268 "istream", 269 "limits", 270 "locale", 271 "ostream", 272 "string", 273 "string_view", 274 ], 275 "test_suite_guard": "defined(__cpp_char8_t)", 276 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CHAR8_T)", 277 }, 278 { 279 "name": "__cpp_lib_chrono", 280 "values": { 281 "c++17": 201611, 282 # "c++26": 202306, # P2592R3 Hashing support for std::chrono value classes 283 }, 284 "headers": ["chrono"], 285 }, 286 { 287 "name": "__cpp_lib_chrono_udls", 288 "values": {"c++14": 201304}, 289 "headers": ["chrono"], 290 }, 291 { 292 "name": "__cpp_lib_clamp", 293 "values": {"c++17": 201603}, 294 "headers": ["algorithm"], 295 }, 296 { 297 "name": "__cpp_lib_complex_udls", 298 "values": {"c++14": 201309}, 299 "headers": ["complex"], 300 }, 301 { 302 "name": "__cpp_lib_concepts", 303 "values": {"c++20": 202002}, 304 "headers": ["concepts"], 305 }, 306 { 307 "name": "__cpp_lib_constexpr_algorithms", 308 "values": { 309 "c++20": 201806, 310 # "c++26": 202306, # P2562R1 constexpr Stable Sorting 311 }, 312 "headers": ["algorithm", "utility"], 313 }, 314 { 315 "name": "__cpp_lib_constexpr_bitset", 316 "values": {"c++23": 202207}, 317 "headers": ["bitset"], 318 }, 319 { 320 "name": "__cpp_lib_constexpr_charconv", 321 "values": {"c++23": 202207}, 322 "headers": ["charconv"], 323 }, 324 { 325 "name": "__cpp_lib_constexpr_cmath", 326 "values": {"c++23": 202202}, 327 "headers": ["cmath", "cstdlib"], 328 "unimplemented": True, 329 }, 330 { 331 "name": "__cpp_lib_constexpr_complex", 332 "values": {"c++20": 201711}, 333 "headers": ["complex"], 334 }, 335 { 336 "name": "__cpp_lib_constexpr_dynamic_alloc", 337 "values": {"c++20": 201907}, 338 "headers": ["memory"], 339 }, 340 { 341 "name": "__cpp_lib_constexpr_functional", 342 "values": {"c++20": 201907}, 343 "headers": ["functional"], 344 }, 345 { 346 "name": "__cpp_lib_constexpr_iterator", 347 "values": {"c++20": 201811}, 348 "headers": ["iterator"], 349 }, 350 { 351 "name": "__cpp_lib_constexpr_memory", 352 "values": {"c++20": 201811, "c++23": 202202}, 353 "headers": ["memory"], 354 }, 355 { 356 "name": "__cpp_lib_constexpr_numeric", 357 "values": {"c++20": 201911}, 358 "headers": ["numeric"], 359 }, 360 { 361 "name": "__cpp_lib_constexpr_string", 362 "values": {"c++20": 201907}, 363 "headers": ["string"], 364 }, 365 { 366 "name": "__cpp_lib_constexpr_string_view", 367 "values": {"c++20": 201811}, 368 "headers": ["string_view"], 369 }, 370 { 371 "name": "__cpp_lib_constexpr_tuple", 372 "values": {"c++20": 201811}, 373 "headers": ["tuple"], 374 }, 375 { 376 "name": "__cpp_lib_constexpr_typeinfo", 377 "values": {"c++23": 202106}, 378 "headers": ["typeinfo"], 379 }, 380 { 381 "name": "__cpp_lib_constexpr_utility", 382 "values": {"c++20": 201811}, 383 "headers": ["utility"], 384 }, 385 { 386 "name": "__cpp_lib_constexpr_vector", 387 "values": {"c++20": 201907}, 388 "headers": ["vector"], 389 }, 390 { 391 "name": "__cpp_lib_copyable_function", 392 "values": {"c++26": 202306}, # P2548R6 copyable_function 393 "headers": ["functional"], 394 "unimplemented": True, 395 }, 396 { 397 "name": "__cpp_lib_coroutine", 398 "values": {"c++20": 201902}, 399 "headers": ["coroutine"], 400 }, 401 { 402 "name": "__cpp_lib_debugging", 403 "values": {"c++26": 202311}, # P2546R5 Debugging Support 404 "headers": ["debugging"], 405 "unimplemented": True, 406 }, 407 { 408 "name": "__cpp_lib_destroying_delete", 409 "values": {"c++20": 201806}, 410 "headers": ["new"], 411 "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", 412 "libcxx_guard": "_LIBCPP_STD_VER >= 20 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", 413 }, 414 { 415 "name": "__cpp_lib_enable_shared_from_this", 416 "values": {"c++17": 201603}, 417 "headers": ["memory"], 418 }, 419 { 420 "name": "__cpp_lib_endian", 421 "values": {"c++20": 201907}, 422 "headers": ["bit"], 423 }, 424 { 425 "name": "__cpp_lib_erase_if", 426 "values": {"c++20": 202002}, 427 "headers": [ 428 "deque", 429 "forward_list", 430 "list", 431 "map", 432 "set", 433 "string", 434 "unordered_map", 435 "unordered_set", 436 "vector", 437 ], 438 }, 439 { 440 "name": "__cpp_lib_exchange_function", 441 "values": {"c++14": 201304}, 442 "headers": ["utility"], 443 }, 444 { 445 "name": "__cpp_lib_execution", 446 "values": {"c++17": 201603, "c++20": 201902}, 447 "headers": ["execution"], 448 "unimplemented": True, 449 }, 450 { 451 "name": "__cpp_lib_expected", 452 "values": {"c++23": 202211}, 453 "headers": ["expected"], 454 }, 455 { 456 "name": "__cpp_lib_filesystem", 457 "values": {"c++17": 201703}, 458 "headers": ["filesystem"], 459 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY", 460 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY", 461 }, 462 { 463 "name": "__cpp_lib_format", 464 "values": { 465 # "c++20": 201907 Not implemented P1361R2 Integration of chrono with text formatting 466 # "c++20": 202106 Fully implemented 467 # "c++20": 202110 Not implemented P2372R3 Fixing locale handling in chrono formatters 468 "c++20": 202106, 469 # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types 470 # "c++26": 202311, P2918R2 Runtime format strings II (implemented) 471 }, 472 # Note these three papers are adopted at the June 2023 meeting and have sequential numbering 473 # 202304 P2510R3 Formatting pointers (Implemented) 474 # 202305 P2757R3 Type-checking format args 475 # 202306 P2637R3 Member Visit 476 "headers": ["format"], 477 "unimplemented": True, 478 }, 479 { 480 "name": "__cpp_lib_format_ranges", 481 "values": {"c++23": 202207}, 482 "headers": ["format"], 483 }, 484 { 485 "name": "__cpp_lib_format_uchar", 486 "values": { 487 "c++20": 202311 # DR P2909R4 Fix formatting of code units as integers 488 }, 489 "headers": [""], # Note not in format 490 }, 491 { 492 "name": "__cpp_lib_formatters", 493 "values": {"c++23": 202302}, 494 "headers": ["stacktrace", "thread"], 495 "unimplemented": True, 496 }, 497 { 498 "name": "__cpp_lib_forward_like", 499 "values": {"c++23": 202207}, 500 "headers": ["utility"], 501 }, 502 { 503 "name": "__cpp_lib_freestanding_algorithm", 504 "values": { 505 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes 506 }, 507 "headers": ["algorithm"], 508 "unimplemented": True, 509 }, 510 { 511 "name": "__cpp_lib_freestanding_array", 512 "values": { 513 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes 514 }, 515 "headers": ["array"], 516 "unimplemented": True, 517 }, 518 { 519 "name": "__cpp_lib_freestanding_cstring", 520 "values": { 521 "c++26": 202306 # P2338R4 Freestanding Library: Character primitives and the C library 522 # 202311 # P2407R5 Freestanding Library: Partial Classes 523 }, 524 "headers": ["cstring"], 525 "unimplemented": True, 526 }, 527 { 528 "name": "__cpp_lib_freestanding_expected", 529 "values": { 530 "c++26": 202311 # P2833R2 Freestanding Library: inout expected span 531 }, 532 "headers": ["expected"], 533 "unimplemented": True, 534 }, 535 { 536 "name": "__cpp_lib_freestanding_mdspan", 537 "values": { 538 "c++26": 202311 # P2833R2 Freestanding Library: inout expected span 539 }, 540 "headers": ["mdspan"], 541 "unimplemented": True, 542 }, 543 { 544 "name": "__cpp_lib_freestanding_optional", 545 "values": { 546 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes 547 }, 548 "headers": ["optional"], 549 "unimplemented": True, 550 }, 551 { 552 "name": "__cpp_lib_freestanding_string_view", 553 "values": { 554 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes 555 }, 556 "headers": ["string_view"], 557 "unimplemented": True, 558 }, 559 { 560 "name": "__cpp_lib_freestanding_variant", 561 "values": { 562 "c++26": 202311 # P2407R5 Freestanding Library: Partial Classes 563 }, 564 "headers": ["variant"], 565 "unimplemented": True, 566 }, 567 { 568 "name": "__cpp_lib_fstream_native_handle", 569 "values": {"c++26": 202306}, # P1759R6 Native handles and file streams 570 "headers": ["fstream"], 571 "unimplemented": True, 572 }, 573 { 574 "name": "__cpp_lib_function_ref", 575 "values": { 576 "c++26": 202306 # P0792R14 function_ref: a type-erased callable reference 577 }, 578 "headers": ["functional"], 579 "unimplemented": True, 580 }, 581 { 582 "name": "__cpp_lib_gcd_lcm", 583 "values": {"c++17": 201606}, 584 "headers": ["numeric"], 585 }, 586 { 587 "name": "__cpp_lib_generic_associative_lookup", 588 "values": {"c++14": 201304}, 589 "headers": ["map", "set"], 590 }, 591 { 592 "name": "__cpp_lib_generic_unordered_lookup", 593 "values": {"c++20": 201811}, 594 "headers": ["unordered_map", "unordered_set"], 595 }, 596 { 597 "name": "__cpp_lib_hardware_interference_size", 598 "values": {"c++17": 201703}, 599 "test_suite_guard": "!defined(_LIBCPP_VERSION) || (defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE))", 600 "libcxx_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)", 601 "headers": ["new"], 602 }, 603 { 604 "name": "__cpp_lib_has_unique_object_representations", 605 "values": {"c++17": 201606}, 606 "headers": ["type_traits"], 607 }, 608 { 609 "name": "__cpp_lib_hazard_pointer", 610 "values": {"c++26": 202306}, # P2530R3 Hazard Pointers for C++26 611 "headers": [ 612 "hazard_pointer" # TODO verify this entry since the paper was underspecified. 613 ], 614 "unimplemented": True, 615 }, 616 { 617 "name": "__cpp_lib_hypot", 618 "values": {"c++17": 201603}, 619 "headers": ["cmath"], 620 }, 621 { 622 "name": "__cpp_lib_incomplete_container_elements", 623 "values": {"c++17": 201505}, 624 "headers": ["forward_list", "list", "vector"], 625 }, 626 { 627 "name": "__cpp_lib_int_pow2", 628 "values": {"c++20": 202002}, 629 "headers": ["bit"], 630 }, 631 { 632 "name": "__cpp_lib_integer_comparison_functions", 633 "values": {"c++20": 202002}, 634 "headers": ["utility"], 635 }, 636 { 637 "name": "__cpp_lib_integer_sequence", 638 "values": {"c++14": 201304}, 639 "headers": ["utility"], 640 }, 641 { 642 "name": "__cpp_lib_integral_constant_callable", 643 "values": {"c++14": 201304}, 644 "headers": ["type_traits"], 645 }, 646 { 647 "name": "__cpp_lib_interpolate", 648 "values": {"c++20": 201902}, 649 "headers": ["cmath", "numeric"], 650 }, 651 { 652 "name": "__cpp_lib_invoke", 653 "values": {"c++17": 201411}, 654 "headers": ["functional"], 655 }, 656 { 657 "name": "__cpp_lib_invoke_r", 658 "values": {"c++23": 202106}, 659 "headers": ["functional"], 660 }, 661 { 662 "name": "__cpp_lib_ios_noreplace", 663 "values": { "c++23": 202207 }, 664 "headers": ["ios"], 665 }, 666 { 667 "name": "__cpp_lib_is_aggregate", 668 "values": {"c++17": 201703}, 669 "headers": ["type_traits"], 670 }, 671 { 672 "name": "__cpp_lib_is_constant_evaluated", 673 "values": {"c++20": 201811}, 674 "headers": ["type_traits"], 675 }, 676 { 677 "name": "__cpp_lib_is_final", 678 "values": {"c++14": 201402}, 679 "headers": ["type_traits"], 680 }, 681 { 682 "name": "__cpp_lib_is_invocable", 683 "values": {"c++17": 201703}, 684 "headers": ["type_traits"], 685 }, 686 { 687 "name": "__cpp_lib_is_layout_compatible", 688 "values": {"c++20": 201907}, 689 "headers": ["type_traits"], 690 "unimplemented": True, 691 }, 692 { 693 "name": "__cpp_lib_is_nothrow_convertible", 694 "values": {"c++20": 201806}, 695 "headers": ["type_traits"], 696 }, 697 { 698 "name": "__cpp_lib_is_null_pointer", 699 "values": {"c++14": 201309}, 700 "headers": ["type_traits"], 701 }, 702 { 703 "name": "__cpp_lib_is_pointer_interconvertible", 704 "values": {"c++20": 201907}, 705 "headers": ["type_traits"], 706 "unimplemented": True, 707 }, 708 { 709 "name": "__cpp_lib_is_scoped_enum", 710 "values": {"c++23": 202011}, 711 "headers": ["type_traits"], 712 }, 713 { 714 "name": "__cpp_lib_is_swappable", 715 "values": {"c++17": 201603}, 716 "headers": ["type_traits"], 717 }, 718 { 719 "name": "__cpp_lib_jthread", 720 "values": {"c++20": 201911}, 721 "headers": ["stop_token", "thread"], 722 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)", 723 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN) && _LIBCPP_AVAILABILITY_HAS_SYNC", 724 }, 725 { 726 "name": "__cpp_lib_latch", 727 "values": {"c++20": 201907}, 728 "headers": ["latch"], 729 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)", 730 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC", 731 }, 732 { 733 "name": "__cpp_lib_launder", 734 "values": {"c++17": 201606}, 735 "headers": ["new"], 736 }, 737 { 738 "name": "__cpp_lib_linalg", 739 "values": { 740 "c++26": 202311 # P1673 A free function linear algebra interface based on the BLAS 741 }, 742 "headers": ["linalg"], 743 "unimplemented": True, 744 }, 745 { 746 "name": "__cpp_lib_list_remove_return_type", 747 "values": {"c++20": 201806}, 748 "headers": ["forward_list", "list"], 749 }, 750 { 751 "name": "__cpp_lib_logical_traits", 752 "values": {"c++17": 201510}, 753 "headers": ["type_traits"], 754 }, 755 { 756 "name": "__cpp_lib_make_from_tuple", 757 "values": {"c++17": 201606}, 758 "headers": ["tuple"], 759 }, 760 { 761 "name": "__cpp_lib_make_reverse_iterator", 762 "values": {"c++14": 201402}, 763 "headers": ["iterator"], 764 }, 765 { 766 "name": "__cpp_lib_make_unique", 767 "values": {"c++14": 201304}, 768 "headers": ["memory"], 769 }, 770 { 771 "name": "__cpp_lib_map_try_emplace", 772 "values": {"c++17": 201411}, 773 "headers": ["map"], 774 }, 775 { 776 "name": "__cpp_lib_math_constants", 777 "values": {"c++20": 201907}, 778 "headers": ["numbers"], 779 }, 780 { 781 "name": "__cpp_lib_math_special_functions", 782 "values": {"c++17": 201603}, 783 "headers": ["cmath"], 784 "unimplemented": True, 785 }, 786 { 787 "name": "__cpp_lib_mdspan", 788 "values": {"c++23": 202207}, 789 "headers": ["mdspan"], 790 }, 791 { 792 "name": "__cpp_lib_memory_resource", 793 "values": {"c++17": 201603}, 794 "headers": ["memory_resource"], 795 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR", 796 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR", 797 }, 798 { 799 "name": "__cpp_lib_move_iterator_concept", 800 "values": {"c++20": 202207}, 801 "headers": ["iterator"], 802 }, 803 { 804 "name": "__cpp_lib_move_only_function", 805 "values": {"c++23": 202110}, 806 "headers": ["functional"], 807 "unimplemented": True, 808 }, 809 { 810 "name": "__cpp_lib_node_extract", 811 "values": {"c++17": 201606}, 812 "headers": ["map", "set", "unordered_map", "unordered_set"], 813 }, 814 { 815 "name": "__cpp_lib_nonmember_container_access", 816 "values": {"c++17": 201411}, 817 "headers": [ 818 "array", 819 "deque", 820 "forward_list", 821 "iterator", 822 "list", 823 "map", 824 "regex", 825 "set", 826 "string", 827 "unordered_map", 828 "unordered_set", 829 "vector", 830 ], 831 }, 832 { 833 "name": "__cpp_lib_not_fn", 834 "values": { 835 "c++17": 201603, 836 # "c++26": 202306, # P2714R1 Bind front and back to NTTP callables 837 }, 838 "headers": ["functional"], 839 }, 840 { 841 "name": "__cpp_lib_null_iterators", 842 "values": {"c++14": 201304}, 843 "headers": ["iterator"], 844 }, 845 { 846 "name": "__cpp_lib_optional", 847 "values": {"c++17": 201606, "c++23": 202110}, 848 "headers": ["optional"], 849 }, 850 { 851 "name": "__cpp_lib_out_ptr", 852 "values": { 853 "c++23": 202106, 854 "c++26": 202311, # P2833R2 Freestanding Library: inout expected span 855 }, 856 "headers": ["memory"], 857 "unimplemented": True, 858 }, 859 { 860 "name": "__cpp_lib_parallel_algorithm", 861 "values": {"c++17": 201603}, 862 "headers": ["algorithm", "numeric"], 863 "unimplemented": True, 864 }, 865 { 866 "name": "__cpp_lib_polymorphic_allocator", 867 "values": {"c++20": 201902}, 868 "headers": ["memory_resource"], 869 "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_PMR", 870 "libcxx_guard": "_LIBCPP_AVAILABILITY_HAS_PMR", 871 }, 872 { 873 "name": "__cpp_lib_print", 874 "values": {"c++23": 202207}, 875 "headers": ["ostream", "print"], 876 "unimplemented": True, 877 }, 878 { 879 "name": "__cpp_lib_quoted_string_io", 880 "values": {"c++14": 201304}, 881 "headers": ["iomanip"], 882 }, 883 { 884 "name": "__cpp_lib_ranges", 885 "values": {"c++20": 202207}, 886 "headers": ["algorithm", "functional", "iterator", "memory", "ranges"], 887 }, 888 { 889 "name": "__cpp_lib_ranges_as_const", 890 "values": { 891 "c++23": 202207 # P2278R4 cbegin should always return a constant iterator 892 # 202311 # DR P2836R1 std::basic_const_iterator should follow its underlying type’s convertibility 893 }, 894 "headers": ["ranges"], 895 "unimplemented": True, 896 }, 897 { 898 "name": "__cpp_lib_ranges_as_rvalue", 899 "values": {"c++23": 202207}, 900 "headers": ["ranges"], 901 }, 902 { 903 "name": "__cpp_lib_ranges_chunk", 904 "values": {"c++23": 202202}, 905 "headers": ["ranges"], 906 "unimplemented": True, 907 }, 908 { 909 "name": "__cpp_lib_ranges_chunk_by", 910 "values": {"c++23": 202202}, 911 "headers": ["ranges"], 912 }, 913 { 914 "name": "__cpp_lib_ranges_iota", 915 "values": {"c++23": 202202}, 916 "headers": ["numeric"], 917 "unimplemented": True, 918 }, 919 { 920 "name": "__cpp_lib_ranges_join_with", 921 "values": {"c++23": 202202}, 922 "headers": ["ranges"], 923 "unimplemented": True, 924 }, 925 { 926 "name": "__cpp_lib_ranges_repeat", 927 "values": {"c++23": 202207}, 928 "headers": ["ranges"], 929 }, 930 { 931 "name": "__cpp_lib_ranges_slide", 932 "values": {"c++23": 202202}, 933 "headers": ["ranges"], 934 "unimplemented": True, 935 }, 936 { 937 "name": "__cpp_lib_ranges_starts_ends_with", 938 "values": {"c++23": 202106}, 939 "headers": ["algorithm"], 940 "unimplemented": True, 941 }, 942 { 943 "name": "__cpp_lib_ranges_to_container", 944 "values": {"c++23": 202202}, 945 "headers": [ 946 "deque", 947 "forward_list", 948 "list", 949 "map", 950 "queue", 951 "ranges", 952 "set", 953 "stack", 954 "string", 955 "unordered_map", 956 "unordered_set", 957 "vector", 958 ], 959 }, 960 { 961 "name": "__cpp_lib_ranges_zip", 962 "values": {"c++23": 202110}, 963 "headers": ["ranges", "tuple", "utility"], 964 "unimplemented": True, 965 }, 966 { 967 "name": "__cpp_lib_ratio", 968 "values": {"c++26": 202306}, # P2734R0 Adding the new SI prefixes 969 "headers": ["ratio"], 970 }, 971 { 972 "name": "__cpp_lib_raw_memory_algorithms", 973 "values": {"c++17": 201606}, 974 "headers": ["memory"], 975 }, 976 { 977 "name": "__cpp_lib_rcu", 978 "values": {"c++26": 202306}, # P2545R4 Read-Copy Update (RCU) 979 "headers": [ 980 "rcu" # TODO verify this entry since the paper was underspecified. 981 ], 982 "unimplemented": True, 983 }, 984 { 985 "name": "__cpp_lib_reference_from_temporary", 986 "values": {"c++23": 202202}, 987 "headers": ["type_traits"], 988 "unimplemented": True, 989 }, 990 { 991 "name": "__cpp_lib_remove_cvref", 992 "values": {"c++20": 201711}, 993 "headers": ["type_traits"], 994 }, 995 { 996 "name": "__cpp_lib_result_of_sfinae", 997 "values": {"c++14": 201210}, 998 "headers": ["functional", "type_traits"], 999 }, 1000 { 1001 "name": "__cpp_lib_robust_nonmodifying_seq_ops", 1002 "values": {"c++14": 201304}, 1003 "headers": ["algorithm"], 1004 }, 1005 { 1006 "name": "__cpp_lib_sample", 1007 "values": {"c++17": 201603}, 1008 "headers": ["algorithm"], 1009 }, 1010 { 1011 "name": "__cpp_lib_saturation_arithmetic", 1012 "values": {"c++26": 202311}, # P0543R3 Saturation arithmetic 1013 "headers": [""], # Note not in <numerics> 1014 "unimplemented": True, 1015 }, 1016 { 1017 "name": "__cpp_lib_scoped_lock", 1018 "values": {"c++17": 201703}, 1019 "headers": ["mutex"], 1020 }, 1021 { 1022 "name": "__cpp_lib_semaphore", 1023 "values": {"c++20": 201907}, 1024 "headers": ["semaphore"], 1025 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)", 1026 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC", 1027 }, 1028 { 1029 "name": "__cpp_lib_shared_mutex", 1030 "values": {"c++17": 201505}, 1031 "headers": ["shared_mutex"], 1032 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", 1033 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", 1034 }, 1035 { 1036 "name": "__cpp_lib_shared_ptr_arrays", 1037 "values": {"c++17": 201611, "c++20": 201707}, 1038 "headers": ["memory"], 1039 }, 1040 { 1041 "name": "__cpp_lib_shared_ptr_weak_type", 1042 "values": {"c++17": 201606}, 1043 "headers": ["memory"], 1044 }, 1045 { 1046 "name": "__cpp_lib_shared_timed_mutex", 1047 "values": {"c++14": 201402}, 1048 "headers": ["shared_mutex"], 1049 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", 1050 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", 1051 }, 1052 { 1053 "name": "__cpp_lib_shift", 1054 "values": {"c++20": 201806}, 1055 "headers": ["algorithm"], 1056 }, 1057 { 1058 "name": "__cpp_lib_smart_ptr_for_overwrite", 1059 "values": {"c++20": 202002}, 1060 "headers": ["memory"], 1061 "unimplemented": True, 1062 }, 1063 { 1064 "name": "__cpp_lib_smart_ptr_owner_equality", 1065 "values": { 1066 "c++26": 202306 # P1901R2 Enabling the Use of weak_ptr as Keys in Unordered Associative Containers 1067 }, 1068 "headers": ["memory"], 1069 "unimplemented": True, 1070 }, 1071 { 1072 "name": "__cpp_lib_source_location", 1073 "values": {"c++20": 201907}, 1074 "headers": ["source_location"], 1075 "test_suite_guard": "__has_builtin(__builtin_source_location) && !(defined(TEST_APPLE_CLANG_VER) && TEST_APPLE_CLANG_VER <= 1403)", 1076 "libcxx_guard": "__has_builtin(__builtin_source_location) && !(defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER <= 1403)", 1077 }, 1078 { 1079 "name": "__cpp_lib_span", 1080 "values": { 1081 "c++20": 202002, 1082 # "c++26": 202311, # P2821R5 span.at() 1083 # 202311 # P2833R2 Freestanding Library: inout expected span 1084 }, 1085 "headers": ["span"], 1086 }, 1087 { 1088 "name": "__cpp_lib_span_initializer_list", 1089 "values": {"c++26": 202311}, # P2447R6 std::span over an initializer list 1090 "headers": ["span"], 1091 "unimplemented": True, 1092 }, 1093 { 1094 "name": "__cpp_lib_spanstream", 1095 "values": {"c++23": 202106}, 1096 "headers": ["spanstream"], 1097 "unimplemented": True, 1098 }, 1099 { 1100 "name": "__cpp_lib_ssize", 1101 "values": {"c++20": 201902}, 1102 "headers": ["iterator"], 1103 }, 1104 { 1105 "name": "__cpp_lib_sstream_from_string_view", 1106 "values": { 1107 "c++26": 202306 # P2495R3 Interfacing stringstreams with string_view 1108 }, 1109 "headers": ["sstream"], 1110 "unimplemented": True, 1111 }, 1112 { 1113 "name": "__cpp_lib_stacktrace", 1114 "values": {"c++23": 202011}, 1115 "headers": ["stacktrace"], 1116 "unimplemented": True, 1117 }, 1118 { 1119 "name": "__cpp_lib_starts_ends_with", 1120 "values": {"c++20": 201711}, 1121 "headers": ["string", "string_view"], 1122 }, 1123 { 1124 "name": "__cpp_lib_stdatomic_h", 1125 "values": {"c++23": 202011}, 1126 "headers": ["stdatomic.h"], 1127 }, 1128 { 1129 "name": "__cpp_lib_string_contains", 1130 "values": {"c++23": 202011}, 1131 "headers": ["string", "string_view"], 1132 }, 1133 { 1134 "name": "__cpp_lib_string_resize_and_overwrite", 1135 "values": {"c++23": 202110}, 1136 "headers": ["string"], 1137 }, 1138 { 1139 "name": "__cpp_lib_string_udls", 1140 "values": {"c++14": 201304}, 1141 "headers": ["string"], 1142 }, 1143 { 1144 "name": "__cpp_lib_string_view", 1145 "values": {"c++17": 201606, "c++20": 201803}, 1146 "headers": ["string", "string_view"], 1147 }, 1148 { 1149 "name": "__cpp_lib_submdspan", 1150 "values": {"c++26": 202306}, # P2630R4 submdspan 1151 "headers": ["mdspan"], 1152 "unimplemented": True, 1153 }, 1154 { 1155 "name": "__cpp_lib_syncbuf", 1156 "values": {"c++20": 201803}, 1157 "headers": ["syncstream"], 1158 "test_suite_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)", 1159 "libcxx_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)", 1160 }, 1161 { 1162 "name": "__cpp_lib_text_encoding", 1163 "values": { 1164 "c++26": 202306 # P1885R12 Naming Text Encodings to Demystify Them 1165 }, 1166 "headers": ["text_encoding"], 1167 "unimplemented": True, 1168 }, 1169 { 1170 "name": "__cpp_lib_three_way_comparison", 1171 "values": {"c++20": 201907}, 1172 "headers": ["compare"], 1173 "unimplemented": True, 1174 }, 1175 { 1176 "name": "__cpp_lib_to_address", 1177 "values": {"c++20": 201711}, 1178 "headers": ["memory"], 1179 }, 1180 { 1181 "name": "__cpp_lib_to_array", 1182 "values": {"c++20": 201907}, 1183 "headers": ["array"], 1184 }, 1185 { 1186 "name": "__cpp_lib_to_chars", 1187 "values": { 1188 "c++17": 201611, 1189 "c++26": 202306, # P2497R0 Testing for success or failure of <charconv> functions 1190 }, 1191 "headers": ["charconv"], 1192 "unimplemented": True, 1193 }, 1194 { 1195 "name": "__cpp_lib_to_string", 1196 "values": {"c++23": 202306}, # P2587R3 to_string or not to_string 1197 "headers": ["string"], 1198 "unimplemented": True, 1199 }, 1200 { 1201 "name": "__cpp_lib_to_underlying", 1202 "values": {"c++23": 202102}, 1203 "headers": ["utility"], 1204 }, 1205 { 1206 "name": "__cpp_lib_transformation_trait_aliases", 1207 "values": {"c++14": 201304}, 1208 "headers": ["type_traits"], 1209 }, 1210 { 1211 "name": "__cpp_lib_transparent_operators", 1212 "values": {"c++14": 201210, "c++17": 201510}, 1213 "headers": ["functional", "memory"], 1214 }, 1215 { 1216 "name": "__cpp_lib_tuple_element_t", 1217 "values": {"c++14": 201402}, 1218 "headers": ["tuple"], 1219 }, 1220 { 1221 "name": "__cpp_lib_tuple_like", 1222 "values": { 1223 "c++23": 202207, # P2165R4 Compatibility between tuple, pair and tuple-like objects 1224 "c++26": 202311, # P2819R2 Add tuple protocol to complex 1225 }, 1226 "headers": ["map", "tuple", "unordered_map", "utility"], 1227 "unimplemented": True, 1228 }, 1229 { 1230 "name": "__cpp_lib_tuples_by_type", 1231 "values": {"c++14": 201304}, 1232 "headers": ["tuple", "utility"], 1233 }, 1234 { 1235 "name": "__cpp_lib_type_identity", 1236 "values": {"c++20": 201806}, 1237 "headers": ["type_traits"], 1238 }, 1239 { 1240 "name": "__cpp_lib_type_trait_variable_templates", 1241 "values": {"c++17": 201510}, 1242 "headers": ["type_traits"], 1243 }, 1244 { 1245 "name": "__cpp_lib_uncaught_exceptions", 1246 "values": {"c++17": 201411}, 1247 "headers": ["exception"], 1248 }, 1249 { 1250 "name": "__cpp_lib_unordered_map_try_emplace", 1251 "values": {"c++17": 201411}, 1252 "headers": ["unordered_map"], 1253 }, 1254 { 1255 "name": "__cpp_lib_unreachable", 1256 "values": {"c++23": 202202}, 1257 "headers": ["utility"], 1258 }, 1259 { 1260 "name": "__cpp_lib_unwrap_ref", 1261 "values": {"c++20": 201811}, 1262 "headers": ["functional"], 1263 }, 1264 { 1265 "name": "__cpp_lib_variant", 1266 "values": {"c++17": 202102}, 1267 "headers": ["variant"], 1268 }, 1269 { 1270 "name": "__cpp_lib_void_t", 1271 "values": {"c++17": 201411}, 1272 "headers": ["type_traits"], 1273 }, 1274 { 1275 "name": "__cpp_lib_within_lifetime", 1276 "values": { 1277 "c++26": 202306 # P2641R4 Checking if a union alternative is active 1278 }, 1279 "headers": ["type_traits"], 1280 "unimplemented": True, 1281 }, 1282 ] 1283] 1284 1285assert feature_test_macros == sorted(feature_test_macros, key=lambda tc: tc["name"]) 1286assert all(tc["headers"] == sorted(tc["headers"]) for tc in feature_test_macros) 1287assert all( 1288 ("libcxx_guard" in tc) == ("test_suite_guard" in tc) for tc in feature_test_macros 1289) 1290assert all( 1291 all( 1292 key 1293 in [ 1294 "name", 1295 "values", 1296 "headers", 1297 "libcxx_guard", 1298 "test_suite_guard", 1299 "unimplemented", 1300 ] 1301 for key in tc.keys() 1302 ) 1303 for tc in feature_test_macros 1304) 1305 1306# Map from each header to the Lit annotations that should be used for 1307# tests that include that header. 1308# 1309# For example, when threads are not supported, any test that includes 1310# <thread> should be marked as UNSUPPORTED, because including <thread> 1311# is a hard error in that case. 1312lit_markup = { 1313 "barrier": ["UNSUPPORTED: no-threads"], 1314 "filesystem": ["UNSUPPORTED: no-filesystem"], 1315 "fstream": ["UNSUPPORTED: no-localization"], 1316 "iomanip": ["UNSUPPORTED: no-localization"], 1317 "ios": ["UNSUPPORTED: no-localization"], 1318 "iostream": ["UNSUPPORTED: no-localization"], 1319 "istream": ["UNSUPPORTED: no-localization"], 1320 "latch": ["UNSUPPORTED: no-threads"], 1321 "locale": ["UNSUPPORTED: no-localization"], 1322 "mutex": ["UNSUPPORTED: no-threads"], 1323 "ostream": ["UNSUPPORTED: no-localization"], 1324 "print": ["UNSUPPORTED: no-filesystem"], 1325 "regex": ["UNSUPPORTED: no-localization"], 1326 "semaphore": ["UNSUPPORTED: no-threads"], 1327 "shared_mutex": ["UNSUPPORTED: no-threads"], 1328 "sstream": ["UNSUPPORTED: no-localization"], 1329 "syncstream": ["UNSUPPORTED: no-localization"], 1330 "stdatomic.h": ["UNSUPPORTED: no-threads"], 1331 "stop_token": ["UNSUPPORTED: no-threads"], 1332 "thread": ["UNSUPPORTED: no-threads"], 1333} 1334 1335 1336def get_std_dialects(): 1337 std_dialects = ["c++14", "c++17", "c++20", "c++23", "c++26"] 1338 return list(std_dialects) 1339 1340 1341def get_first_std(d): 1342 for s in get_std_dialects(): 1343 if s in d.keys(): 1344 return s 1345 return None 1346 1347 1348def get_last_std(d): 1349 rev_dialects = get_std_dialects() 1350 rev_dialects.reverse() 1351 for s in rev_dialects: 1352 if s in d.keys(): 1353 return s 1354 return None 1355 1356 1357def get_std_before(d, std): 1358 std_dialects = get_std_dialects() 1359 candidates = std_dialects[0 : std_dialects.index(std)] 1360 candidates.reverse() 1361 for cand in candidates: 1362 if cand in d.keys(): 1363 return cand 1364 return None 1365 1366 1367def get_value_before(d, std): 1368 new_std = get_std_before(d, std) 1369 if new_std is None: 1370 return None 1371 return d[new_std] 1372 1373 1374def get_for_std(d, std): 1375 # This catches the C++11 case for which there should be no defined feature 1376 # test macros. 1377 std_dialects = get_std_dialects() 1378 if std not in std_dialects: 1379 return None 1380 # Find the value for the newest C++ dialect between C++14 and std 1381 std_list = list(std_dialects[0 : std_dialects.index(std) + 1]) 1382 std_list.reverse() 1383 for s in std_list: 1384 if s in d.keys(): 1385 return d[s] 1386 return None 1387 1388 1389def get_std_number(std): 1390 return std.replace("c++", "") 1391 1392 1393""" 1394 Functions to produce the <version> header 1395""" 1396 1397 1398def produce_macros_definition_for_std(std): 1399 result = "" 1400 indent = 55 1401 for tc in feature_test_macros: 1402 if std not in tc["values"]: 1403 continue 1404 inner_indent = 1 1405 if "test_suite_guard" in tc.keys(): 1406 result += "# if %s\n" % tc["libcxx_guard"] 1407 inner_indent += 2 1408 if get_value_before(tc["values"], std) is not None: 1409 assert "test_suite_guard" not in tc.keys() 1410 result += "# undef %s\n" % tc["name"] 1411 line = "#%sdefine %s" % ((" " * inner_indent), tc["name"]) 1412 line += " " * (indent - len(line)) 1413 line += " %sL" % tc["values"][std] 1414 if "unimplemented" in tc.keys(): 1415 line = "// " + line 1416 result += line 1417 result += "\n" 1418 if "test_suite_guard" in tc.keys(): 1419 result += "# endif\n" 1420 return result.strip() 1421 1422 1423def produce_macros_definitions(): 1424 macro_definition_template = """#if _LIBCPP_STD_VER >= {std_number} 1425{macro_definition} 1426#endif""" 1427 1428 macros_definitions = [] 1429 for std in get_std_dialects(): 1430 macros_definitions.append( 1431 macro_definition_template.format( 1432 std_number=get_std_number(std), 1433 macro_definition=produce_macros_definition_for_std(std), 1434 ) 1435 ) 1436 1437 return "\n\n".join(macros_definitions) 1438 1439 1440def chunks(l, n): 1441 """Yield successive n-sized chunks from l.""" 1442 for i in range(0, len(l), n): 1443 yield l[i : i + n] 1444 1445 1446def produce_version_synopsis(): 1447 indent = 56 1448 header_indent = 56 + len("20XXYYL ") 1449 result = "" 1450 1451 def indent_to(s, val): 1452 if len(s) >= val: 1453 return s 1454 s += " " * (val - len(s)) 1455 return s 1456 1457 line = indent_to("Macro name", indent) + "Value" 1458 line = indent_to(line, header_indent) + "Headers" 1459 result += line + "\n" 1460 for tc in feature_test_macros: 1461 prev_defined_std = get_last_std(tc["values"]) 1462 line = "{name: <{indent}}{value}L ".format( 1463 name=tc["name"], indent=indent, value=tc["values"][prev_defined_std] 1464 ) 1465 headers = list(tc["headers"]) 1466 headers.remove("version") 1467 for chunk in chunks(headers, 3): 1468 line = indent_to(line, header_indent) 1469 chunk = ["<%s>" % header for header in chunk] 1470 line += " ".join(chunk) 1471 result += line 1472 result += "\n" 1473 line = "" 1474 while True: 1475 prev_defined_std = get_std_before(tc["values"], prev_defined_std) 1476 if prev_defined_std is None: 1477 break 1478 result += "%s%sL // %s\n" % ( 1479 indent_to("", indent), 1480 tc["values"][prev_defined_std], 1481 prev_defined_std.replace("c++", "C++"), 1482 ) 1483 return result 1484 1485 1486def produce_version_header(): 1487 template = """// -*- C++ -*- 1488//===----------------------------------------------------------------------===// 1489// 1490// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 1491// See https://llvm.org/LICENSE.txt for license information. 1492// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 1493// 1494//===----------------------------------------------------------------------===// 1495 1496#ifndef _LIBCPP_VERSIONH 1497#define _LIBCPP_VERSIONH 1498 1499/* 1500 version synopsis 1501 1502{synopsis} 1503 1504*/ 1505 1506#include <__assert> // all public C++ headers provide the assertion handler 1507#include <__availability> 1508#include <__config> 1509 1510#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 1511# pragma GCC system_header 1512#endif 1513 1514// clang-format off 1515 1516{cxx_macros} 1517 1518// clang-format on 1519 1520#endif // _LIBCPP_VERSIONH 1521""" 1522 1523 version_str = template.format( 1524 synopsis=produce_version_synopsis().strip(), 1525 cxx_macros=produce_macros_definitions(), 1526 ) 1527 version_header_path = os.path.join(include_path, "version") 1528 with open(version_header_path, "w", newline="\n") as f: 1529 f.write(version_str) 1530 1531 1532""" 1533 Functions to produce test files 1534""" 1535 1536test_types = { 1537 "undefined": """ 1538# ifdef {name} 1539# error "{name} should not be defined before {std_first}" 1540# endif 1541""", 1542 "test_suite_guard": """ 1543# if {test_suite_guard} 1544# ifndef {name} 1545# error "{name} should be defined in {std}" 1546# endif 1547# if {name} != {value} 1548# error "{name} should have the value {value} in {std}" 1549# endif 1550# else 1551# ifdef {name} 1552# error "{name} should not be defined when the requirement '{test_suite_guard}' is not met!" 1553# endif 1554# endif 1555""", 1556 "unimplemented": """ 1557# if !defined(_LIBCPP_VERSION) 1558# ifndef {name} 1559# error "{name} should be defined in {std}" 1560# endif 1561# if {name} != {value} 1562# error "{name} should have the value {value} in {std}" 1563# endif 1564# else // _LIBCPP_VERSION 1565# ifdef {name} 1566# error "{name} should not be defined because it is unimplemented in libc++!" 1567# endif 1568# endif 1569""", 1570 "defined": """ 1571# ifndef {name} 1572# error "{name} should be defined in {std}" 1573# endif 1574# if {name} != {value} 1575# error "{name} should have the value {value} in {std}" 1576# endif 1577""", 1578} 1579 1580 1581def generate_std_test(test_list, std): 1582 result = "" 1583 for tc in test_list: 1584 val = get_for_std(tc["values"], std) 1585 if val is not None: 1586 val = "%sL" % val 1587 if val is None: 1588 result += test_types["undefined"].format( 1589 name=tc["name"], std_first=get_first_std(tc["values"]) 1590 ) 1591 elif "unimplemented" in tc.keys(): 1592 result += test_types["unimplemented"].format( 1593 name=tc["name"], value=val, std=std 1594 ) 1595 elif "test_suite_guard" in tc.keys(): 1596 result += test_types["test_suite_guard"].format( 1597 name=tc["name"], 1598 value=val, 1599 std=std, 1600 test_suite_guard=tc["test_suite_guard"], 1601 ) 1602 else: 1603 result += test_types["defined"].format(name=tc["name"], value=val, std=std) 1604 return result.strip() 1605 1606 1607def generate_std_tests(test_list): 1608 std_tests_template = """#if TEST_STD_VER < {first_std_number} 1609 1610{pre_std_test} 1611 1612{other_std_tests} 1613 1614#elif TEST_STD_VER > {penultimate_std_number} 1615 1616{last_std_test} 1617 1618#endif // TEST_STD_VER > {penultimate_std_number}""" 1619 1620 std_dialects = get_std_dialects() 1621 1622 other_std_tests = [] 1623 for std in std_dialects[:-1]: 1624 other_std_tests.append("#elif TEST_STD_VER == " + get_std_number(std)) 1625 other_std_tests.append(generate_std_test(test_list, std)) 1626 1627 std_tests = std_tests_template.format( 1628 first_std_number=get_std_number(std_dialects[0]), 1629 pre_std_test=generate_std_test(test_list, "c++11"), 1630 other_std_tests="\n\n".join(other_std_tests), 1631 penultimate_std_number=get_std_number(std_dialects[-2]), 1632 last_std_test=generate_std_test(test_list, std_dialects[-1]), 1633 ) 1634 1635 return std_tests 1636 1637 1638def generate_synopsis(test_list): 1639 max_name_len = max([len(tc["name"]) for tc in test_list]) 1640 indent = max_name_len + 8 1641 1642 def mk_line(prefix, suffix): 1643 return "{prefix: <{max_len}}{suffix}\n".format( 1644 prefix=prefix, suffix=suffix, max_len=indent 1645 ) 1646 1647 result = "" 1648 result += mk_line("/* Constant", "Value") 1649 for tc in test_list: 1650 prefix = " %s" % tc["name"] 1651 for std in [s for s in get_std_dialects() if s in tc["values"].keys()]: 1652 result += mk_line( 1653 prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++")) 1654 ) 1655 prefix = "" 1656 result += "*/" 1657 return result 1658 1659 1660def produce_tests(): 1661 headers = set([h for tc in feature_test_macros for h in tc["headers"]]) 1662 for h in headers: 1663 test_list = [tc for tc in feature_test_macros if h in tc["headers"]] 1664 if not has_header(h): 1665 for tc in test_list: 1666 assert "unimplemented" in tc.keys() 1667 continue 1668 markup = "\n".join("// " + tag for tag in lit_markup.get(h, [])) 1669 test_body = """//===----------------------------------------------------------------------===// 1670// 1671// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 1672// See https://llvm.org/LICENSE.txt for license information. 1673// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 1674// 1675//===----------------------------------------------------------------------===// 1676// 1677// WARNING: This test was generated by {script_name} 1678// and should not be edited manually. 1679// 1680// clang-format off 1681{markup} 1682// <{header}> 1683 1684// Test the feature test macros defined by <{header}> 1685 1686{synopsis} 1687 1688#include <{header}> 1689#include "test_macros.h" 1690 1691{cxx_tests} 1692 1693""".format( 1694 script_name=script_name, 1695 header=h, 1696 markup=("\n{}\n".format(markup) if markup else ""), 1697 synopsis=generate_synopsis(test_list), 1698 cxx_tests=generate_std_tests(test_list), 1699 ) 1700 test_name = "{header}.version.compile.pass.cpp".format(header=h) 1701 out_path = os.path.join(macro_test_path, test_name) 1702 with open(out_path, "w", newline="\n") as f: 1703 f.write(test_body) 1704 1705 1706""" 1707 Produce documentation for the feature test macros 1708""" 1709 1710 1711def make_widths(grid): 1712 widths = [] 1713 for i in range(0, len(grid[0])): 1714 cell_width = 2 + max( 1715 reduce(lambda x, y: x + y, [[len(row[i])] for row in grid], []) 1716 ) 1717 widths += [cell_width] 1718 return widths 1719 1720 1721def create_table(grid, indent): 1722 indent_str = " " * indent 1723 col_widths = make_widths(grid) 1724 result = [indent_str + add_divider(col_widths, 2)] 1725 header_flag = 2 1726 for row_i in range(0, len(grid)): 1727 row = grid[row_i] 1728 line = indent_str + " ".join( 1729 [pad_cell(row[i], col_widths[i]) for i in range(0, len(row))] 1730 ) 1731 result.append(line.rstrip()) 1732 if row_i == len(grid) - 1: 1733 header_flag = 2 1734 if row[0].startswith("**"): 1735 header_flag += 1 1736 separator = indent_str + add_divider(col_widths, header_flag) 1737 result.append(separator.rstrip()) 1738 header_flag = 0 1739 return "\n".join(result) 1740 1741 1742def add_divider(widths, header_flag): 1743 if header_flag == 3: 1744 return "=".join(["=" * w for w in widths]) 1745 if header_flag == 2: 1746 return " ".join(["=" * w for w in widths]) 1747 if header_flag == 1: 1748 return "-".join(["-" * w for w in widths]) 1749 else: 1750 return " ".join(["-" * w for w in widths]) 1751 1752 1753def pad_cell(s, length, left_align=True): 1754 padding = (length - len(s)) * " " 1755 return s + padding 1756 1757 1758def get_status_table(): 1759 table = [["Macro Name", "Value"]] 1760 for std in get_std_dialects(): 1761 table += [["**" + std.replace("c++", "C++ ") + "**", ""]] 1762 for tc in feature_test_macros: 1763 if std not in tc["values"].keys(): 1764 continue 1765 value = "``%sL``" % tc["values"][std] 1766 if "unimplemented" in tc.keys(): 1767 value = "*unimplemented*" 1768 table += [["``%s``" % tc["name"], value]] 1769 return table 1770 1771 1772def produce_docs(): 1773 doc_str = """.. _FeatureTestMacroTable: 1774 1775========================== 1776Feature Test Macro Support 1777========================== 1778 1779.. contents:: 1780 :local: 1781 1782Overview 1783======== 1784 1785This file documents the feature test macros currently supported by libc++. 1786 1787.. _feature-status: 1788 1789Status 1790====== 1791 1792.. table:: Current Status 1793 :name: feature-status-table 1794 :widths: auto 1795 1796{status_tables} 1797 1798""".format( 1799 status_tables=create_table(get_status_table(), 4) 1800 ) 1801 1802 table_doc_path = os.path.join(docs_path, "FeatureTestMacroTable.rst") 1803 with open(table_doc_path, "w", newline="\n") as f: 1804 f.write(doc_str) 1805 1806 1807def main(): 1808 produce_version_header() 1809 produce_tests() 1810 produce_docs() 1811 1812 1813if __name__ == "__main__": 1814 main() 1815