[libcxx] [llvm] [RFC][libc++] Reworks clang-tidy selection. (PR #81362)

Mark de Wever via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 3 04:13:26 PST 2024


https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/81362

>From 10a15df28061f1898c6beaa3e4e38f2fcbc52859 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Sat, 10 Feb 2024 17:05:37 +0100
Subject: [PATCH 1/2] [RFC][libc++] Reworks clang-tidy selection.

The current selection is done in the test scipts which gives the user
no control where to find clang-tidy. The version selection itself is
hard-coded and not based on the version of clang used.

This moves the selection to configuration time and tries to find a better
match.
- Mixing the version of clang-tidy and the clang libraries causes ODR
  violations. This results in practice in crashes or incorrect results.
- Mixing the version of clang-tidy and the clang binaray sometimes causes
  issues with supported diagnotic flags. For example, flags tested against
  clang 17 may not be available in clang-tidy 16.

Currently clang-tidy 18.1 can be used, it tests against the clang
libraries version 18. This is a caused by the new LLVM version numbering
scheme.

The new selection tries to match the clang version or the version of the
HEAD and the last 3 releases. (During the release period libc++ supports 4
versions instead of the typical 3 versions.)

Note the LLVM version changes should reviewed seperately.
---
 cmake/Modules/LLVMVersion.cmake               | 15 ++++
 libcxx/CMakeLists.txt                         |  4 +
 libcxx/test/configs/cmake-bridge.cfg.in       |  1 +
 .../tools/clang_tidy_checks/CMakeLists.txt    | 78 ++++++++++++++++++-
 libcxx/utils/ci/run-buildbot                  |  9 +++
 libcxx/utils/libcxx/test/config.py            |  7 ++
 libcxx/utils/libcxx/test/features.py          | 30 +------
 llvm/CMakeLists.txt                           | 13 +---
 runtimes/CMakeLists.txt                       |  2 +
 9 files changed, 117 insertions(+), 42 deletions(-)
 create mode 100644 cmake/Modules/LLVMVersion.cmake

diff --git a/cmake/Modules/LLVMVersion.cmake b/cmake/Modules/LLVMVersion.cmake
new file mode 100644
index 00000000000000..5e28283fbc1c60
--- /dev/null
+++ b/cmake/Modules/LLVMVersion.cmake
@@ -0,0 +1,15 @@
+# The LLVM Version number information
+
+if(NOT DEFINED LLVM_VERSION_MAJOR)
+  set(LLVM_VERSION_MAJOR 19)
+endif()
+if(NOT DEFINED LLVM_VERSION_MINOR)
+  set(LLVM_VERSION_MINOR 0)
+endif()
+if(NOT DEFINED LLVM_VERSION_PATCH)
+  set(LLVM_VERSION_PATCH 0)
+endif()
+if(NOT DEFINED LLVM_VERSION_SUFFIX)
+  set(LLVM_VERSION_SUFFIX git)
+endif()
+
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index d392e95077ac57..fbe426a253f182 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -124,6 +124,10 @@ option(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS
    the shared library they shipped should turn this on and see `include/__availability`
    for more details." OFF)
 option(LIBCXX_ENABLE_CLANG_TIDY "Whether to compile and run clang-tidy checks" OFF)
+set(LIBCXX_CLANG_TIDY_EXECUTABLE "" CACHE FILEPATH
+  "The clang-tidy executable to use to run the clang-tidy checks.
+   When the variable is not set cmake will search for clang-tidy.
+   This is only used when LIBCXX_ENABLE_CLANG_TIDY is ON.")
 
 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
   set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-gcc.cfg.in")
diff --git a/libcxx/test/configs/cmake-bridge.cfg.in b/libcxx/test/configs/cmake-bridge.cfg.in
index 84b3270a8940ac..1f294af48818a3 100644
--- a/libcxx/test/configs/cmake-bridge.cfg.in
+++ b/libcxx/test/configs/cmake-bridge.cfg.in
@@ -25,6 +25,7 @@ config.test_exec_root = os.path.join('@CMAKE_BINARY_DIR@', 'test')
 # Add substitutions for bootstrapping the test suite configuration
 import shlex
 config.substitutions.append(('%{cxx}', shlex.quote('@CMAKE_CXX_COMPILER@')))
+config.substitutions.append(('%{clang-tidy}', shlex.quote('@LIBCXX_CLANG_TIDY@')))
 config.substitutions.append(('%{libcxx-dir}', '@LIBCXX_SOURCE_DIR@'))
 config.substitutions.append(('%{include-dir}', '@LIBCXX_GENERATED_INCLUDE_DIR@'))
 config.substitutions.append(('%{target-include-dir}', '@LIBCXX_GENERATED_INCLUDE_TARGET_DIR@'))
diff --git a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
index 978e7095216522..1b195f72319eda 100644
--- a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
+++ b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
@@ -5,11 +5,82 @@
 set(LLVM_DIR_SAVE ${LLVM_DIR})
 set(Clang_DIR_SAVE ${Clang_DIR})
 
-find_package(Clang 18)
-if (NOT Clang_FOUND)
-  find_package(Clang 17)
+# libc++ only supports the latest two released versions of clang-tidy. During
+# the release period there the new unreleased version is also supported. To keep
+# this code simple, always accept the last 3 versions.
+set(HEAD ${LLVM_VERSION_MAJOR})
+math(EXPR MINUS_1 "${HEAD} - 1")
+math(EXPR MINUS_2 "${MINUS_1} - 1")
+math(EXPR MINUS_3 "${MINUS_2} - 1")
+
+if("${LIBCXX_CLANG_TIDY_EXECUTABLE}" STREQUAL "")
+  set(NAMES "clang-tidy-${HEAD}"
+            "clang-tidy-${MINUS_1}"
+            "clang-tidy-${MINUS_2}"
+            "clang-tidy-${MINUS_3}"
+            "clang-tidy")
+  if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+    string(REGEX MATCH
+           "[0-9]+"
+           LIBCXX_CLANG_MAJOR
+           "${CMAKE_CXX_COMPILER_VERSION}")
+    set(NAMES "clang-tidy-${LIBCXX_CLANG_MAJOR}"
+              "clang-tidy")
+  endif()
+  find_program(LIBCXX_CLANG_TIDY NAMES ${NAMES})
+else()
+  set(LIBCXX_CLANG_TIDY "${LIBCXX_CLANG_TIDY_EXECUTABLE}" CACHE INTERNAL "")
+endif()
+
+if("${LIBCXX_CLANG_TIDY}" STREQUAL "")
+  set(LIBCXX_CLANG_TIDY "" CACHE INTERNAL "")
+  message(STATUS "Could not find a clang-tidy executable;
+                  custom libc++ clang-tidy checks will not be available.")
+  return()
+endif()
+
+execute_process(COMMAND
+            "${LIBCXX_CLANG_TIDY}" "--version"
+            OUTPUT_VARIABLE CLANG_TIDY_VERSION_OUTPUT
+            COMMAND_ERROR_IS_FATAL ANY)
+string(REGEX MATCH
+       "[0-9]+\.[0-9]+\.[0-9]+"
+       LIBCXX_CLANG_TIDY_VERSION
+       "${CLANG_TIDY_VERSION_OUTPUT}")
+
+if("${LIBCXX_CLANG_TIDY_VERSION}" VERSION_LESS "${MINUS_3}")
+  set(LIBCXX_CLANG_TIDY "" CACHE INTERNAL "")
+  message(STATUS "The clang-tidy version found ${LIBCXX_CLANG_TIDY_VERSION} is
+                  too old, version ${MINUS_3}.0.0 is required;
+                  custom libc++ clang-tidy checks will not be available.")
+  return()
 endif()
 
+# For modules clang-tidy 17 or newer is required. This is due to the state of
+# implementation in clang/clang-tidy. This additional restriction should be
+# temporary.
+# TODO(LLVM-19) Remove this check
+if("${LIBCXX_CLANG_TIDY_VERSION}" VERSION_LESS "17.0.0")
+  message(STATUS "The clang-tidy version found ${LIBCXX_CLANG_TIDY_VERSION} is
+                  too old, version 17.0.0 is required;
+                  custom libc++ clang-tidy checks will not be available.")
+endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+   NOT CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "${LIBCXX_CLANG_TIDY_VERSION}")
+
+  set(LIBCXX_CLANG_TIDY "" CACHE INTERNAL "")
+  message(STATUS "The version of clang ${CMAKE_CXX_COMPILER_VERSION} differs
+                  from the version of clang-tidy ${LIBCXX_CLANG_TIDY_VERSION};
+                  custom libc++ clang-tidy checks will not be available.")
+  return()
+endif()
+
+# Since the Clang C++ ABI is not stable the Clang libraries and clang-tidy
+# version must match. Otherwise there likely will be ODR-violations. This had
+# led to crashes and incorrect output of the clang-tidy based checks.
+find_package(Clang "${LIBCXX_CLANG_TIDY_VERSION}")
+
 set(SOURCES
     abi_tag_on_virtual.cpp
     header_exportable_declarations.cpp
@@ -23,6 +94,7 @@ set(SOURCES
    )
 
 if(NOT Clang_FOUND)
+  set(LIBCXX_CLANG_TIDY "" CACHE INTERNAL "")
   message(STATUS "Could not find a suitable version of the Clang development package;
                   custom libc++ clang-tidy checks will not be available.")
   return()
diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot
index ddfe53d2d8bd63..3719ab7f0453bb 100755
--- a/libcxx/utils/ci/run-buildbot
+++ b/libcxx/utils/ci/run-buildbot
@@ -47,6 +47,10 @@ CLANG_FORMAT        The clang-format binary to use when generating the format
 ENABLE_CLANG_TIDY   Whether to compile and run clang-tidy checks. This variable
                     is optional.
 
+CLANG_TIDY_EXECUTABLE
+                    The clang-tidy executable to use. Its version should match
+                    the clang version used. This variable is optional.
+
 EOF
 }
 
@@ -115,6 +119,10 @@ if [ -z "${ENABLE_CLANG_TIDY}" ]; then
     ENABLE_CLANG_TIDY=Off
 fi
 
+if [ -z "${CLANG_TIDY_EXECUTABLE}" ]; then
+   CLANG_TIDY_EXECUTABLE=''
+fi
+
 function generate-cmake-base() {
     echo "--- Generating CMake"
     ${CMAKE} \
@@ -127,6 +135,7 @@ function generate-cmake-base() {
           -DLIBCXXABI_ENABLE_WERROR=YES \
           -DLIBUNWIND_ENABLE_WERROR=YES \
           -DLIBCXX_ENABLE_CLANG_TIDY=${ENABLE_CLANG_TIDY} \
+		  -DLIBCXX_CLANG_TIDY_EXECUTABLE=${CLANG_TIDY_EXECUTABLE} \
           -DLLVM_LIT_ARGS="-sv --xunit-xml-output test-results.xml --timeout=1500 --time-tests" \
           "${@}"
 }
diff --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py
index 9a71c494030d70..1b19ea29120c80 100644
--- a/libcxx/utils/libcxx/test/config.py
+++ b/libcxx/utils/libcxx/test/config.py
@@ -9,6 +9,13 @@
 import os
 
 
+def _hasSubstitution(substitution, config):
+    for k, v in config.substitutions:
+        if k == substitution:
+            return True
+    return False
+
+
 def _getSubstitution(substitution, config):
     for (orig, replacement) in config.substitutions:
         if orig == substitution:
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index 6ef40755c59d97..da4aa3b8447097 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -7,6 +7,7 @@
 # ===----------------------------------------------------------------------===##
 
 from libcxx.test.dsl import *
+import libcxx.test.config as config
 from lit.BooleanExpression import BooleanExpression
 import re
 import shutil
@@ -24,29 +25,6 @@
 _msvcVersion = lambda cfg: (int(compilerMacros(cfg)["_MSC_VER"]) // 100, int(compilerMacros(cfg)["_MSC_VER"]) % 100)
 
 
-def _getSuitableClangTidy(cfg):
-    try:
-        # If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests.
-        if runScriptExitCode(cfg, ["stat %{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin"]) != 0:
-            return None
-
-        # TODO MODULES require ToT due module specific fixes.
-        if runScriptExitCode(cfg, ['clang-tidy-18 --version']) == 0:
-          return 'clang-tidy-18'
-
-        # TODO This should be the last stable release.
-        # LLVM RELEASE bump to latest stable version
-        if runScriptExitCode(cfg, ["clang-tidy-16 --version"]) == 0:
-            return "clang-tidy-16"
-
-        # LLVM RELEASE bump version
-        if int(re.search("[0-9]+", commandOutput(cfg, ["clang-tidy --version"])).group()) >= 16:
-            return "clang-tidy"
-
-    except ConfigurationRuntimeError:
-        return None
-
-
 def _getAndroidDeviceApi(cfg):
     return int(
         programOutput(
@@ -299,10 +277,8 @@ def _getAndroidDeviceApi(cfg):
     ),
     Feature(
         name="has-clang-tidy",
-        when=lambda cfg: _getSuitableClangTidy(cfg) is not None,
-        actions=[
-            AddSubstitution("%{clang-tidy}", lambda cfg: _getSuitableClangTidy(cfg))
-        ],
+        when=lambda cfg: config._hasSubstitution("%{clang-tidy}", cfg)
+        and config._getSubstitution("%{clang-tidy}", cfg) != "",
     ),
     # Whether module support for the platform is available.
     Feature(
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 81f2753a4edd85..0f83a3e2212552 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -15,18 +15,7 @@ if(NOT LLVM_NO_INSTALL_NAME_DIR_FOR_BUILD_TREE)
   set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON)
 endif()
 
-if(NOT DEFINED LLVM_VERSION_MAJOR)
-  set(LLVM_VERSION_MAJOR 19)
-endif()
-if(NOT DEFINED LLVM_VERSION_MINOR)
-  set(LLVM_VERSION_MINOR 0)
-endif()
-if(NOT DEFINED LLVM_VERSION_PATCH)
-  set(LLVM_VERSION_PATCH 0)
-endif()
-if(NOT DEFINED LLVM_VERSION_SUFFIX)
-  set(LLVM_VERSION_SUFFIX git)
-endif()
+include(${LLVM_COMMON_CMAKE_UTILS}/Modules/LLVMVersion.cmake)
 
 if (NOT PACKAGE_VERSION)
   set(PACKAGE_VERSION
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 634ffe710b06b8..d9415237cbefde 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -6,6 +6,8 @@ set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
 include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake
   NO_POLICY_SCOPE)
 
+include(${LLVM_COMMON_CMAKE_UTILS}/Modules/LLVMVersion.cmake)
+
 project(Runtimes C CXX ASM)
 
 list(INSERT CMAKE_MODULE_PATH 0

>From 66e03317785914089e9dc1b18d3ba459693e81fd Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Sun, 3 Mar 2024 13:08:36 +0100
Subject: [PATCH 2/2] Address review comments

---
 libcxx/CMakeLists.txt                         |  4 -
 libcxx/test/configs/cmake-bridge.cfg.in       |  1 -
 libcxx/test/tools/CMakeLists.txt              |  5 ++
 .../tools/clang_tidy_checks/CMakeLists.txt    | 74 +------------------
 libcxx/utils/ci/run-buildbot                  |  9 ---
 libcxx/utils/libcxx/test/config.py            |  7 --
 libcxx/utils/libcxx/test/features.py          |  7 --
 libcxx/utils/libcxx/test/params.py            | 46 +++++++++++-
 8 files changed, 48 insertions(+), 105 deletions(-)

diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index fbe426a253f182..d392e95077ac57 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -124,10 +124,6 @@ option(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS
    the shared library they shipped should turn this on and see `include/__availability`
    for more details." OFF)
 option(LIBCXX_ENABLE_CLANG_TIDY "Whether to compile and run clang-tidy checks" OFF)
-set(LIBCXX_CLANG_TIDY_EXECUTABLE "" CACHE FILEPATH
-  "The clang-tidy executable to use to run the clang-tidy checks.
-   When the variable is not set cmake will search for clang-tidy.
-   This is only used when LIBCXX_ENABLE_CLANG_TIDY is ON.")
 
 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
   set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-gcc.cfg.in")
diff --git a/libcxx/test/configs/cmake-bridge.cfg.in b/libcxx/test/configs/cmake-bridge.cfg.in
index 1f294af48818a3..84b3270a8940ac 100644
--- a/libcxx/test/configs/cmake-bridge.cfg.in
+++ b/libcxx/test/configs/cmake-bridge.cfg.in
@@ -25,7 +25,6 @@ config.test_exec_root = os.path.join('@CMAKE_BINARY_DIR@', 'test')
 # Add substitutions for bootstrapping the test suite configuration
 import shlex
 config.substitutions.append(('%{cxx}', shlex.quote('@CMAKE_CXX_COMPILER@')))
-config.substitutions.append(('%{clang-tidy}', shlex.quote('@LIBCXX_CLANG_TIDY@')))
 config.substitutions.append(('%{libcxx-dir}', '@LIBCXX_SOURCE_DIR@'))
 config.substitutions.append(('%{include-dir}', '@LIBCXX_GENERATED_INCLUDE_DIR@'))
 config.substitutions.append(('%{target-include-dir}', '@LIBCXX_GENERATED_INCLUDE_TARGET_DIR@'))
diff --git a/libcxx/test/tools/CMakeLists.txt b/libcxx/test/tools/CMakeLists.txt
index 10be63e8b50aa5..e30ad6cdd8201f 100644
--- a/libcxx/test/tools/CMakeLists.txt
+++ b/libcxx/test/tools/CMakeLists.txt
@@ -3,5 +3,10 @@ set(LIBCXX_TEST_TOOLS_PATH ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
 
 # TODO: Remove LIBCXX_ENABLE_CLANG_TIDY
 if(LIBCXX_ENABLE_CLANG_TIDY)
+  if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+    message(STATUS "Clang-tidy can only be used when building libc++ with "
+                   "a clang compiler.")
+    return()
+  endif()
   add_subdirectory(clang_tidy_checks)
 endif()
diff --git a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
index 1b195f72319eda..9e3bd06ed43ae5 100644
--- a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
+++ b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt
@@ -5,81 +5,10 @@
 set(LLVM_DIR_SAVE ${LLVM_DIR})
 set(Clang_DIR_SAVE ${Clang_DIR})
 
-# libc++ only supports the latest two released versions of clang-tidy. During
-# the release period there the new unreleased version is also supported. To keep
-# this code simple, always accept the last 3 versions.
-set(HEAD ${LLVM_VERSION_MAJOR})
-math(EXPR MINUS_1 "${HEAD} - 1")
-math(EXPR MINUS_2 "${MINUS_1} - 1")
-math(EXPR MINUS_3 "${MINUS_2} - 1")
-
-if("${LIBCXX_CLANG_TIDY_EXECUTABLE}" STREQUAL "")
-  set(NAMES "clang-tidy-${HEAD}"
-            "clang-tidy-${MINUS_1}"
-            "clang-tidy-${MINUS_2}"
-            "clang-tidy-${MINUS_3}"
-            "clang-tidy")
-  if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
-    string(REGEX MATCH
-           "[0-9]+"
-           LIBCXX_CLANG_MAJOR
-           "${CMAKE_CXX_COMPILER_VERSION}")
-    set(NAMES "clang-tidy-${LIBCXX_CLANG_MAJOR}"
-              "clang-tidy")
-  endif()
-  find_program(LIBCXX_CLANG_TIDY NAMES ${NAMES})
-else()
-  set(LIBCXX_CLANG_TIDY "${LIBCXX_CLANG_TIDY_EXECUTABLE}" CACHE INTERNAL "")
-endif()
-
-if("${LIBCXX_CLANG_TIDY}" STREQUAL "")
-  set(LIBCXX_CLANG_TIDY "" CACHE INTERNAL "")
-  message(STATUS "Could not find a clang-tidy executable;
-                  custom libc++ clang-tidy checks will not be available.")
-  return()
-endif()
-
-execute_process(COMMAND
-            "${LIBCXX_CLANG_TIDY}" "--version"
-            OUTPUT_VARIABLE CLANG_TIDY_VERSION_OUTPUT
-            COMMAND_ERROR_IS_FATAL ANY)
-string(REGEX MATCH
-       "[0-9]+\.[0-9]+\.[0-9]+"
-       LIBCXX_CLANG_TIDY_VERSION
-       "${CLANG_TIDY_VERSION_OUTPUT}")
-
-if("${LIBCXX_CLANG_TIDY_VERSION}" VERSION_LESS "${MINUS_3}")
-  set(LIBCXX_CLANG_TIDY "" CACHE INTERNAL "")
-  message(STATUS "The clang-tidy version found ${LIBCXX_CLANG_TIDY_VERSION} is
-                  too old, version ${MINUS_3}.0.0 is required;
-                  custom libc++ clang-tidy checks will not be available.")
-  return()
-endif()
-
-# For modules clang-tidy 17 or newer is required. This is due to the state of
-# implementation in clang/clang-tidy. This additional restriction should be
-# temporary.
-# TODO(LLVM-19) Remove this check
-if("${LIBCXX_CLANG_TIDY_VERSION}" VERSION_LESS "17.0.0")
-  message(STATUS "The clang-tidy version found ${LIBCXX_CLANG_TIDY_VERSION} is
-                  too old, version 17.0.0 is required;
-                  custom libc++ clang-tidy checks will not be available.")
-endif()
-
-if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
-   NOT CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "${LIBCXX_CLANG_TIDY_VERSION}")
-
-  set(LIBCXX_CLANG_TIDY "" CACHE INTERNAL "")
-  message(STATUS "The version of clang ${CMAKE_CXX_COMPILER_VERSION} differs
-                  from the version of clang-tidy ${LIBCXX_CLANG_TIDY_VERSION};
-                  custom libc++ clang-tidy checks will not be available.")
-  return()
-endif()
-
 # Since the Clang C++ ABI is not stable the Clang libraries and clang-tidy
 # version must match. Otherwise there likely will be ODR-violations. This had
 # led to crashes and incorrect output of the clang-tidy based checks.
-find_package(Clang "${LIBCXX_CLANG_TIDY_VERSION}")
+find_package(Clang ${CMAKE_CXX_COMPILER_VERSION})
 
 set(SOURCES
     abi_tag_on_virtual.cpp
@@ -94,7 +23,6 @@ set(SOURCES
    )
 
 if(NOT Clang_FOUND)
-  set(LIBCXX_CLANG_TIDY "" CACHE INTERNAL "")
   message(STATUS "Could not find a suitable version of the Clang development package;
                   custom libc++ clang-tidy checks will not be available.")
   return()
diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot
index 3719ab7f0453bb..ddfe53d2d8bd63 100755
--- a/libcxx/utils/ci/run-buildbot
+++ b/libcxx/utils/ci/run-buildbot
@@ -47,10 +47,6 @@ CLANG_FORMAT        The clang-format binary to use when generating the format
 ENABLE_CLANG_TIDY   Whether to compile and run clang-tidy checks. This variable
                     is optional.
 
-CLANG_TIDY_EXECUTABLE
-                    The clang-tidy executable to use. Its version should match
-                    the clang version used. This variable is optional.
-
 EOF
 }
 
@@ -119,10 +115,6 @@ if [ -z "${ENABLE_CLANG_TIDY}" ]; then
     ENABLE_CLANG_TIDY=Off
 fi
 
-if [ -z "${CLANG_TIDY_EXECUTABLE}" ]; then
-   CLANG_TIDY_EXECUTABLE=''
-fi
-
 function generate-cmake-base() {
     echo "--- Generating CMake"
     ${CMAKE} \
@@ -135,7 +127,6 @@ function generate-cmake-base() {
           -DLIBCXXABI_ENABLE_WERROR=YES \
           -DLIBUNWIND_ENABLE_WERROR=YES \
           -DLIBCXX_ENABLE_CLANG_TIDY=${ENABLE_CLANG_TIDY} \
-		  -DLIBCXX_CLANG_TIDY_EXECUTABLE=${CLANG_TIDY_EXECUTABLE} \
           -DLLVM_LIT_ARGS="-sv --xunit-xml-output test-results.xml --timeout=1500 --time-tests" \
           "${@}"
 }
diff --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py
index 1b19ea29120c80..9a71c494030d70 100644
--- a/libcxx/utils/libcxx/test/config.py
+++ b/libcxx/utils/libcxx/test/config.py
@@ -9,13 +9,6 @@
 import os
 
 
-def _hasSubstitution(substitution, config):
-    for k, v in config.substitutions:
-        if k == substitution:
-            return True
-    return False
-
-
 def _getSubstitution(substitution, config):
     for (orig, replacement) in config.substitutions:
         if orig == substitution:
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index da4aa3b8447097..3f0dc0c50a0d00 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -7,7 +7,6 @@
 # ===----------------------------------------------------------------------===##
 
 from libcxx.test.dsl import *
-import libcxx.test.config as config
 from lit.BooleanExpression import BooleanExpression
 import re
 import shutil
@@ -24,7 +23,6 @@
 _isMSVC = lambda cfg: "_MSC_VER" in compilerMacros(cfg)
 _msvcVersion = lambda cfg: (int(compilerMacros(cfg)["_MSC_VER"]) // 100, int(compilerMacros(cfg)["_MSC_VER"]) % 100)
 
-
 def _getAndroidDeviceApi(cfg):
     return int(
         programOutput(
@@ -275,11 +273,6 @@ def _getAndroidDeviceApi(cfg):
         name="executor-has-no-bash",
         when=lambda cfg: runScriptExitCode(cfg, ["%{exec} bash -c 'bash --version'"]) != 0,
     ),
-    Feature(
-        name="has-clang-tidy",
-        when=lambda cfg: config._hasSubstitution("%{clang-tidy}", cfg)
-        and config._getSubstitution("%{clang-tidy}", cfg) != "",
-    ),
     # Whether module support for the platform is available.
     Feature(
         name="has-no-cxx-module-support",
diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py
index 89d9f22e9dc6df..4b79e09a9a4046 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -53,17 +53,14 @@
     "-Wunused-parameter",
     "-Wunreachable-code",
     "-Wno-unused-local-typedef",
-
     # Disable warnings for extensions used in C++03
     "-Wno-local-type-template-args",
     "-Wno-c++11-extensions",
-
     # TODO(philnik) This fails with the PSTL.
     "-Wno-unknown-pragmas",
     # Don't fail compilation in case the compiler fails to perform the requested
     # loop vectorization.
     "-Wno-pass-failed",
-
     # TODO: Find out why GCC warns in lots of places (is this a problem with always_inline?)
     "-Wno-dangling-reference",
     "-Wno-mismatched-new-delete",
@@ -110,6 +107,37 @@ def getSizeOptimizationFlag(cfg):
         )
 
 
+def testClangTidy(cfg, version, executable):
+    try:
+        if version in commandOutput(cfg, [f"{executable} --version"]):
+            return executable
+    except ConfigurationRuntimeError:
+        return None
+
+
+def getSuitableClangTidy(cfg):
+    # If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests.
+    if (
+        runScriptExitCode(
+            cfg, ["stat %{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin"]
+        )
+        != 0
+    ):
+        return None
+
+    version = "{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format(
+        **compilerMacros(cfg)
+    )
+    exe = testClangTidy(
+        cfg, version, "clang-tidy-{__clang_major__}".format(**compilerMacros(cfg))
+    )
+
+    if not exe:
+        exe = testClangTidy(cfg, version, "clang-tidy")
+
+    return exe
+
+
 # fmt: off
 DEFAULT_PARAMETERS = [
     Parameter(
@@ -366,6 +394,16 @@ def getSizeOptimizationFlag(cfg):
         default=f"{shlex.quote(sys.executable)} {shlex.quote(str(Path(__file__).resolve().parent.parent.parent / 'run.py'))}",
         help="Custom executor to use instead of the configured default.",
         actions=lambda executor: [AddSubstitution("%{executor}", executor)],
-    )
+    ),
+    Parameter(
+        name='clang-tidy-executable',
+        type=str,
+        default=lambda cfg: getSuitableClangTidy(cfg),
+        help="TODO",
+        actions=lambda exe: [] if exe is None else [
+            AddFeature('has-clang-tidy'),
+            AddSubstitution('%{clang-tidy}', exe),
+        ]
+     ),
 ]
 # fmt: on



More information about the llvm-commits mailing list