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