Skip to content

[libc++] Implements the new FTM header test generator. #134542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 18, 2025

Conversation

mordante
Copy link
Member

@mordante mordante commented Apr 6, 2025

This generator has almost identical output to the existing script. Notable differences are

  • conditionally include headers that are not implemented yet
  • removes the synopsis
  • uses 2 spaces indent in # if

There are a few more test macros added that triggered bugs in existing FTM.

@mordante mordante requested a review from a team as a code owner April 6, 2025 15:04
@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

This generator has almost identical output to the existing script. Notable differences are

  • conditionally include not yet implemented headers
  • removes the synopsis
  • uses 2 spaces indent in # if

There are a few more test macros added that triggered bugs in existing FTM.


Patch is 43.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/134542.diff

10 Files Affected:

  • (modified) libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py (+31-5)
  • (added) libcxx/test/libcxx/feature_test_macro/generate_header_test.sh.py (+643)
  • (modified) libcxx/test/libcxx/feature_test_macro/implemented_ftms.sh.py (+8-1)
  • (added) libcxx/test/libcxx/feature_test_macro/implemented_standard_library_headers.sh.py (+32)
  • (modified) libcxx/test/libcxx/feature_test_macro/standard_ftms.sh.py (+13-1)
  • (added) libcxx/test/libcxx/feature_test_macro/standard_library_headers.sh.py (+33)
  • (modified) libcxx/test/libcxx/feature_test_macro/test_data.json (+27-1)
  • (modified) libcxx/test/libcxx/feature_test_macro/version_header.sh.py (+5-3)
  • (modified) libcxx/test/libcxx/feature_test_macro/version_header_implementation.sh.py (+19-3)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (+281-3)
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 52696d8bc3605..7cf35b2a21d93 100644
--- a/libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py
+++ b/libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py
@@ -27,26 +27,52 @@ def setUp(self):
     def test_implementation(self):
         expected = {
             "__cpp_lib_any": Metadata(
-                headers=["any"], test_suite_guard=None, libcxx_guard=None
+                headers=["any"],
+                available_since="c++17",
+                test_suite_guard=None,
+                libcxx_guard=None,
             ),
             "__cpp_lib_barrier": Metadata(
                 headers=["barrier"],
+                available_since="c++20",
                 test_suite_guard="!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)",
                 libcxx_guard="_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC",
             ),
+            "__cpp_lib_clamp": Metadata(
+                headers=["algorithm"],
+                available_since="c++17",
+                test_suite_guard=None,
+                libcxx_guard=None,
+            ),
             "__cpp_lib_format": Metadata(
-                headers=["format"], test_suite_guard=None, libcxx_guard=None
+                headers=["format"],
+                available_since="c++20",
+                test_suite_guard=None,
+                libcxx_guard=None,
             ),
             "__cpp_lib_parallel_algorithm": Metadata(
                 headers=["algorithm", "numeric"],
+                available_since="c++17",
+                test_suite_guard=None,
+                libcxx_guard=None,
+            ),
+            "__cpp_lib_to_chars": Metadata(
+                headers=["charconv"],
+                available_since="c++17",
                 test_suite_guard=None,
                 libcxx_guard=None,
             ),
             "__cpp_lib_variant": Metadata(
-                headers=["variant"], test_suite_guard=None, libcxx_guard=None
+                headers=["variant"],
+                available_since="c++17",
+                test_suite_guard=None,
+                libcxx_guard=None,
             ),
-            "__cpp_lib_missing_FTM_in_older_standard": Metadata(
-                headers=[], test_suite_guard=None, libcxx_guard=None
+            "__cpp_lib_zz_missing_FTM_in_older_standard": Metadata(
+                headers=[],
+                available_since="c++17",
+                test_suite_guard=None,
+                libcxx_guard=None,
             ),
         }
         self.assertEqual(self.ftm.ftm_metadata, expected)
diff --git a/libcxx/test/libcxx/feature_test_macro/generate_header_test.sh.py b/libcxx/test/libcxx/feature_test_macro/generate_header_test.sh.py
new file mode 100644
index 0000000000000..cca5bae8e7e70
--- /dev/null
+++ b/libcxx/test/libcxx/feature_test_macro/generate_header_test.sh.py
@@ -0,0 +1,643 @@
+# ===----------------------------------------------------------------------===##
+#
+# 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 %t/tests
+
+import os
+import sys
+import unittest
+
+UTILS = sys.argv[1]
+TEST_DATA = sys.argv[2]
+OUTPUT_PATH = sys.argv[3]
+del sys.argv[1:4]
+
+sys.path.append(UTILS)
+from generate_feature_test_macro_components import FeatureTestMacros
+
+
+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
+
+        self.expected = dict(
+            {
+                "algorithm": """\
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING: This test was generated by
+// generate_feature_test_macro_components.py
+// and should not be edited manually.
+
+// <algorithm>
+
+// Test the feature test macros defined by <algorithm>
+
+// clang-format off
+
+#include <algorithm>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 17
+
+#  ifdef __cpp_lib_clamp
+#    error "__cpp_lib_clamp should not be defined before c++17"
+#  endif
+
+#  ifdef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should not be defined before c++17"
+#  endif
+
+#elif TEST_STD_VER == 17
+
+#  ifndef __cpp_lib_clamp
+#    error "__cpp_lib_clamp should be defined in c++17"
+#  endif
+#  if __cpp_lib_clamp != 201603L
+#    error "__cpp_lib_clamp should have the value 201603L in c++17"
+#  endif
+
+#  ifndef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should be defined in c++17"
+#  endif
+#  if __cpp_lib_parallel_algorithm != 201603L
+#    error "__cpp_lib_parallel_algorithm should have the value 201603L in c++17"
+#  endif
+
+#elif TEST_STD_VER == 20
+
+#  ifndef __cpp_lib_clamp
+#    error "__cpp_lib_clamp should be defined in c++20"
+#  endif
+#  if __cpp_lib_clamp != 201603L
+#    error "__cpp_lib_clamp should have the value 201603L in c++20"
+#  endif
+
+#  ifndef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should be defined in c++20"
+#  endif
+#  if __cpp_lib_parallel_algorithm != 201603L
+#    error "__cpp_lib_parallel_algorithm should have the value 201603L in c++20"
+#  endif
+
+#elif TEST_STD_VER == 23
+
+#  ifndef __cpp_lib_clamp
+#    error "__cpp_lib_clamp should be defined in c++23"
+#  endif
+#  if __cpp_lib_clamp != 201603L
+#    error "__cpp_lib_clamp should have the value 201603L in c++23"
+#  endif
+
+#  ifndef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should be defined in c++23"
+#  endif
+#  if __cpp_lib_parallel_algorithm != 201603L
+#    error "__cpp_lib_parallel_algorithm should have the value 201603L in c++23"
+#  endif
+
+#elif TEST_STD_VER > 23
+
+#  ifndef __cpp_lib_clamp
+#    error "__cpp_lib_clamp should be defined in c++26"
+#  endif
+#  if __cpp_lib_clamp != 201603L
+#    error "__cpp_lib_clamp should have the value 201603L in c++26"
+#  endif
+
+#  ifndef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should be defined in c++26"
+#  endif
+#  if __cpp_lib_parallel_algorithm != 201603L
+#    error "__cpp_lib_parallel_algorithm should have the value 201603L in c++26"
+#  endif
+
+#endif // TEST_STD_VER > 23
+
+// clang-format on
+
+""",
+                "any": """\
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING: This test was generated by
+// generate_feature_test_macro_components.py
+// and should not be edited manually.
+
+// <any>
+
+// Test the feature test macros defined by <any>
+
+// clang-format off
+
+#include <any>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 17
+
+#  ifdef __cpp_lib_any
+#    error "__cpp_lib_any should not be defined before c++17"
+#  endif
+
+#elif TEST_STD_VER == 17
+
+#  ifndef __cpp_lib_any
+#    error "__cpp_lib_any should be defined in c++17"
+#  endif
+#  if __cpp_lib_any != 201606L
+#    error "__cpp_lib_any should have the value 201606L in c++17"
+#  endif
+
+#elif TEST_STD_VER == 20
+
+#  ifndef __cpp_lib_any
+#    error "__cpp_lib_any should be defined in c++20"
+#  endif
+#  if __cpp_lib_any != 201606L
+#    error "__cpp_lib_any should have the value 201606L in c++20"
+#  endif
+
+#elif TEST_STD_VER == 23
+
+#  ifndef __cpp_lib_any
+#    error "__cpp_lib_any should be defined in c++23"
+#  endif
+#  if __cpp_lib_any != 201606L
+#    error "__cpp_lib_any should have the value 201606L in c++23"
+#  endif
+
+#elif TEST_STD_VER > 23
+
+#  ifndef __cpp_lib_any
+#    error "__cpp_lib_any should be defined in c++26"
+#  endif
+#  if __cpp_lib_any != 201606L
+#    error "__cpp_lib_any should have the value 201606L in c++26"
+#  endif
+
+#endif // TEST_STD_VER > 23
+
+// clang-format on
+
+""",
+                "barrier": """\
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING: This test was generated by
+// generate_feature_test_macro_components.py
+// and should not be edited manually.
+
+// UNSUPPORTED: no-threads
+
+// <barrier>
+
+// Test the feature test macros defined by <barrier>
+
+// clang-format off
+
+#include <barrier>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 17
+
+#  ifdef __cpp_lib_barrier
+#    error "__cpp_lib_barrier should not be defined before c++20"
+#  endif
+
+#elif TEST_STD_VER == 17
+
+#  ifdef __cpp_lib_barrier
+#    error "__cpp_lib_barrier should not be defined before c++20"
+#  endif
+
+#elif TEST_STD_VER == 20
+
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
+#    ifndef __cpp_lib_barrier
+#      error "__cpp_lib_barrier should be defined in c++20"
+#    endif
+#    if __cpp_lib_barrier != 201907L
+#      error "__cpp_lib_barrier should have the value 201907L in c++20"
+#    endif
+#  else
+#    ifdef __cpp_lib_barrier
+#      error "__cpp_lib_barrier should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
+#    endif
+#  endif
+
+#elif TEST_STD_VER == 23
+
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
+#    ifndef __cpp_lib_barrier
+#      error "__cpp_lib_barrier should be defined in c++23"
+#    endif
+#    if __cpp_lib_barrier != 201907L
+#      error "__cpp_lib_barrier should have the value 201907L in c++23"
+#    endif
+#  else
+#    ifdef __cpp_lib_barrier
+#      error "__cpp_lib_barrier should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
+#    endif
+#  endif
+
+#elif TEST_STD_VER > 23
+
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
+#    ifndef __cpp_lib_barrier
+#      error "__cpp_lib_barrier should be defined in c++26"
+#    endif
+#    if __cpp_lib_barrier != 299900L
+#      error "__cpp_lib_barrier should have the value 299900L in c++26"
+#    endif
+#  else
+#    ifdef __cpp_lib_barrier
+#      error "__cpp_lib_barrier should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
+#    endif
+#  endif
+
+#endif // TEST_STD_VER > 23
+
+// clang-format on
+
+""",
+                "charconv": """\
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING: This test was generated by
+// generate_feature_test_macro_components.py
+// and should not be edited manually.
+
+// <charconv>
+
+// Test the feature test macros defined by <charconv>
+
+// clang-format off
+
+#if __has_include(<charconv>)
+#  include <charconv>
+#endif
+#include "test_macros.h"
+
+#if TEST_STD_VER < 17
+
+#  ifdef __cpp_lib_to_chars
+#    error "__cpp_lib_to_chars should not be defined before c++17"
+#  endif
+
+#elif TEST_STD_VER == 17
+
+#  if !defined(_LIBCPP_VERSION)
+#    ifndef __cpp_lib_to_chars
+#      error "__cpp_lib_to_chars should be defined in c++17"
+#    endif
+#    if __cpp_lib_to_chars != 201611L
+#      error "__cpp_lib_to_chars should have the value 201611L in c++17"
+#    endif
+#  else
+#    ifdef __cpp_lib_to_chars
+#      error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
+#    endif
+#  endif
+
+#elif TEST_STD_VER == 20
+
+#  if !defined(_LIBCPP_VERSION)
+#    ifndef __cpp_lib_to_chars
+#      error "__cpp_lib_to_chars should be defined in c++20"
+#    endif
+#    if __cpp_lib_to_chars != 201611L
+#      error "__cpp_lib_to_chars should have the value 201611L in c++20"
+#    endif
+#  else
+#    ifdef __cpp_lib_to_chars
+#      error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
+#    endif
+#  endif
+
+#elif TEST_STD_VER == 23
+
+#  if !defined(_LIBCPP_VERSION)
+#    ifndef __cpp_lib_to_chars
+#      error "__cpp_lib_to_chars should be defined in c++23"
+#    endif
+#    if __cpp_lib_to_chars != 201611L
+#      error "__cpp_lib_to_chars should have the value 201611L in c++23"
+#    endif
+#  else
+#    ifdef __cpp_lib_to_chars
+#      error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
+#    endif
+#  endif
+
+#elif TEST_STD_VER > 23
+
+#  if !defined(_LIBCPP_VERSION)
+#    ifndef __cpp_lib_to_chars
+#      error "__cpp_lib_to_chars should be defined in c++26"
+#    endif
+#    if __cpp_lib_to_chars != 201611L
+#      error "__cpp_lib_to_chars should have the value 201611L in c++26"
+#    endif
+#  else
+#    ifdef __cpp_lib_to_chars
+#      error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
+#    endif
+#  endif
+
+#endif // TEST_STD_VER > 23
+
+// clang-format on
+
+""",
+                "format": """\
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING: This test was generated by
+// generate_feature_test_macro_components.py
+// and should not be edited manually.
+
+// <format>
+
+// Test the feature test macros defined by <format>
+
+// clang-format off
+
+#include <format>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 17
+
+#  ifdef __cpp_lib_format
+#    error "__cpp_lib_format should not be defined before c++20"
+#  endif
+
+#elif TEST_STD_VER == 17
+
+#  ifdef __cpp_lib_format
+#    error "__cpp_lib_format should not be defined before c++20"
+#  endif
+
+#elif TEST_STD_VER == 20
+
+#  if !defined(_LIBCPP_VERSION)
+#    ifndef __cpp_lib_format
+#      error "__cpp_lib_format should be defined in c++20"
+#    endif
+#    if __cpp_lib_format != 202110L
+#      error "__cpp_lib_format should have the value 202110L in c++20"
+#    endif
+#  else
+#    ifdef __cpp_lib_format
+#      error "__cpp_lib_format should not be defined because it is unimplemented in libc++!"
+#    endif
+#  endif
+
+#elif TEST_STD_VER == 23
+
+#  if !defined(_LIBCPP_VERSION)
+#    ifndef __cpp_lib_format
+#      error "__cpp_lib_format should be defined in c++23"
+#    endif
+#    if __cpp_lib_format != 202207L
+#      error "__cpp_lib_format should have the value 202207L in c++23"
+#    endif
+#  else
+#    ifdef __cpp_lib_format
+#      error "__cpp_lib_format should not be defined because it is unimplemented in libc++!"
+#    endif
+#  endif
+
+#elif TEST_STD_VER > 23
+
+#  if !defined(_LIBCPP_VERSION)
+#    ifndef __cpp_lib_format
+#      error "__cpp_lib_format should be defined in c++26"
+#    endif
+#    if __cpp_lib_format != 202311L
+#      error "__cpp_lib_format should have the value 202311L in c++26"
+#    endif
+#  else
+#    ifdef __cpp_lib_format
+#      error "__cpp_lib_format should not be defined because it is unimplemented in libc++!"
+#    endif
+#  endif
+
+#endif // TEST_STD_VER > 23
+
+// clang-format on
+
+""",
+                "numeric": """\
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING: This test was generated by
+// generate_feature_test_macro_components.py
+// and should not be edited manually.
+
+// <numeric>
+
+// Test the feature test macros defined by <numeric>
+
+// clang-format off
+
+#include <numeric>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 17
+
+#  ifdef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should not be defined before c++17"
+#  endif
+
+#elif TEST_STD_VER == 17
+
+#  ifndef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should be defined in c++17"
+#  endif
+#  if __cpp_lib_parallel_algorithm != 201603L
+#    error "__cpp_lib_parallel_algorithm should have the value 201603L in c++17"
+#  endif
+
+#elif TEST_STD_VER == 20
+
+#  ifndef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should be defined in c++20"
+#  endif
+#  if __cpp_lib_parallel_algorithm != 201603L
+#    error "__cpp_lib_parallel_algorithm should have the value 201603L in c++20"
+#  endif
+
+#elif TEST_STD_VER == 23
+
+#  ifndef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should be defined in c++23"
+#  endif
+#  if __cpp_lib_parallel_algorithm != 201603L
+#    error "__cpp_lib_parallel_algorithm should have the value 201603L in c++23"
+#  endif
+
+#elif TEST_STD_VER > 23
+
+#  ifndef __cpp_lib_parallel_algorithm
+#    error "__cpp_lib_parallel_algorithm should be defined in c++26"
+#  endif
+#  if __cpp_lib_parallel_algorithm != 201603L
+#    error "__cpp_lib_parallel_algorithm should have the value 201603L in c++26"
+#  endif
+
+#endif // TEST_STD_VER > 23
+
+// clang-format on
+
+""",
+                "variant": """\
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING: This test was generated by
+// generate_feature_test_macro_components.py
+// and should not be edited manually.
+
+// <variant>
+
+// Test the feature test macros defined by <variant>
+
+// clang-format off
+
+#include <variant>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 17
+
+#  ifdef __cpp_lib_variant
+#    error "__cpp_lib_variant should not be defined before c++17"
+#  endif
+
+#elif TEST_STD_VER == 17
+
+#  ifndef __cpp_lib_variant
+#    error "__cpp_lib_variant should be defined in c++17"
+#  endif
+#  if __cpp_lib_variant != 202102L
+#    error "__cpp_lib_variant should have the value 202102L in c++17"
+#  endif
+
+#elif TEST_STD_VER == 20
+
+#  if !defined(_LIBCPP_VERSION)
+#    ifndef __cpp_lib_variant
+#      error "__cpp_lib_variant should be defined in c++20"
+#    endif
+#    if __cpp_lib_variant != 202106L
+#      error "__cpp_lib_variant should have the value 202106L in c++20"
+#    endif
+#  else
+#    ifdef __cpp_lib_variant
+#      error "__cpp_lib_variant should not be defined because it is unimplemented in libc++!"
+#    endif
+#  endif
+
+#elif TEST_STD_VER == 23
+
+#  if !defined(_LIBCPP_VERSION)
+#    ifndef __cpp_lib_variant
+#      error "__cpp_lib_variant should be defined in c++23"
+#    endif
+#    if __cpp_lib_variant != 202106L
+#      error "__cpp_lib_variant should have the value 202106L in c++23"
+#    endif
+#  else
+#    ifdef __cpp_lib_variant
+#      error "__cpp_lib_va...
[truncated]

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/generate_header_test.sh.py libcxx/test/libcxx/feature_test_macro/standard_library_headers.sh.py libcxx/test/libcxx/feature_test_macro/ftm_metadata.sh.py libcxx/test/libcxx/feature_test_macro/implemented_ftms.sh.py libcxx/test/libcxx/feature_test_macro/invalid.sh.py libcxx/test/libcxx/feature_test_macro/is_implemented.sh.py libcxx/test/libcxx/feature_test_macro/standard_ftms.sh.py libcxx/test/libcxx/feature_test_macro/std_dialects.sh.py libcxx/test/libcxx/feature_test_macro/version_header.sh.py libcxx/test/libcxx/feature_test_macro/version_header_implementation.sh.py libcxx/utils/generate_feature_test_macro_components.py
View the diff from darker here.
--- utils/generate_feature_test_macro_components.py	2025-05-18 12:09:15.000000 +0000
+++ utils/generate_feature_test_macro_components.py	2025-05-18 12:12:45.441300 +0000
@@ -2083,10 +2083,11 @@
             )
         )
 
     return "\n\n".join(result)
 
+
 #
 # The templates used to create a FTM test file
 #
 
 
@@ -2402,21 +2403,20 @@
                 if not std in values.keys():
                     result[get_std_number(std)].append({ftm: None})
                     continue
 
                 result[get_std_number(std)].append(
-                        {
-                            ftm: FtmHeaderTest(
-                                values[std],
-                                self.is_implemented(ftm, std),
-                                self.ftm_metadata[ftm].test_suite_guard,
-                            )
-                        }
+                    {
+                        ftm: FtmHeaderTest(
+                            values[std],
+                            self.is_implemented(ftm, std),
+                            self.ftm_metadata[ftm].test_suite_guard,
+                        )
+                    }
                 )
 
         return result
-
 
     def generate_ftm_test(self, std: Std, ftm: Ftm, value: FtmHeaderTest) -> str:
         """Adds a single `ftm` test for C++ `std` based on the status information in `value`.
 
         When std == None this test is generating the TEST_STD_VER < MIN. Where
@@ -2473,13 +2473,11 @@
             return ftm_unavailable_in_dialect.format(
                 ftm=ftm, dialect=self.ftm_metadata[ftm].available_since
             )
 
         if not value.implemented:
-            return ftm_not_implemented.format(
-                ftm=ftm, value=value.value, dialect=std
-            )
+            return ftm_not_implemented.format(ftm=ftm, value=value.value, dialect=std)
 
         if self.ftm_metadata[ftm].test_suite_guard:
             return ftm_conditionally_implemented.format(
                 ftm=ftm,
                 value=value.value,
@@ -2497,11 +2495,11 @@
             self.generate_ftm_test(std, ftm, value)
             for element in data
             for ftm, value in element.items()
         )
 
-    def generate_lit_markup(self, header:str) -> str:
+    def generate_lit_markup(self, header: str) -> str:
         if not header in lit_markup.keys():
             return ""
 
         return "\n".join(f"// {markup}" for markup in lit_markup[header]) + "\n\n"
 
@@ -2509,32 +2507,32 @@
         """Returns the body for the FTM test of a `header`."""
 
         # FTM block before the first Standard that introduced them.
         # This test the macros are not available before this version.
         data = ftm_header_test_file_dialect_block.format(
-                pp_if="if",
-                operator="<",
-                dialect=get_std_number(self.std_dialects[0]),
-                tests=self.generate_header_test_dialect(
-                    None, next(iter(self.header_ftm_data(header).values()))
-                ),
-            )
+            pp_if="if",
+            operator="<",
+            dialect=get_std_number(self.std_dialects[0]),
+            tests=self.generate_header_test_dialect(
+                None, next(iter(self.header_ftm_data(header).values()))
+            ),
+        )
 
         # FTM for all Standards that have FTM defined.
         # Note in libc++ the TEST_STD_VER contains 99 for the Standard
         # in development, therefore the last entry uses a different #elif.
         data += "".join(
-                ftm_header_test_file_dialect_block.format(
-                    pp_if="elif",
-                    operator="==" if std != get_std_number(self.std_dialects[-1]) else ">",
-                    dialect=std
-                    if std != get_std_number(self.std_dialects[-1])
-                    else get_std_number(self.std_dialects[-2]),
-                    tests=self.generate_header_test_dialect(f"c++{std}", values),
-                )
-                for std, values in self.header_ftm_data(header).items()
+            ftm_header_test_file_dialect_block.format(
+                pp_if="elif",
+                operator="==" if std != get_std_number(self.std_dialects[-1]) else ">",
+                dialect=std
+                if std != get_std_number(self.std_dialects[-1])
+                else get_std_number(self.std_dialects[-2]),
+                tests=self.generate_header_test_dialect(f"c++{std}", values),
             )
+            for std, values in self.header_ftm_data(header).items()
+        )
 
         # The final #endif for the last #elif block.
         data += f"\n#endif // TEST_STD_VER > {get_std_number(self.std_dialects[-2])}"
 
         # Generate the test for the requested header.
@@ -2545,11 +2543,11 @@
             include=(
                 ftm_header_test_file_include_conditional.format(header=header)
                 if header in self.__unavailable_headers
                 else ftm_header_test_file_include_unconditional.format(header=header)
             ),
-            data=data
+            data=data,
         )
 
     def generate_header_test_directory(self, path: os.path) -> None:
         """Generates all FTM tests in the directory `path`."""
 
@@ -2573,11 +2571,12 @@
     # Example how to use the new generator to generate the output.
     if False:
         ftm = FeatureTestMacros(
             os.path.join(
                 source_root, "test", "libcxx", "feature_test_macro", "test_data.json"
-            ), headers_not_available
+            ),
+            headers_not_available,
         )
         version_header_path = os.path.join(include_path, "version")
         with open(version_header_path, "w", newline="\n") as f:
             f.write(ftm.version_header)
 

