[libc++] Improve generate_feature_test_macro_components.py.

This improves the naming of the fields `depends`/`internal_depends`. It
also adds the documentation for this script. The changes are based on
D99290 and its review comments.

Differential Revision: https://reviews.llvm.org/D99615
This commit is contained in:
Mark de Wever 2021-03-30 20:19:12 +02:00
parent e92d2b80c6
commit c2c68a5940
1 changed files with 87 additions and 54 deletions

View File

@ -29,13 +29,45 @@ def add_version_header(tc):
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 <version>. 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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
"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 @@ feature_test_macros = [ add_version_header(x) for x in [
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 @@ def produce_macros_definition_for_std(std):
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 @@ def produce_macros_definition_for_std(std):
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 @@ test_types = {
# 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 @@ test_types = {
# 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 @@ def generate_std_test(test_list, std):
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()