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