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