diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -29,13 +29,45 @@ tc["headers"].append("version") return tc +# ================ ============================================================ +# Field Description +# ================ ============================================================ +# name The name of the feature-test macro. +# values A dict whose keys are C++ versions and whose values are the +# value of the feature-test macro for that C++ version. +# (TODO: This isn't a very clean model for feature-test +# macros affected by multiple papers.) +# headers An array with the headers that should provide the +# feature-test macro. +# test_suite_guard An optional string field. When this field is provided, +# `libcxx_guard` must also be provided. This field is used +# only to generate the unit tests for the feature-test macros. +# It can't depend on macros defined in <__config> because the +# `test/std/` parts of the test suite are intended to be +# portable to any C++ standard library implementation, not +# just libc++. It may depend on +# * macros defined by the compiler itself, or +# * macros generated by CMake. +# In some cases we add +# `&& !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM_...)` +# in order to make libc++ pass the tests on OSX; see D94983. +# libcxx_guard An optional string field. When this field is provided, +# `test_suite_guard` must also be provided. This field is used +# only to guard the feature-test macro in . It may +# be the same as `test_suite_guard`, or it may depend on +# macros defined in <__config>. +# unimplemented An optional Boolean field with the value `True`. This field +# is only used when a feature isn't fully implemented. Once +# you've fully implemented the feature, you should remove +# this field. +# ================ ============================================================ feature_test_macros = [ add_version_header(x) for x in [ { "name": "__cpp_lib_addressof_constexpr", "values": { "c++17": 201603 }, "headers": ["memory"], - "depends": "TEST_HAS_BUILTIN(__builtin_addressof) || TEST_GCC_VER >= 700", - "internal_depends": "!defined(_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF)", + "test_suite_guard": "TEST_HAS_BUILTIN(__builtin_addressof) || TEST_GCC_VER >= 700", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF)", }, { "name": "__cpp_lib_allocator_traits_is_always_equal", "values": { "c++17": 201411 }, @@ -65,60 +97,60 @@ "name": "__cpp_lib_atomic_flag_test", "values": { "c++20": 201907 }, "headers": ["atomic"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", }, { "name": "__cpp_lib_atomic_float", "values": { "c++20": 201711 }, "headers": ["atomic"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", "unimplemented": True, }, { "name": "__cpp_lib_atomic_is_always_lock_free", "values": { "c++17": 201603 }, "headers": ["atomic"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", }, { "name": "__cpp_lib_atomic_lock_free_type_aliases", "values": { "c++20": 201907 }, "headers": ["atomic"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", }, { "name": "__cpp_lib_atomic_ref", "values": { "c++20": 201806 }, "headers": ["atomic"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", "unimplemented": True, }, { "name": "__cpp_lib_atomic_shared_ptr", "values": { "c++20": 201711 }, "headers": ["atomic"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", "unimplemented": True, }, { "name": "__cpp_lib_atomic_value_initialization", "values": { "c++20": 201911 }, "headers": ["atomic", "memory"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", "unimplemented": True, }, { "name": "__cpp_lib_atomic_wait", "values": { "c++20": 201907 }, "headers": ["atomic"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_atomic_wait)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_atomic_wait)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_atomic_wait)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_atomic_wait)", }, { "name": "__cpp_lib_barrier", "values": { "c++20": 201907 }, "headers": ["barrier"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_barrier)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_barrier)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_barrier)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_barrier)", }, { "name": "__cpp_lib_bind_front", "values": { "c++20": 201907 }, @@ -154,8 +186,8 @@ "name": "__cpp_lib_char8_t", "values": { "c++20": 201811 }, "headers": ["atomic", "filesystem", "istream", "limits", "locale", "ostream", "string", "string_view"], - "depends": "defined(__cpp_char8_t)", - "internal_depends": "!defined(_LIBCPP_NO_HAS_CHAR8_T)", + "test_suite_guard": "defined(__cpp_char8_t)", + "libcxx_guard": "!defined(_LIBCPP_NO_HAS_CHAR8_T)", }, { "name": "__cpp_lib_chrono", "values": { "c++17": 201611 }, @@ -236,8 +268,8 @@ "name": "__cpp_lib_destroying_delete", "values": { "c++20": 201806 }, "headers": ["new"], - "depends": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", - "internal_depends": "_LIBCPP_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", + "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", + "libcxx_guard": "_LIBCPP_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", }, { "name": "__cpp_lib_enable_shared_from_this", "values": { "c++17": 201603 }, @@ -263,8 +295,8 @@ "name": "__cpp_lib_filesystem", "values": { "c++17": 201703 }, "headers": ["filesystem"], - "depends": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem)", - "internal_depends": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem)" + "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem)", + "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem)" }, { "name": "__cpp_lib_format", "values": { "c++20": 201907 }, @@ -291,8 +323,8 @@ "name": "__cpp_lib_has_unique_object_representations", "values": { "c++17": 201606 }, "headers": ["type_traits"], - "depends": "TEST_HAS_BUILTIN_IDENTIFIER(__has_unique_object_representations) || TEST_GCC_VER >= 700", - "internal_depends": "defined(_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS)", + "test_suite_guard": "TEST_HAS_BUILTIN_IDENTIFIER(__has_unique_object_representations) || TEST_GCC_VER >= 700", + "libcxx_guard": "defined(_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS)", }, { "name": "__cpp_lib_hypot", "values": { "c++17": 201603 }, @@ -330,14 +362,14 @@ "name": "__cpp_lib_is_aggregate", "values": { "c++17": 201703 }, "headers": ["type_traits"], - "depends": "TEST_HAS_BUILTIN_IDENTIFIER(__is_aggregate) || TEST_GCC_VER_NEW >= 7001", - "internal_depends": "!defined(_LIBCPP_HAS_NO_IS_AGGREGATE)", + "test_suite_guard": "TEST_HAS_BUILTIN_IDENTIFIER(__is_aggregate) || TEST_GCC_VER_NEW >= 7001", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_IS_AGGREGATE)", }, { "name": "__cpp_lib_is_constant_evaluated", "values": { "c++20": 201811 }, "headers": ["type_traits"], - "depends": "TEST_HAS_BUILTIN(__builtin_is_constant_evaluated) || TEST_GCC_VER >= 900", - "internal_depends": "!defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED)", + "test_suite_guard": "TEST_HAS_BUILTIN(__builtin_is_constant_evaluated) || TEST_GCC_VER >= 900", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED)", }, { "name": "__cpp_lib_is_final", "values": { "c++14": 201402 }, @@ -376,15 +408,15 @@ "name": "__cpp_lib_jthread", "values": { "c++20": 201911 }, "headers": ["stop_token", "thread"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", "unimplemented": True, }, { "name": "__cpp_lib_latch", "values": { "c++20": 201907 }, "headers": ["latch"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_latch)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_latch)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_latch)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_latch)", }, { "name": "__cpp_lib_launder", "values": { "c++17": 201606 }, @@ -417,8 +449,8 @@ "name": "__cpp_lib_math_constants", "values": { "c++20": 201907 }, "headers": ["numbers"], - "depends": "defined(__cpp_concepts) && __cpp_concepts >= 201907L", - "internal_depends": "!defined(_LIBCPP_HAS_NO_CONCEPTS)", + "test_suite_guard": "defined(__cpp_concepts) && __cpp_concepts >= 201907L", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CONCEPTS)", }, { "name": "__cpp_lib_math_special_functions", "values": { "c++17": 201603 }, @@ -496,14 +528,14 @@ "name": "__cpp_lib_semaphore", "values": { "c++20": 201907 }, "headers": ["semaphore"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore)", }, { "name": "__cpp_lib_shared_mutex", "values": { "c++17": 201505 }, "headers": ["shared_mutex"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_mutex)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_mutex)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_mutex)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_mutex)", }, { "name": "__cpp_lib_shared_ptr_arrays", "values": { "c++17": 201611 }, @@ -516,8 +548,8 @@ "name": "__cpp_lib_shared_timed_mutex", "values": { "c++14": 201402 }, "headers": ["shared_mutex"], - "depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_timed_mutex)", - "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_timed_mutex)", + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_timed_mutex)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_timed_mutex)", }, { "name": "__cpp_lib_shift", "values": { "c++20": 201806 }, @@ -638,6 +670,8 @@ assert feature_test_macros == sorted(feature_test_macros, key=lambda tc: tc["name"]) assert all(tc["headers"] == sorted(tc["headers"]) for tc in feature_test_macros) +assert all(("libcxx_guard" in tc) == ("test_suite_guard" in tc) for tc in feature_test_macros) +assert all(all(key in ["name", "values", "headers", "libcxx_guard", "test_suite_guard", "unimplemented"] for key in tc.keys()) for tc in feature_test_macros) # Map from each header to the Lit annotations that should be used for # tests that include that header. @@ -721,12 +755,11 @@ if std not in tc["values"]: continue inner_indent = 1 - if 'depends' in tc.keys(): - assert 'internal_depends' in tc.keys() - result += "# if %s\n" % tc["internal_depends"] + if 'test_suite_guard' in tc.keys(): + result += "# if %s\n" % tc["libcxx_guard"] inner_indent += 2 if get_value_before(tc["values"], std) is not None: - assert 'depends' not in tc.keys() + assert 'test_suite_guard' not in tc.keys() result += "# undef %s\n" % tc["name"] line = "#%sdefine %s" % ((" " * inner_indent), tc["name"]) line += " " * (indent - len(line)) @@ -735,7 +768,7 @@ line = "// " + line result += line result += "\n" - if 'depends' in tc.keys(): + if 'test_suite_guard' in tc.keys(): result += "# endif\n" return result.strip() @@ -847,8 +880,8 @@ # endif """, - "depends": """ -# if {depends} + "test_suite_guard": """ +# if {test_suite_guard} # ifndef {name} # error "{name} should be defined in {std}" # endif @@ -857,7 +890,7 @@ # endif # else # ifdef {name} -# error "{name} should not be defined when {depends} is not defined!" +# error "{name} should not be defined when {test_suite_guard} is not defined!" # endif # endif """, @@ -897,8 +930,8 @@ result += test_types["undefined"].format(name=tc["name"], std_first=get_first_std(tc["values"])) elif 'unimplemented' in tc.keys(): result += test_types["unimplemented"].format(name=tc["name"], value=val, std=std) - elif "depends" in tc.keys(): - result += test_types["depends"].format(name=tc["name"], value=val, std=std, depends=tc["depends"]) + elif "test_suite_guard" in tc.keys(): + result += test_types["test_suite_guard"].format(name=tc["name"], value=val, std=std, test_suite_guard=tc["test_suite_guard"]) else: result += test_types["defined"].format(name=tc["name"], value=val, std=std) return result.strip()