@mordante mordante force-pushed the users/mordante/ftm/is_implemented branch from 14c5af3 to fa5cbcf Compare April 8, 2025 17:41
Base automatically changed from users/mordante/ftm/is_implemented to main April 11, 2025 18:27
@mordante mordante force-pushed the users/mordante/ftm/generate_header_tests branch from 00cf2e7 to da82709 Compare April 12, 2025 13:04
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 some comments.

@@ -2296,24 +2374,205 @@ def version_header(self) -> str:
)
)

def header_ftm_data(self, header: str) -> Dict[Std, List[Dict[Ftm, FtmHeaderTest]]]:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
def header_ftm_data(self, header: str) -> Dict[Std, List[Dict[Ftm, FtmHeaderTest]]]:
def test_data(self, header: str) -> Dict[Std, List[Dict[Ftm, FtmHeaderTest]]]:

Then you call this like self.test_data("cstdlib"), which I guess is reasonably readable?

This generator has almost identical output to the existing script.
Notable differences are
- conditionally include not yet implemented headers
- removes the synopsis
- uses 2 spaces indent in `# if`

There are a few more test macros added that triggered bugs in existing
FTM.
@mordante mordante force-pushed the users/mordante/ftm/generate_header_tests branch from 446fd9c to d2f630d Compare May 18, 2025 12:09
@mordante mordante merged commit b12d68e into main May 18, 2025
114 of 134 checks passed
@mordante mordante deleted the users/mordante/ftm/generate_header_tests branch May 18, 2025 16:21
ajaden-codes pushed a commit to Jaddyen/llvm-project that referenced this pull request Jun 6, 2025
This generator has almost identical output to the existing script.
Notable differences are
- conditionally include headers that are not implemented yet
- removes the synopsis
- uses 2 spaces indent in `# if`

There are a few more test macros added that triggered bugs in existing
FTM.
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.

3 participants