From 9b4d8211b75f67559a6c2eaf67ce052c1076669f Mon Sep 17 00:00:00 2001 From: Timo Ewalds Date: Wed, 30 Jul 2025 17:16:29 +0100 Subject: [PATCH 01/15] Add a sketch of a try_lock that takes multiple locks. --- mutex_protected.h | 11 +++++++++++ mutex_protected_test.cc | 31 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/mutex_protected.h b/mutex_protected.h index 5b09b91..77593dd 100644 --- a/mutex_protected.h +++ b/mutex_protected.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -254,6 +255,16 @@ auto lock_protected(MutexProtected &...mps) { return std::make_tuple(mps.adopt_lock()...); } +template +std::expected try_lock(MutexProtected &...mps) { + int r = std::try_lock(mps.mutex...); + if (r >= 0) { + return r; + } else { + return std::make_tuple(mps.adopt_lock()...); + } +} + } // namespace xyz #endif // XYZ_MUTEX_PROTECTED_H diff --git a/mutex_protected_test.cc b/mutex_protected_test.cc index 26fc6cf..42f0cf8 100644 --- a/mutex_protected_test.cc +++ b/mutex_protected_test.cc @@ -185,6 +185,37 @@ TYPED_TEST(MutexProtectedTest, LockMultiple) { } } +TYPED_TEST(MutexProtectedTest, TryLockMultiple) { + mutex_protected a(1); + mutex_protected b(2); + { + auto r = xyz::try_lock(a, b); + ASSERT_TRUE(r.has_value()); + auto [la, lb] = r.value(); + EXPECT_EQ(*la, 1); + EXPECT_EQ(*lb, 2); + *la += 10; + *lb += 10; + } + { + auto la = a.lock(); + auto r = xyz::try_lock(a, b); + ASSERT_FALSE(r.has_value()); + EXPECT_EQ(r.error(), 0); + } + { + auto lb = b.lock(); + auto r = xyz::try_lock(a, b); + ASSERT_FALSE(r.has_value()); + EXPECT_EQ(r.error(), 1); + } + { + auto [lb, la] = xyz::lock(b, a); + EXPECT_EQ(*la, 11); + EXPECT_EQ(*lb, 12); + } +} + template class SharedMutexProtectedTest : public testing::Test {}; From 1bbffbae94af7c8957c9d6231dd6e391159071fa Mon Sep 17 00:00:00 2001 From: Timo Ewalds Date: Thu, 31 Jul 2025 15:22:00 +0100 Subject: [PATCH 02/15] try_lock -> try_lock_protected --- mutex_protected.h | 9 ++++++--- mutex_protected_test.cc | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/mutex_protected.h b/mutex_protected.h index 77593dd..34f4b32 100644 --- a/mutex_protected.h +++ b/mutex_protected.h @@ -239,14 +239,17 @@ class mutex_protected { M mutex; T v; - // Used by `xyz::lock_protected` when locking multiple mutex_protected - // objects. + // Used by `xyz::lock_protected` and `xyz::try_lock_protected` when locking + // multiple mutex_protected objects. mutex_locked> adopt_lock() { return mutex_locked>(&v, mutex, std::adopt_lock); } template friend auto lock_protected(MutexProtected &...mp); + + template + friend std::expected try_lock_protected(MutexProtected &...mp); }; template @@ -256,7 +259,7 @@ auto lock_protected(MutexProtected &...mps) { } template -std::expected try_lock(MutexProtected &...mps) { +std::expected try_lock_protected(MutexProtected &...mps) { int r = std::try_lock(mps.mutex...); if (r >= 0) { return r; diff --git a/mutex_protected_test.cc b/mutex_protected_test.cc index 42f0cf8..43ae3f1 100644 --- a/mutex_protected_test.cc +++ b/mutex_protected_test.cc @@ -189,7 +189,7 @@ TYPED_TEST(MutexProtectedTest, TryLockMultiple) { mutex_protected a(1); mutex_protected b(2); { - auto r = xyz::try_lock(a, b); + auto r = xyz::try_lock_protected(a, b); ASSERT_TRUE(r.has_value()); auto [la, lb] = r.value(); EXPECT_EQ(*la, 1); @@ -199,18 +199,18 @@ TYPED_TEST(MutexProtectedTest, TryLockMultiple) { } { auto la = a.lock(); - auto r = xyz::try_lock(a, b); + auto r = xyz::try_lock_protected(a, b); ASSERT_FALSE(r.has_value()); EXPECT_EQ(r.error(), 0); } { auto lb = b.lock(); - auto r = xyz::try_lock(a, b); + auto r = xyz::try_lock_protected(a, b); ASSERT_FALSE(r.has_value()); EXPECT_EQ(r.error(), 1); } { - auto [lb, la] = xyz::lock(b, a); + auto [lb, la] = xyz::lock_protected(b, a); EXPECT_EQ(*la, 11); EXPECT_EQ(*lb, 12); } From 603aee9ac25b088c7362b5875d4cd282f43ac5b8 Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" Date: Thu, 31 Jul 2025 22:49:49 +0100 Subject: [PATCH 03/15] Fix compile errors and tests --- .bazelrc | 2 +- .vscode/settings.json | 17 ++++++++++++- cmake/xyz_add_library.cmake | 4 +-- cmake/xyz_add_object_library.cmake | 4 +-- cmake/xyz_add_test.cmake | 4 +-- mutex_protected.h | 13 +++++++--- mutex_protected_test.cc | 41 ++++++++++++++++++++---------- 7 files changed, 59 insertions(+), 26 deletions(-) diff --git a/.bazelrc b/.bazelrc index 12a75ac..31e5143 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,6 +1,6 @@ test --test_output=errors -build --cxxopt='-std=c++20' +build --cxxopt='-std=c++23' build --cxxopt='-Wno-self-move' build --cxxopt='-fdiagnostics-color=always' diff --git a/.vscode/settings.json b/.vscode/settings.json index 88e6e0b..dec6981 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -67,6 +67,21 @@ "streambuf": "cpp", "thread": "cpp", "cinttypes": "cpp", - "typeinfo": "cpp" + "typeinfo": "cpp", + "__bit_reference": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__node_handle": "cpp", + "__split_buffer": "cpp", + "__verbose_abort": "cpp", + "bitset": "cpp", + "complex": "cpp", + "execution": "cpp", + "forward_list": "cpp", + "ios": "cpp", + "locale": "cpp", + "print": "cpp", + "queue": "cpp", + "stack": "cpp" } } diff --git a/cmake/xyz_add_library.cmake b/cmake/xyz_add_library.cmake index 9d1b87d..9879ae6 100644 --- a/cmake/xyz_add_library.cmake +++ b/cmake/xyz_add_library.cmake @@ -47,9 +47,9 @@ function(xyz_add_library) endif() if (NOT XYZ_VERSION) - set(XYZ_CXX_STANDARD cxx_std_20) + set(XYZ_CXX_STANDARD cxx_std_23) else() - set(VALID_TARGET_VERSIONS 11 14 17 20 23) + set(VALID_TARGET_VERSIONS 23) list(FIND VALID_TARGET_VERSIONS ${XYZ_VERSION} index) if(index EQUAL -1) message(FATAL_ERROR "TYPE must be one of <${VALID_TARGET_VERSIONS}>") diff --git a/cmake/xyz_add_object_library.cmake b/cmake/xyz_add_object_library.cmake index 2a40659..34ba252 100644 --- a/cmake/xyz_add_object_library.cmake +++ b/cmake/xyz_add_object_library.cmake @@ -52,9 +52,9 @@ function(xyz_add_object_library) endif() if (NOT XYZ_VERSION) - set(XYZ_CXX_STANDARD cxx_std_20) + set(XYZ_CXX_STANDARD cxx_std_23) else() - set(VALID_TARGET_VERSIONS 11 14 17 20 23) + set(VALID_TARGET_VERSIONS 23) list(FIND VALID_TARGET_VERSIONS ${XYZ_VERSION} index) if(index EQUAL -1) message(FATAL_ERROR "TYPE must be one of <${VALID_TARGET_VERSIONS}>") diff --git a/cmake/xyz_add_test.cmake b/cmake/xyz_add_test.cmake index 28b8884..b1aa1f0 100644 --- a/cmake/xyz_add_test.cmake +++ b/cmake/xyz_add_test.cmake @@ -47,9 +47,9 @@ function(xyz_add_test) message(FATAL_ERROR "NAME parameter must be supplied") endif() if (NOT XYZ_VERSION) - set(XYZ_VERSION 20) + set(XYZ_VERSION 23) else() - set(VALID_TARGET_VERSIONS 11 14 17 20 23) + set(VALID_TARGET_VERSIONS 23) list(FIND VALID_TARGET_VERSIONS ${XYZ_VERSION} index) if(index EQUAL -1) message(FATAL_ERROR "TYPE must be one of <${VALID_TARGET_VERSIONS}>") diff --git a/mutex_protected.h b/mutex_protected.h index 34f4b32..502f0db 100644 --- a/mutex_protected.h +++ b/mutex_protected.h @@ -249,7 +249,8 @@ class mutex_protected { friend auto lock_protected(MutexProtected &...mp); template - friend std::expected try_lock_protected(MutexProtected &...mp); + friend auto try_lock_protected(MutexProtected &...mps) + -> std::expected, int>; }; template @@ -259,12 +260,16 @@ auto lock_protected(MutexProtected &...mps) { } template -std::expected try_lock_protected(MutexProtected &...mps) { +auto try_lock_protected(MutexProtected &...mps) + -> std::expected, int> { int r = std::try_lock(mps.mutex...); if (r >= 0) { - return r; + return std::expected, int>( + std::unexpect, r); + } else { - return std::make_tuple(mps.adopt_lock()...); + return std::expected, int>( + std::in_place, mps.adopt_lock()...); } } diff --git a/mutex_protected_test.cc b/mutex_protected_test.cc index 43ae3f1..127737f 100644 --- a/mutex_protected_test.cc +++ b/mutex_protected_test.cc @@ -191,23 +191,36 @@ TYPED_TEST(MutexProtectedTest, TryLockMultiple) { { auto r = xyz::try_lock_protected(a, b); ASSERT_TRUE(r.has_value()); - auto [la, lb] = r.value(); + + auto& [la, lb] = r.value(); EXPECT_EQ(*la, 1); EXPECT_EQ(*lb, 2); *la += 10; *lb += 10; } - { - auto la = a.lock(); - auto r = xyz::try_lock_protected(a, b); - ASSERT_FALSE(r.has_value()); - EXPECT_EQ(r.error(), 0); - } - { - auto lb = b.lock(); - auto r = xyz::try_lock_protected(a, b); - ASSERT_FALSE(r.has_value()); - EXPECT_EQ(r.error(), 1); + if constexpr (!std::is_same_v && + !std::is_same_v) { + { + auto r = xyz::try_lock_protected(a, b); + ASSERT_TRUE(r.has_value()); + auto& [la, lb] = r.value(); + EXPECT_EQ(*la, 11); + EXPECT_EQ(*lb, 12); + } + { + auto la = a.lock(); + auto r = xyz::try_lock_protected(a, b); + ASSERT_FALSE(r.has_value()); + EXPECT_EQ(r.error(), 0); + } + { + auto lb = b.lock(); + auto r = xyz::try_lock_protected(a, b); + ASSERT_FALSE(r.has_value()); + EXPECT_EQ(r.error(), 1); + } + } else /* constexpr */ { + // Recursive mutexes can be locked multiple times by the same thread. } { auto [lb, la] = xyz::lock_protected(b, a); @@ -321,8 +334,8 @@ TYPED_TEST(SharedMutexProtectedTest, ThreadSafetyCorrectness) { } EXPECT_EQ(*value.lock(), writers * iters); - // Hopefully this stops things from being optimized away, but I don't see how - // this could fail. + // Hopefully this stops things from being optimized away, but I don't see + // how this could fail. EXPECT_LE(*grand_total.lock(), (long long)readers * writers * iters * iters); } From 050798f429f7bacac5746aae0dd4ac74b58ccf84 Mon Sep 17 00:00:00 2001 From: Timo Ewalds Date: Wed, 30 Jul 2025 17:16:29 +0100 Subject: [PATCH 04/15] Add a sketch of a try_lock that takes multiple locks. --- mutex_protected.h | 1 + mutex_protected_test.cc | 35 ++++++++++++++++++----------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/mutex_protected.h b/mutex_protected.h index 502f0db..bb87845 100644 --- a/mutex_protected.h +++ b/mutex_protected.h @@ -260,6 +260,7 @@ auto lock_protected(MutexProtected &...mps) { } template + auto try_lock_protected(MutexProtected &...mps) -> std::expected, int> { int r = std::try_lock(mps.mutex...); diff --git a/mutex_protected_test.cc b/mutex_protected_test.cc index 127737f..4228cf1 100644 --- a/mutex_protected_test.cc +++ b/mutex_protected_test.cc @@ -198,29 +198,30 @@ TYPED_TEST(MutexProtectedTest, TryLockMultiple) { *la += 10; *lb += 10; } - if constexpr (!std::is_same_v && - !std::is_same_v) { - { - auto r = xyz::try_lock_protected(a, b); - ASSERT_TRUE(r.has_value()); - auto& [la, lb] = r.value(); - EXPECT_EQ(*la, 11); - EXPECT_EQ(*lb, 12); - } - { - auto la = a.lock(); + { + auto r = xyz::try_lock_protected(a, b); + ASSERT_TRUE(r.has_value()); + auto& [la, lb] = r.value(); + EXPECT_EQ(*la, 11); + EXPECT_EQ(*lb, 12); + } + { + auto la = a.lock(); + std::thread t([&]() { // Needed due to recursive locks. auto r = xyz::try_lock_protected(a, b); ASSERT_FALSE(r.has_value()); EXPECT_EQ(r.error(), 0); - } - { - auto lb = b.lock(); + }); + t.join(); + } + { + auto lb = b.lock(); + std::thread t([&]() { // Needed due to recursive locks. auto r = xyz::try_lock_protected(a, b); ASSERT_FALSE(r.has_value()); EXPECT_EQ(r.error(), 1); - } - } else /* constexpr */ { - // Recursive mutexes can be locked multiple times by the same thread. + }); + t.join(); } { auto [lb, la] = xyz::lock_protected(b, a); From 686b01308be418bc793a595580ae0854333e41da Mon Sep 17 00:00:00 2001 From: Timo Ewalds Date: Thu, 31 Jul 2025 15:22:00 +0100 Subject: [PATCH 05/15] try_lock -> try_lock_protected --- mutex_protected.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mutex_protected.h b/mutex_protected.h index bb87845..cbba185 100644 --- a/mutex_protected.h +++ b/mutex_protected.h @@ -249,6 +249,7 @@ class mutex_protected { friend auto lock_protected(MutexProtected &...mp); template + friend auto try_lock_protected(MutexProtected &...mps) -> std::expected, int>; }; @@ -260,7 +261,6 @@ auto lock_protected(MutexProtected &...mps) { } template - auto try_lock_protected(MutexProtected &...mps) -> std::expected, int> { int r = std::try_lock(mps.mutex...); From 24ff41700c1834bcbad77d877bd9b1fe80642d72 Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" Date: Thu, 31 Jul 2025 22:49:49 +0100 Subject: [PATCH 06/15] Fix compile errors and tests --- mutex_protected.h | 1 - 1 file changed, 1 deletion(-) diff --git a/mutex_protected.h b/mutex_protected.h index cbba185..502f0db 100644 --- a/mutex_protected.h +++ b/mutex_protected.h @@ -249,7 +249,6 @@ class mutex_protected { friend auto lock_protected(MutexProtected &...mp); template - friend auto try_lock_protected(MutexProtected &...mps) -> std::expected, int>; }; From 084f528a93231f4fde2878bde61ac5f4d888a3b4 Mon Sep 17 00:00:00 2001 From: Timo Ewalds Date: Fri, 1 Aug 2025 00:24:24 +0100 Subject: [PATCH 07/15] Remove old compilers that don't support std::expected. --- .github/workflows/cmake.yml | 39 ------------------------------------- 1 file changed, 39 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index eb1e17f..3dd8f6c 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -31,19 +31,6 @@ jobs: matrix: configuration: ["Release", "Debug"] settings: - - { - name: "Ubuntu GCC-11", - os: ubuntu-24.04, - compiler: - { - type: GCC, - version: 11, - cc: "gcc-11", - cxx: "g++-11", - std: 20, - }, - lib: "libstdc++11", - } - { name: "Ubuntu GCC-12", os: ubuntu-24.04, @@ -83,32 +70,6 @@ jobs: }, lib: "libstdc++14", } - - { - name: "Ubuntu Clang-17 + libc++", - os: ubuntu-24.04, - compiler: - { - type: CLANG, - version: 17, - cc: "clang-17", - cxx: "clang++-17", - std: 20, - }, - lib: "libc++17", - } - - { - name: "Ubuntu Clang-18 + libc++", - os: ubuntu-24.04, - compiler: - { - type: CLANG, - version: 18, - cc: "clang-18", - cxx: "clang++-18", - std: 20, - }, - lib: "libc++18", - } - { name: "Ubuntu Clang-19 + libc++", os: ubuntu-24.04, From 2492efeed6921b12b54b1c8c5351f5f8159ac7c5 Mon Sep 17 00:00:00 2001 From: Timo Ewalds Date: Fri, 1 Aug 2025 00:52:13 +0100 Subject: [PATCH 08/15] Add to the readme. --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 92a8b1b..fb2ca41 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,32 @@ mutex_protected value; ### Locking multiple mutexes simultaneously +If you have multiple mutexes that you want to lock, you need to be careful to +avoid deadlocks that can happen if different threads lock them in a different +order. The solution is to lock them in the same order, which is best delegated +to `std::lock`, `std::try_lock` or `std::scoped_lock`, but those only work on +true mutexes. We want to return multiple guards, so supply `lock_protected` and +`try_lock_protected` for `mutex_protected` objects. + +```cpp +mutex_protected a(1); +mutex_protected b(2); + +auto [lb, la] = xyz::lock_protected(b, a); +*la += *lb; +``` + +```cpp +auto r = xyz::try_lock_protected(a, b); +if (r.has_value()) { + auto& [la, lb] = r.value(); + *la += *lb; +} else { + assert(r.has_error()); + // r.error() tells you which lock was contended. +} +``` + ## License This code is licensed under the MIT License. See [LICENSE](LICENSE) for details. From 7b7caab43b0e5f9acf2a801231fddc3a5cac4c62 Mon Sep 17 00:00:00 2001 From: Timo Ewalds Date: Tue, 5 Aug 2025 21:23:25 +0100 Subject: [PATCH 09/15] Make clang-tidy use c++23 --- .github/workflows/clang-tidy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index c835123..0ae3bc8 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -47,4 +47,4 @@ jobs: --names-only \ --exclude_dirs build exploration compile_checks benchmarks)" echo $PROJECT_SOURCE_FILES \ - | xargs clang-tidy -warnings-as-errors="*" -p compile_commands.json + | xargs clang-tidy -std=cpp23 -warnings-as-errors="*" -p compile_commands.json From 2e51c5eb36ce78b3332937791336a8516e37dcf2 Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" Date: Thu, 7 Aug 2025 00:14:34 +0100 Subject: [PATCH 10/15] Remove non-supported clang-tidy flag --- .github/workflows/clang-tidy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 0ae3bc8..c835123 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -47,4 +47,4 @@ jobs: --names-only \ --exclude_dirs build exploration compile_checks benchmarks)" echo $PROJECT_SOURCE_FILES \ - | xargs clang-tidy -std=cpp23 -warnings-as-errors="*" -p compile_commands.json + | xargs clang-tidy -warnings-as-errors="*" -p compile_commands.json From cbe765dba1a6482bdd48da988e3f60dafb1efa2c Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" Date: Thu, 7 Aug 2025 00:18:52 +0100 Subject: [PATCH 11/15] Require clang v19 --- .github/workflows/clang-tidy.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index c835123..8205c9a 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -36,7 +36,11 @@ jobs: - name: Install the latest version of uv. uses: astral-sh/setup-uv@v5 - + - name: Install Clang + uses: egor-tensin/setup-clang@v1 + with: + version: 19 + platform: x64 - name: Configure CMake # We need `compile_commands.json` to be generated. run: cmake --preset Release From ff13ea320b9fca304724864df454ceb04cf275b5 Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" Date: Thu, 7 Aug 2025 00:23:51 +0100 Subject: [PATCH 12/15] Require latest clang for clang-tidy CI --- .github/workflows/clang-tidy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 8205c9a..c967281 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -39,7 +39,7 @@ jobs: - name: Install Clang uses: egor-tensin/setup-clang@v1 with: - version: 19 + version: latest platform: x64 - name: Configure CMake # We need `compile_commands.json` to be generated. run: cmake --preset Release From b240eb639c6a30f17c8f757f9790afbba886fdfd Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" Date: Thu, 7 Aug 2025 00:25:55 +0100 Subject: [PATCH 13/15] Require latest GCC for clang-tidy CI --- .github/workflows/clang-tidy.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index c967281..ca17dd1 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -41,6 +41,11 @@ jobs: with: version: latest platform: x64 + - name: Install Latest GCC + uses: egor-tensin/setup-gcc@v1 + with: + version: latest + platform: x64 - name: Configure CMake # We need `compile_commands.json` to be generated. run: cmake --preset Release From a9707a4b970794d1c2e24d6af3d42ea43369f4f4 Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" Date: Thu, 7 Aug 2025 00:44:52 +0100 Subject: [PATCH 14/15] Install a newer version of clang-tidy --- .github/workflows/clang-tidy.yml | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index ca17dd1..eccd45d 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -36,24 +36,15 @@ jobs: - name: Install the latest version of uv. uses: astral-sh/setup-uv@v5 - - name: Install Clang - uses: egor-tensin/setup-clang@v1 - with: - version: latest - platform: x64 - - name: Install Latest GCC - uses: egor-tensin/setup-gcc@v1 - with: - version: latest - platform: x64 - - name: Configure CMake # We need `compile_commands.json` to be generated. - run: cmake --preset Release - - name: clang-tidy + - name: Install clang-tidy-19 + run: sudo apt-get install -y clang-tidy-19 + + - name: clang-tidy (v19) run: | uv run scripts/reduce_compile_commands.py build/compile_commands.json > compile_commands.json PROJECT_SOURCE_FILES="$(python scripts/reduce_compile_commands.py build/compile_commands.json \ --names-only \ --exclude_dirs build exploration compile_checks benchmarks)" echo $PROJECT_SOURCE_FILES \ - | xargs clang-tidy -warnings-as-errors="*" -p compile_commands.json + | xargs clang-tidy-19 -warnings-as-errors="*" -p compile_commands.json From 323553ad5e60e7e670bc1c1e9d3c4d4b5deecf3f Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" Date: Thu, 7 Aug 2025 00:49:01 +0100 Subject: [PATCH 15/15] Restore mistakenly deleted step --- .github/workflows/clang-tidy.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index eccd45d..b7873c9 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -40,6 +40,9 @@ jobs: - name: Install clang-tidy-19 run: sudo apt-get install -y clang-tidy-19 + - name: Configure CMake # We need `compile_commands.json` to be generated. + run: cmake --preset Release + - name: clang-tidy (v19) run: | uv run scripts/reduce_compile_commands.py build/compile_commands.json > compile_commands.json