Skip to content

Conversation

@mordante
Copy link
Member

@mordante mordante commented Apr 6, 2025

At the moment the ftm macro for __cpp_lib_to_chars will have the following values:

standard_ftms: {
"c++17": "201611L",
"c++20": "201611L",
"c++23": "201611L",
"c++26": "201611L",
}

implemented_ftms: {
"c++17": None,
}

This is an issue with the test whether the FTM is implemented it does:
self.implemented_ftms[ftm][std] == self.standard_ftms[ftm][std]
This will fail in C++20 since implemented_ftms[ftm] does not have the key c++20. This adds a new helper function and removes the None entries when a FTM is not implemented.

@mordante mordante requested a review from a team as a code owner April 6, 2025 13:35
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Apr 6, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 6, 2025

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

Changes

At the moment the ftm macro for __cpp_lib_to_chars will have the following values:

standard_ftms: {
"c++17": "201611L",
"c++20": "201611L",
"c++23": "201611L",
"c++26": "201611L",
}

implemented_ftms: {
"c++17": None,
}

This is an issue with the test whether the FTM is implemented it does:
self.implemented_ftms[ftm][std] == self.standard_ftms[ftm][std]
This will fail in C++20 since implemented_ftms[ftm] does not have the key c++20. This adds a new helper function and removes the None entries when a FTM is not implemented.


Full diff: https://github.com/llvm/llvm-project/pull/134538.diff

3 Files Affected:

  • (modified) libcxx/test/libcxx/feature_test_macro/implemented_ftms.sh.py (+2-10)
  • (added) libcxx/test/libcxx/feature_test_macro/is_implemented.sh.py (+39)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (+17-2)
diff --git a/libcxx/test/libcxx/feature_test_macro/implemented_ftms.sh.py b/libcxx/test/libcxx/feature_test_macro/implemented_ftms.sh.py
index 92e14757ddd49..4f445d55c883c 100644
--- a/libcxx/test/libcxx/feature_test_macro/implemented_ftms.sh.py
+++ b/libcxx/test/libcxx/feature_test_macro/implemented_ftms.sh.py
@@ -38,11 +38,7 @@ def test_implementation(self):
                 "c++23": "201907L",
                 "c++26": "299900L",
             },
-            "__cpp_lib_format": {
-                "c++20": None,
-                "c++23": None,
-                "c++26": None,
-            },
+            "__cpp_lib_format": {},
             "__cpp_lib_parallel_algorithm": {
                 "c++17": "201603L",
                 "c++20": "201603L",
@@ -55,11 +51,7 @@ def test_implementation(self):
                 "c++23": "202102L",
                 "c++26": "202102L",
             },
-            "__cpp_lib_missing_FTM_in_older_standard": {
-                "c++17": None,
-                "c++20": None,
-                "c++26": None,
-            },
+            "__cpp_lib_missing_FTM_in_older_standard": {},
         }
 
         self.assertEqual(self.ftm.implemented_ftms, expected)
