[libcxx-commits] [libcxx] [libc++] Improves type-safety in generator script. (PR #101880)
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Aug 4 06:48:55 PDT 2024
https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/101880
>From aea5d6f9c5a18bfa2a53744c54aa02e837f7d10b Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Sun, 4 Aug 2024 13:06:49 +0200
Subject: [PATCH 1/2] [libc++] Improves type-safety in generator script.
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.
---
.../feature_test_macro/ftm_metadata.sh.py | 45 +++----
.../version_header_implementation.sh.py | 122 +++++++++---------
.../generate_feature_test_macro_components.py | 110 +++++++++-------
3 files changed, 140 insertions(+), 137 deletions(-)
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}))
>From 171b6710b5f41f8f546913196964305a437e27f7 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Sun, 4 Aug 2024 15:48:43 +0200
Subject: [PATCH 2/2] Fixes building with older Python versions.
---
libcxx/utils/generate_feature_test_macro_components.py | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 620c764982e29..dbd0a6408a991 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -8,8 +8,8 @@
Any,
Dict,
List, # Needed for python 3.8 compatibility.
+ NewType,
Optional,
- TypeAlias,
)
import functools
import json
@@ -1924,10 +1924,9 @@ 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
-
+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
@dataclass
class Metadata:
More information about the libcxx-commits
mailing list