[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