[libcxx-commits] [libcxx] 5b9e6c7 - [libc++] Improves type-safety in generator script. (#101880)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Feb 10 09:03:47 PST 2025
Author: Mark de Wever
Date: 2025-02-10T18:03:44+01:00
New Revision: 5b9e6c7993359c16b4d645c851bb7fe2fd7b78c7
URL: https://github.com/llvm/llvm-project/commit/5b9e6c7993359c16b4d645c851bb7fe2fd7b78c7
DIFF: https://github.com/llvm/llvm-project/commit/5b9e6c7993359c16b4d645c851bb7fe2fd7b78c7.diff
LOG: [libc++] Improves type-safety in generator script. (#101880)
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.
Added:
Modified:
libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py
libcxx/test/libcxx/feature_test_macro/version_header_implementation.sh.py
libcxx/utils/generate_feature_test_macro_components.py
Removed:
################################################################################
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 541447a5916c0c5..4f23773f9a0a586 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,38 +19,29 @@ 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_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
- "libcxx_guard": "_LIBCPP_HAS_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_missing_FTM_in_older_standard": {
- "headers": [],
- "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_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
+ libcxx_guard="_LIBCPP_HAS_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
+ ),
+ "__cpp_lib_missing_FTM_in_older_standard": Metadata(
+ headers=[], 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 b9e087c2107672d..2771a2f7d8abf01 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
@@ -16,7 +16,7 @@
del sys.argv[1:3]
sys.path.append(UTILS)
-from generate_feature_test_macro_components import FeatureTestMacros
+from generate_feature_test_macro_components import FeatureTestMacros, VersionHeader
class Test(unittest.TestCase):
def setUp(self):
@@ -27,114 +27,114 @@ def test_implementation(self):
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,
+ ),
},
{
- "__cpp_lib_missing_FTM_in_older_standard": {
- "value": "2017L",
- "implemented": False,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_missing_FTM_in_older_standard" : VersionHeader(
+ value = "2017L",
+ implemented = False,
+ need_undef = False,
+ condition = None,
+ ),
},
],
"20": [
{
- "__cpp_lib_barrier": {
- "value": "201907L",
- "implemented": True,
- "need_undef": False,
- "condition": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
- },
+ "__cpp_lib_barrier": VersionHeader(
+ value="201907L",
+ implemented=True,
+ need_undef=False,
+ condition="_LIBCPP_HAS_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": False,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_variant": VersionHeader(
+ value="202106L",
+ implemented=False,
+ need_undef=False,
+ condition=None,
+ ),
},
{
- "__cpp_lib_missing_FTM_in_older_standard": {
- "value": "2020L",
- "implemented": False,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_missing_FTM_in_older_standard" : VersionHeader(
+ value = "2020L",
+ implemented = False,
+ need_undef = False,
+ 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": "_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
- },
+ "__cpp_lib_barrier": VersionHeader(
+ value="299900L",
+ implemented=True,
+ need_undef=True,
+ condition="_LIBCPP_HAS_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": False,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_variant": VersionHeader(
+ value="202306L",
+ implemented=False,
+ need_undef=False,
+ condition=None,
+ ),
},
{
- "__cpp_lib_missing_FTM_in_older_standard": {
- "value": "2026L",
- "implemented": False,
- "need_undef": False,
- "condition": None,
- },
+ "__cpp_lib_missing_FTM_in_older_standard" : VersionHeader(
+ value = "2026L",
+ implemented = False,
+ need_undef = False,
+ condition = None,
+ ),
},
],
}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 58ecd79cf7469c7..e9e531733abb506 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.
+ NewType,
+ Optional,
+)
import functools
import json
@@ -1944,9 +1951,28 @@ def produce_docs():
f.write(doc_str)
+Std = NewType("Std", str) # Standard version number
+Ftm = NewType("Ftm", str) # The name of a feature test macro
+Value = NewType("Value", 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:
@@ -1983,7 +2009,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
@@ -1994,27 +2020,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}
@@ -2132,7 +2160,7 @@ def __init__(self, filename: str):
self.__data = json.load(f)
@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'
@@ -2151,63 +2179,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:
@@ -2223,11 +2232,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] == self.standard_ftms[ftm][std]
- entry["need_undef"] = last_entry is not None and last_entry["implemented"] and entry["implemented"]
- entry["condition"] = self.ftm_metadata[ftm]["libcxx_guard"]
+ implemented = self.implemented_ftms[ftm][std] == self.standard_ftms[ftm][std]
+ entry = VersionHeader(
+ value,
+ implemented,
+ last_entry is not None and last_entry.implemented and implemented,
+ self.ftm_metadata[ftm].libcxx_guard,
+ )
last_entry = entry
result[get_std_number(std)].append(dict({ftm: entry}))
More information about the libcxx-commits
mailing list