diff --git a/.clang-tidy b/.clang-tidy index 23018386c1..96cb6f5826 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -57,10 +57,12 @@ Checks: | readability-string-compare, readability-suspicious-call-argument, readability-uniqueptr-delete-release, + -bugprone-chained-comparison, -bugprone-easily-swappable-parameters, -bugprone-exception-escape, -bugprone-reserved-identifier, -bugprone-unused-raii, + -performance-enum-size, CheckOptions: - key: modernize-use-equals-default.IgnoreMacros diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 967587643c..1c34a5662d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -341,6 +341,12 @@ jobs: - clang: 16 std: 20 container_suffix: "-bullseye" + - clang: 17 + std: 20 + container_suffix: "-bookworm" + - clang: 18 + std: 20 + container_suffix: "-bookworm" name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64" container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}" diff --git a/.github/workflows/ci_sh_def.yml b/.github/workflows/ci_sh_def.yml index fd11911db5..f37f751634 100644 --- a/.github/workflows/ci_sh_def.yml +++ b/.github/workflows/ci_sh_def.yml @@ -358,6 +358,12 @@ jobs: - clang: 16 std: 20 container_suffix: "-bullseye" + - clang: 17 + std: 20 + container_suffix: "-bookworm" + - clang: 18 + std: 20 + container_suffix: "-bookworm" name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64" container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}" diff --git a/.github/workflows/ci_sh_def.yml.patch b/.github/workflows/ci_sh_def.yml.patch index e6f5e57f68..456ca7365e 100644 --- a/.github/workflows/ci_sh_def.yml.patch +++ b/.github/workflows/ci_sh_def.yml.patch @@ -1,5 +1,5 @@ ---- ci.yml 2024-07-01 20:26:45.034547517 -0700 -+++ ci_sh_def.yml 2024-07-01 20:27:32.110506039 -0700 +--- ci.yml 2024-07-29 11:18:11.967568957 -0700 ++++ ci_sh_def.yml 2024-07-29 11:18:42.087538968 -0700 @@ -1,4 +1,16 @@ -name: CI +# PLEASE KEEP THIS GROUP OF FILES IN SYNC AT ALL TIMES: @@ -67,7 +67,7 @@ - name: Build run: cmake --build build -j 2 -@@ -358,6 +375,7 @@ +@@ -364,6 +381,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} @@ -75,7 +75,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -387,7 +405,7 @@ +@@ -393,7 +411,7 @@ run: apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y cmake git python3-dev python3-pytest python3-numpy - name: Configure @@ -84,7 +84,7 @@ - name: Build run: cmake --build build -j2 --verbose -@@ -475,7 +493,7 @@ +@@ -481,7 +499,7 @@ cmake -S . -B build -DDOWNLOAD_CATCH=ON \ -DCMAKE_CXX_STANDARD=17 \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \ @@ -93,7 +93,7 @@ -DPYBIND11_TEST_FILTER="test_smart_ptr.cpp" - name: Build -@@ -531,6 +549,7 @@ +@@ -537,6 +555,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} @@ -101,7 +101,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -553,6 +572,7 @@ +@@ -559,6 +578,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} @@ -109,7 +109,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" -@@ -602,6 +622,7 @@ +@@ -608,6 +628,7 @@ -DDOWNLOAD_CATCH=ON \ -DDOWNLOAD_EIGEN=OFF \ -DCMAKE_CXX_STANDARD=11 \ @@ -117,7 +117,7 @@ -DCMAKE_CXX_COMPILER=$(which icpc) \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") -@@ -634,6 +655,7 @@ +@@ -640,6 +661,7 @@ -DDOWNLOAD_CATCH=ON \ -DDOWNLOAD_EIGEN=OFF \ -DCMAKE_CXX_STANDARD=17 \ @@ -125,7 +125,7 @@ -DCMAKE_CXX_COMPILER=$(which icpc) \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") -@@ -705,6 +727,7 @@ +@@ -711,6 +733,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=11 @@ -133,7 +133,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -755,6 +778,7 @@ +@@ -761,6 +784,7 @@ cmake ../pybind11-tests -DDOWNLOAD_CATCH=ON -DPYBIND11_WERROR=ON @@ -141,7 +141,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") working-directory: /build-tests -@@ -858,6 +882,7 @@ +@@ -864,6 +888,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON @@ -149,7 +149,7 @@ ${{ matrix.args }} - name: Build C++11 run: cmake --build build -j 2 -@@ -912,6 +937,7 @@ +@@ -918,6 +943,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON @@ -157,7 +157,7 @@ ${{ matrix.args }} - name: Build C++11 run: cmake --build build --config Debug -j 2 -@@ -954,6 +980,7 @@ +@@ -960,6 +986,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=20 @@ -165,7 +165,7 @@ - name: Build C++20 run: cmake --build build -j 2 -@@ -974,6 +1001,7 @@ +@@ -980,6 +1007,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=20 @@ -173,7 +173,7 @@ "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" - name: Build C++20 - Exercise cmake -DPYBIND11_TEST_OVERRIDE -@@ -1026,6 +1054,7 @@ +@@ -1032,6 +1060,7 @@ run: >- cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") @@ -181,7 +181,7 @@ -S . -B build - name: Build C++11 -@@ -1047,6 +1076,7 @@ +@@ -1053,6 +1082,7 @@ run: >- cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") @@ -189,7 +189,7 @@ -S . -B build2 - name: Build C++14 -@@ -1068,6 +1098,7 @@ +@@ -1074,6 +1104,7 @@ run: >- cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") @@ -197,7 +197,7 @@ -S . -B build3 - name: Build C++17 -@@ -1135,6 +1166,7 @@ +@@ -1141,6 +1172,7 @@ -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 @@ -205,7 +205,7 @@ - name: Build run: cmake --build . -j 2 -@@ -1200,6 +1232,7 @@ +@@ -1206,6 +1238,7 @@ -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 @@ -213,7 +213,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -1223,6 +1256,7 @@ +@@ -1229,6 +1262,7 @@ -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 85bcc3c6c9..6bb22171b7 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -42,7 +42,7 @@ jobs: # in .github/CONTRIBUTING.md and update as needed. name: Clang-Tidy runs-on: ubuntu-latest - container: silkeh/clang:15-bullseye + container: silkeh/clang:18-bookworm steps: - uses: actions/checkout@v4 diff --git a/docs/limitations.rst b/docs/limitations.rst index def5ad659c..1b06ea8728 100644 --- a/docs/limitations.rst +++ b/docs/limitations.rst @@ -50,10 +50,6 @@ clean, well written patch would likely be accepted to solve them. One consequence is that containers of ``char *`` are currently not supported. `#2245 `_ -- The ``cpptest`` does not run on Windows with Python 3.8 or newer, due to DLL - loader changes. User code that is correctly installed should not be affected. - `#2560 `_ - Python 3.9.0 warning ^^^^^^^^^^^^^^^^^^^^ diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 58f81bb33a..156baea906 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -574,7 +574,7 @@ PYBIND11_NOINLINE internals &get_internals() { } #endif internals_ptr->istate = tstate->interp; - state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp); + state_dict[PYBIND11_INTERNALS_ID] = capsule(reinterpret_cast(internals_pp)); internals_ptr->registered_exception_translators.push_front(&translate_exception); internals_ptr->static_property_type = make_static_property_type(); internals_ptr->default_metaclass = make_default_metaclass(); diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 4051b789c3..c270687853 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -432,7 +432,7 @@ PYBIND11_NOINLINE void instance::allocate_layout() { // NOLINTNEXTLINE(readability-make-member-function-const) PYBIND11_NOINLINE void instance::deallocate_layout() { if (!simple_layout) { - PyMem_Free(nonsimple.values_and_holders); + PyMem_Free(reinterpret_cast(nonsimple.values_and_holders)); } } diff --git a/include/pybind11/eigen/tensor.h b/include/pybind11/eigen/tensor.h index d4ed6c0ca8..14bb91c40f 100644 --- a/include/pybind11/eigen/tensor.h +++ b/include/pybind11/eigen/tensor.h @@ -469,9 +469,6 @@ struct type_caster, parent_object = reinterpret_borrow(parent); break; - case return_value_policy::take_ownership: - delete src; - // fallthrough default: // move, take_ownership don't make any sense for a ref/map: pybind11_fail("Invalid return_value_policy for Eigen Map type, must be either " diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 05ef3918b1..09894cf74f 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -901,7 +901,11 @@ class array : public buffer { template array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle()) - : array(pybind11::dtype::of(), std::move(shape), std::move(strides), ptr, base) {} + : array(pybind11::dtype::of(), + std::move(shape), + std::move(strides), + reinterpret_cast(ptr), + base) {} template array(ShapeContainer shape, const T *ptr, handle base = handle()) @@ -1986,7 +1990,7 @@ struct vectorize_helper { // Pointers to values the function was called with; the vectorized ones set here will start // out as array_t pointers, but they will be changed them to T pointers before we make // call the wrapped function. Non-vectorized pointers are left as-is. - std::array params{{&args...}}; + std::array params{{reinterpret_cast(&args)...}}; // The array of `buffer_info`s of vectorized arguments: std::array buffers{ diff --git a/include/pybind11/stl/filesystem.h b/include/pybind11/stl/filesystem.h index 85c131efe4..935d794815 100644 --- a/include/pybind11/stl/filesystem.h +++ b/include/pybind11/stl/filesystem.h @@ -33,6 +33,13 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) +#ifdef PYPY_VERSION +# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) (__VA_ARGS__) +#else +# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) \ + (reinterpret_cast(__VA_ARGS__)) +#endif + #if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) template struct path_caster { @@ -72,7 +79,8 @@ struct path_caster { } PyObject *native = nullptr; if constexpr (std::is_same_v) { - if (PyUnicode_FSConverter(buf, &native) != 0) { + if (PyUnicode_FSConverter(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native)) + != 0) { if (auto *c_str = PyBytes_AsString(native)) { // AsString returns a pointer to the internal buffer, which // must not be free'd. @@ -80,7 +88,8 @@ struct path_caster { } } } else if constexpr (std::is_same_v) { - if (PyUnicode_FSDecoder(buf, &native) != 0) { + if (PyUnicode_FSDecoder(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native)) + != 0) { if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) { // AsWideCharString returns a new string that must be free'd. value = c_str; // Copies the string. diff --git a/include/pybind11/stl_bind.h b/include/pybind11/stl_bind.h index a04e168645..15a9046de8 100644 --- a/include/pybind11/stl_bind.h +++ b/include/pybind11/stl_bind.h @@ -180,7 +180,7 @@ void vector_modifiers( v.end()); try { v.shrink_to_fit(); - } catch (const std::exception &) { + } catch (const std::exception &) { // NOLINT(bugprone-empty-catch) // Do nothing } throw; diff --git a/tests/constructor_stats.h b/tests/constructor_stats.h index 937f6c233b..9a5754fed9 100644 --- a/tests/constructor_stats.h +++ b/tests/constructor_stats.h @@ -190,7 +190,7 @@ class ConstructorStats { t1 = &p.first; } } - } catch (const std::out_of_range &) { + } catch (const std::out_of_range &) { // NOLINT(bugprone-empty-catch) } if (!t1) { throw std::runtime_error("Unknown class passed to ConstructorStats::get()"); diff --git a/tests/test_eigen_tensor.inl b/tests/test_eigen_tensor.inl index 25cf29f15b..3b3641e8d6 100644 --- a/tests/test_eigen_tensor.inl +++ b/tests/test_eigen_tensor.inl @@ -147,33 +147,39 @@ void init_tensor_module(pybind11::module &m) { m.def( "take_fixed_tensor", - []() { Eigen::aligned_allocator< Eigen::TensorFixedSize, Options>> allocator; - return new (allocator.allocate(1)) + static auto *obj = new (allocator.allocate(1)) Eigen::TensorFixedSize, Options>( get_fixed_tensor()); + return obj; // take_ownership will fail. }, py::return_value_policy::take_ownership); m.def( "take_tensor", - []() { return new Eigen::Tensor(get_tensor()); }, + []() { + static auto *obj = new Eigen::Tensor(get_tensor()); + return obj; // take_ownership will fail. + }, py::return_value_policy::take_ownership); m.def( "take_const_tensor", []() -> const Eigen::Tensor * { - return new Eigen::Tensor(get_tensor()); + static auto *obj = new Eigen::Tensor(get_tensor()); + return obj; // take_ownership will fail. }, py::return_value_policy::take_ownership); m.def( "take_view_tensor", []() -> const Eigen::TensorMap> * { - return new Eigen::TensorMap>(get_tensor()); + static auto *obj + = new Eigen::TensorMap>(get_tensor()); + return obj; // take_ownership will fail. }, py::return_value_policy::take_ownership); diff --git a/tests/test_modules.cpp b/tests/test_modules.cpp index 18a7ec74cc..7f01687c77 100644 --- a/tests/test_modules.cpp +++ b/tests/test_modules.cpp @@ -90,32 +90,32 @@ TEST_SUBMODULE(modules, m) { try { py::class_(dm, "Dupe1"); failures.append("Dupe1 class"); - } catch (std::runtime_error &) { + } catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch) } try { dm.def("Dupe1", []() { return Dupe1(); }); failures.append("Dupe1 function"); - } catch (std::runtime_error &) { + } catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch) } try { py::class_(dm, "dupe1_factory"); failures.append("dupe1_factory"); - } catch (std::runtime_error &) { + } catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch) } try { py::exception(dm, "Dupe2"); failures.append("Dupe2"); - } catch (std::runtime_error &) { + } catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch) } try { dm.def("DupeException", []() { return 30; }); failures.append("DupeException1"); - } catch (std::runtime_error &) { + } catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch) } try { py::class_(dm, "DupeException"); failures.append("DupeException2"); - } catch (std::runtime_error &) { + } catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch) } return failures; diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index ed77ec0246..596d902745 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -266,6 +266,8 @@ py::array_t test_array_ctors(int i) { return fill(arr_t(buf_ndim1_null)); case 44: return fill(py::array(buf_ndim1_null)); + default: + break; } return arr_t(); } diff --git a/tests/test_opaque_types.cpp b/tests/test_opaque_types.cpp index 0386dba03d..154d0a8d31 100644 --- a/tests/test_opaque_types.cpp +++ b/tests/test_opaque_types.cpp @@ -65,7 +65,7 @@ TEST_SUBMODULE(opaque_types, m) { m.def("return_unique_ptr", []() -> std::unique_ptr { auto *result = new StringList(); - result->push_back("some value"); + result->emplace_back("some value"); return std::unique_ptr(result); }); diff --git a/tests/test_tagbased_polymorphic.cpp b/tests/test_tagbased_polymorphic.cpp index 12ba6532f3..24b49021b4 100644 --- a/tests/test_tagbased_polymorphic.cpp +++ b/tests/test_tagbased_polymorphic.cpp @@ -74,6 +74,7 @@ std::vector> create_zoo() { // simulate some new type of Dog that the Python bindings // haven't been updated for; it should still be considered // a Dog, not just an Animal. + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) ret.emplace_back(new Dog("Ginger", Dog::Kind(150))); ret.emplace_back(new Chihuahua("Hertzl"));