[libcxx-commits] [libcxx] [libc++] Improves type-safety in generator script. (PR #101880)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Aug 4 04:13:44 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Mark de Wever (mordante)
<details>
<summary>Changes</summary>
This changes the code to use dataclasses instead of dict entries. It also adds type aliases to use in the typing information and updates the typing information.
---
Full diff: https://github.com/llvm/llvm-project/pull/101880.diff
3 Files Affected:
- (modified) libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py (+19-26)
- (modified) libcxx/test/libcxx/feature_test_macro/version_header_implementation.sh.py (+61-61)
- (modified) libcxx/utils/generate_feature_test_macro_components.py (+60-50)
``````````diff
diff --git a/libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py b/libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py
index 1dec1ae612ecb..f37479490f264 100644
--- a/libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py
+++ b/libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py
@@ -11,7 +11,7 @@
import sys
sys.path.append(sys.argv[1])
-from generate_feature_test_macro_components import FeatureTestMacros
+from generate_feature_test_macro_components import FeatureTestMacros, Metadata
def test(output, expected):
@@ -19,33 +19,26 @@ def test(output, expected):
ftm = FeatureTestMacros(sys.argv[2])
+
test(
ftm.ftm_metadata,
{
- "__cpp_lib_any": {
- "headers": ["any"],
- "test_suite_guard": None,
- "libcxx_guard": None,
- },
- "__cpp_lib_barrier": {
- "headers": ["barrier"],
- "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
- "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
- },
- "__cpp_lib_format": {
- "headers": ["format"],
- "test_suite_guard": None,
- "libcxx_guard": None,
- },
- "__cpp_lib_parallel_algorithm": {
- "headers": ["algorithm", "numeric"],
- "test_suite_guard": None,
- "libcxx_guard": None,
- },
- "__cpp_lib_variant": {
- "headers": ["variant"],
- "test_suite_guard": None,
- "libcxx_guard": None,
- },
+ "__cpp_lib_any": Metadata(
+ headers=["any"], test_suite_guard=None, libcxx_guard=None
+ ),
+ "__cpp_lib_barrier": Metadata(
+ headers=["barrier"],
+ test_suite_guard="!defined(_LIBCPP_HAS_NO_THREADS) && (!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC)",
+ libcxx_guard="!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
+ ),
+ "__cpp_lib_format": Metadata(
+ headers=["format"], test_suite_guard=None, libcxx_guard=None
+ ),
+ "__cpp_lib_parallel_algorithm": Metadata(
+ headers=["algorithm", "numeric"], test_suite_guard=None, libcxx_guard=None
+ ),
+ "__cpp_lib_variant": Metadata(
+ headers=["variant"], test_suite_guard=None, libcxx_guard=None
+ ),
},
)
diff --git a/libcxx/test/libcxx/feature_test_macro/version_header_implementation.sh.py b/libcxx/test/libcxx/feature_test_macro/version_header_implementation.sh.py
index db90206ae770f..2177e150ff4d6 100644
--- a/libcxx/test/libcxx/feature_test_macro/version_header_implementation.sh.py
+++ b/libcxx/test/libcxx/feature_test_macro/version_header_implementation.sh.py
@@ -11,7 +11,7 @@
import sys
sys.path.append(sys.argv[1])
-from generate_feature_test_macro_components import FeatureTestMacros
+from generate_feature_test_macro_components import FeatureTestMacros, VersionHeader
def test(output, expected):
@@ -24,90 +24,90 @@ def test(output, expected):
{
"17": [
{
- "__cpp_lib_any": {
- "value": "201606L",
- "implemented": True,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_any": VersionHeader(
+ value="201606L",
+ implemented=True,
+ need_undef=False,
+ condition=None,
+ ),
},
{
- "__cpp_lib_parallel_algorithm": {
- "value": "201603L",
- "implemented": True,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_parallel_algorithm": VersionHeader(
+ value="201603L",
+ implemented=True,
+ need_undef=False,
+ condition=None,
+ ),
},
{
- "__cpp_lib_variant": {
- "value": "202102L",
- "implemented": True,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_variant": VersionHeader(
+ value="202102L",
+ implemented=True,
+ need_undef=False,
+ condition=None,
+ ),
},
],
"20": [
{
- "__cpp_lib_barrier": {
- "value": "201907L",
- "implemented": True,
- "need_undef": False,
- "condition": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
- },
+ "__cpp_lib_barrier": VersionHeader(
+ value="201907L",
+ implemented=True,
+ need_undef=False,
+ condition="!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
+ ),
},
{
- "__cpp_lib_format": {
- "value": "202110L",
- "implemented": False,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_format": VersionHeader(
+ value="202110L",
+ implemented=False,
+ need_undef=False,
+ condition=None,
+ ),
},
{
- "__cpp_lib_variant": {
- "value": "202106L",
- "implemented": True,
- "need_undef": True,
- "condition": None,
- },
+ "__cpp_lib_variant": VersionHeader(
+ value="202106L",
+ implemented=True,
+ need_undef=True,
+ condition=None,
+ ),
},
],
"23": [
{
- "__cpp_lib_format": {
- "value": "202207L",
- "implemented": False,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_format": VersionHeader(
+ value="202207L",
+ implemented=False,
+ need_undef=False,
+ condition=None,
+ ),
},
],
"26": [
{
- "__cpp_lib_barrier": {
- "value": "299900L",
- "implemented": True,
- "need_undef": True,
- "condition": "!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
- },
+ "__cpp_lib_barrier": VersionHeader(
+ value="299900L",
+ implemented=True,
+ need_undef=True,
+ condition="!defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC",
+ ),
},
{
- "__cpp_lib_format": {
- "value": "202311L",
- "implemented": False,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_format": VersionHeader(
+ value="202311L",
+ implemented=False,
+ need_undef=False,
+ condition=None,
+ ),
},
{
- "__cpp_lib_variant": {
- "value": "202306L",
- "implemented": True,
- "need_undef": True,
- "condition": None,
- },
+ "__cpp_lib_variant": VersionHeader(
+ value="202306L",
+ implemented=True,
+ need_undef=True,
+ condition=None,
+ ),
},
],
},
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index b041b08f02aac..620c764982e29 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -2,8 +2,15 @@
import os
from builtins import range
+from dataclasses import dataclass
from functools import reduce
-from typing import Any, Dict, List # Needed for python 3.8 compatibility.
+from typing import (
+ Any,
+ Dict,
+ List, # Needed for python 3.8 compatibility.
+ Optional,
+ TypeAlias,
+)
import functools
import json
@@ -1917,9 +1924,29 @@ def produce_docs():
f.write(doc_str)
+Std: TypeAlias = str # Standard version number
+Ftm: TypeAlias = str # The name of a feature test macro
+Value: TypeAlias = str # The value of a feature test macro including the L suffix
+
+
+ at dataclass
+class Metadata:
+ headers: list[str] = None
+ test_suite_guard: str = None
+ libcxx_guard: str = None
+
+
+ at dataclass
+class VersionHeader:
+ value: Value = None
+ implemented: bool = None
+ need_undef: bool = None
+ condition: str = None
+
+
def get_ftms(
- data, std_dialects: List[str], use_implemented_status: bool
-) -> Dict[str, Dict[str, Any]]:
+ data, std_dialects: List[Std], use_implemented_status: bool
+) -> Dict[Ftm, Dict[Std, Optional[Value]]]:
"""Impementation for FeatureTestMacros.(standard|implemented)_ftms()."""
result = dict()
for feature in data:
@@ -1956,7 +1983,7 @@ def get_ftms(
return result
-def generate_version_header_dialect_block(data: Dict[str, Any]) -> str:
+def generate_version_header_dialect_block(data: Dict[Ftm, VersionHeader]) -> str:
"""Generates the contents of the version header for a dialect.
This generates the contents of a
@@ -1967,27 +1994,29 @@ def generate_version_header_dialect_block(data: Dict[str, Any]) -> str:
result = ""
for element in data:
for ftm, entry in element.items():
- if not entry["implemented"]:
+ if not entry.implemented:
# When a FTM is not implemented don't add the guards
# or undefine the (possibly) defined macro.
- result += f'// define {ftm} {entry["value"]}\n'
+ result += f"// define {ftm} {entry.value}\n"
else:
- need_undef = entry["need_undef"]
- if entry["condition"]:
- result += f'# if {entry["condition"]}\n'
- if entry["need_undef"]:
+ need_undef = entry.need_undef
+ if entry.condition:
+ result += f"# if {entry.condition}\n"
+ if entry.need_undef:
result += f"# undef {ftm}\n"
- result += f'# define {ftm} {entry["value"]}\n'
+ result += f"# define {ftm} {entry.value}\n"
result += f"# endif\n"
else:
- if entry["need_undef"]:
+ if entry.need_undef:
result += f"# undef {ftm}\n"
- result += f'# define {ftm} {entry["value"]}\n'
+ result += f"# define {ftm} {entry.value}\n"
return result
-def generate_version_header_implementation(data: Dict[str, Dict[str, Any]]) -> str:
+def generate_version_header_implementation(
+ data: Dict[Std, Dict[Ftm, VersionHeader]]
+) -> str:
"""Generates the body of the version header."""
template = """#if _LIBCPP_STD_VER >= {dialect}
@@ -2104,7 +2133,7 @@ def __init__(self, filename: str):
self.__data = json.load(open(filename))
@functools.cached_property
- def std_dialects(self) -> List[str]:
+ def std_dialects(self) -> List[Std]:
"""Returns the C++ dialects avaiable.
The available dialects are based on the 'c++xy' keys found the 'values'
@@ -2123,63 +2152,44 @@ def std_dialects(self) -> List[str]:
return sorted(list(dialects))
@functools.cached_property
- def standard_ftms(self) -> Dict[str, Dict[str, Any]]:
+ def standard_ftms(self) -> Dict[Ftm, Dict[Std, Optional[Value]]]:
"""Returns the FTM versions per dialect in the Standard.
This function does not use the 'implemented' flag. The output contains
the versions used in the Standard. When a FTM in libc++ is not
implemented according to the Standard to output may opt to show the
expected value.
-
- The result is a dict with the following content
- - key: Name of the feature test macro.
- - value: A dict with the following content:
- * key: The version of the C++ dialect.
- * value: The value of the feature-test macro.
"""
return get_ftms(self.__data, self.std_dialects, False)
@functools.cached_property
- def implemented_ftms(self) -> Dict[str, Dict[str, Any]]:
+ def implemented_ftms(self) -> Dict[Ftm, Dict[Std, Optional[Value]]]:
"""Returns the FTM versions per dialect implemented in libc++.
Unlike `get_std_dialect_versions` this function uses the 'implemented'
flag. This returns the actual implementation status in libc++.
-
- The result is a dict with the following content
- - key: Name of the feature test macro.
- - value: A dict with the following content:
- * key: The version of the C++ dialect.
- * value: The value of the feature-test macro. When a feature-test
- macro is not implemented its value is None.
"""
return get_ftms(self.__data, self.std_dialects, True)
@functools.cached_property
- def ftm_metadata(self) -> Dict[str, Dict[str, Any]]:
+ def ftm_metadata(self) -> Dict[Ftm, Metadata]:
"""Returns the metadata of the FTMs defined in the Standard.
The metadata does not depend on the C++ dialect used.
- The result is a dict with the following contents:
- - key: Name of the feature test macro.
- - value: A dict with the following content:
- * headers: The list of headers that should provide the FTM
- * test_suite_guard: The condition for testing the FTM in the test suite.
- * test_suite_guard: The condition for testing the FTM in the version header.
"""
result = dict()
for feature in self.__data:
- entry = dict()
- entry["headers"] = feature["headers"]
- entry["test_suite_guard"] = feature.get("test_suite_guard", None)
- entry["libcxx_guard"] = feature.get("libcxx_guard", None)
- result[feature["name"]] = entry
+ result[feature["name"]] = Metadata(
+ feature["headers"],
+ feature.get("test_suite_guard", None),
+ feature.get("libcxx_guard", None),
+ )
return result
@property
- def version_header_implementation(self) -> Dict[str, List[Dict[str, Any]]]:
+ def version_header_implementation(self) -> Dict[Std, Dict[Ftm, VersionHeader]]:
"""Generates the body of the version header."""
result = dict()
for std in self.std_dialects:
@@ -2195,13 +2205,13 @@ def version_header_implementation(self) -> Dict[str, List[Dict[str, Any]]]:
continue
last_value = value
- entry = dict()
- entry["value"] = value
- entry["implemented"] = self.implemented_ftms[ftm][std] != None
- entry["need_undef"] = need_undef
- entry["condition"] = self.ftm_metadata[ftm]["libcxx_guard"]
-
- need_undef = entry["implemented"]
+ entry = VersionHeader(
+ value,
+ self.implemented_ftms[ftm][std] != None,
+ need_undef,
+ self.ftm_metadata[ftm].libcxx_guard,
+ )
+ need_undef = entry.implemented
result[get_std_number(std)].append(dict({ftm: entry}))
``````````
</details>
https://github.com/llvm/llvm-project/pull/101880
More information about the libcxx-commits
mailing list