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