diff --git a/libcxx/test/libcxx/feature_test_macro/is_implemented.sh.py b/libcxx/test/libcxx/feature_test_macro/is_implemented.sh.py
new file mode 100644
index 0000000000000..0414722b89a76
--- /dev/null
+++ b/libcxx/test/libcxx/feature_test_macro/is_implemented.sh.py
@@ -0,0 +1,39 @@
+# ===----------------------------------------------------------------------===##
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+# ===----------------------------------------------------------------------===##
+
+# RUN: %{python} %s %{libcxx-dir}/utils %{libcxx-dir}/test/libcxx/feature_test_macro/test_data.json
+
+import sys
+import unittest
+
+UTILS = sys.argv[1]
+TEST_DATA = sys.argv[2]
+del sys.argv[1:3]
+
+sys.path.append(UTILS)
+from generate_feature_test_macro_components import FeatureTestMacros, Metadata
+
+
+class Test(unittest.TestCase):
+    def setUp(self):
+        self.ftm = FeatureTestMacros(TEST_DATA)
+        self.maxDiff = None  # This causes the diff to be printed when the test fails
+
+    def test_implementation(self):
+        # FTM not available in C++14.
+        self.assertEqual(self.ftm.is_implemented("__cpp_lib_any", "c++14"), False)
+        self.assertEqual(self.ftm.is_implemented("__cpp_lib_any", "c++17"), True)
+
+        self.assertEqual(self.ftm.is_implemented("__cpp_lib_format", "c++20"), False)
+
+        # FTM C++20 202106L, libc++ has 202102L
+        self.assertEqual(self.ftm.is_implemented("__cpp_lib_variant", "c++20"), False)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 53252d5e2d673..ecf31f5af7fb2 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -2012,7 +2012,8 @@ def get_ftms(
                         else:
                             break
 
-                entry[std] = last
+                if last:
+                    entry[std] = last
         result[feature["name"]] = entry
 
     return result
@@ -2208,6 +2209,20 @@ def implemented_ftms(self) -> Dict[Ftm, Dict[Std, Optional[Value]]]:
 
         return get_ftms(self.__data, self.std_dialects, True)
 
+    def is_implemented(self, ftm: Ftm, std: Std) -> bool:
+        """Has the FTM `ftm` been implemented in the dialect `std`?"""
+
+        # When a paper for C++20 has not been implemented in libc++, then there will be no
+        # FTM entry in implemented_ftms for C++23 and later.
+        #
+        # Typically standard_ftms is not used with invalid values in the code, but
+        # guard just in case.
+        if not std in self.implemented_ftms[ftm].keys() or not std in self.standard_ftms[ftm].keys():
+            return False
+
+        return self.implemented_ftms[ftm][std] == self.standard_ftms[ftm][std]
+
+
     @functools.cached_property
     def ftm_metadata(self) -> Dict[Ftm, Metadata]:
         """Returns the metadata of the FTMs defined in the Standard.
@@ -2241,7 +2256,7 @@ def version_header_implementation(self) -> Dict[Std, Dict[Ftm, VersionHeader]]:
                     continue
                 last_value = value
 
-                implemented = self.implemented_ftms[ftm][std] == self.standard_ftms[ftm][std]
+                implemented = self.is_implemented(ftm, std)
                 entry = VersionHeader(
                     value,
                     implemented,

@github-actions
Copy link

github-actions bot commented Apr 6, 2025

⚠️ Python code formatter, darker found issues in your code. ⚠️

You can test this locally with the following command:
darker --check --diff -r HEAD~1...HEAD libcxx/test/libcxx/feature_test_macro/is_implemented.sh.py libcxx/test/libcxx/feature_test_macro/implemented_ftms.sh.py libcxx/utils/generate_feature_test_macro_components.py
View the diff from darker here.
--- utils/generate_feature_test_macro_components.py	2025-04-08 17:41:00.000000 +0000
+++ utils/generate_feature_test_macro_components.py	2025-04-08 17:43:20.359813 +0000
@@ -2211,15 +2211,17 @@
         """Has the FTM `ftm` been implemented in the dialect `std`?"""
 
         # When a paper for C++20 has not been implemented in libc++, then there will be no
         # FTM entry in implemented_ftms for C++23 and later. Similarly, a paper like <format>
         # has no entry in standard_ftms for e.g. C++11.
-        if not std in self.implemented_ftms[ftm].keys() or not std in self.standard_ftms[ftm].keys():
+        if (
+            not std in self.implemented_ftms[ftm].keys()
+            or not std in self.standard_ftms[ftm].keys()
+        ):
             return False
 
         return self.implemented_ftms[ftm][std] == self.standard_ftms[ftm][std]
-
 
     @functools.cached_property
     def ftm_metadata(self) -> Dict[Ftm, Metadata]:
         """Returns the metadata of the FTMs defined in the Standard.
 

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with comment rewording.

Base automatically changed from users/mordante/ftm/refactor_tests to main April 8, 2025 17:38
mordante and others added 2 commits April 8, 2025 19:41
At the moment the ftm macro for __cpp_lib_to_chars will have the
following values:

standard_ftms: {
    "c++17": "201611L",
    "c++20": "201611L",
    "c++23": "201611L",
    "c++26": "201611L",
}

implemented_ftms: {
    "c++17": None,
}

This is an issue with the test whether the FTM is implemented it does:
  self.implemented_ftms[ftm][std] == self.standard_ftms[ftm][std]
This will fail in C++20 since implemented_ftms[ftm] does not have the
key c++20. This adds a new helper function and removes the None entries
when a FTM is not implemented.
@mordante mordante force-pushed the users/mordante/ftm/is_implemented branch from 14c5af3 to fa5cbcf Compare April 8, 2025 17:41
@mordante mordante merged commit df579ce into main Apr 11, 2025
76 of 84 checks passed
@mordante mordante deleted the users/mordante/ftm/is_implemented branch April 11, 2025 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants