Skip to content
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

chore: clang-tidy upgrade (to version 18) #5272

Merged
merged 14 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,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 }}"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,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

Expand Down
2 changes: 1 addition & 1 deletion include/pybind11/detail/internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,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<void *>(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();
Expand Down
2 changes: 1 addition & 1 deletion include/pybind11/detail/type_caster_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,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<void *>(nonsimple.values_and_holders));
}
}

Expand Down
3 changes: 0 additions & 3 deletions include/pybind11/eigen/tensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,6 @@ struct type_caster<Eigen::TensorMap<Type, Options>,
parent_object = reinterpret_borrow<object>(parent);
break;

case return_value_policy::take_ownership:
delete src;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a bit of a change, wouldn't it have been causing a double delete somewhere?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a bit of a change, wouldn't it have been causing a double delete somewhere?

It's a change only superficially, but in reality it's more of a no-op:

Imagine someone writing new bindings and trying return_value_policy::take_ownership. The next thing they know, they get the exception from the // fallthrough below. The only thing that makes sense is to pick from the two accepted return value policies named in the exception.

Copy-pasting the commit 7bf9b82 message here for better visibility:

Fix inconsistent pybind11/eigen/tensor.h behavior:

This existing comment in pybind11/eigen/tensor.h

                // move, take_ownership don't make any sense for a ref/map:

is at odds with the delete src; three lines up.

In real-world client code take_ownership will not exist (unless the client code is untested and unused). I.e. the delete is essentially only useful to avoid leaks in the pybind11 unit tests.

While upgrading to clang-tidy 18, the warning below appeared. Apparently it is produced during LTO, and it appears difficult to suppress. Regardless, the best way to resolve this is to remove the delete and to simply make the test objects static in the unit test code.

lto-wrapper: warning: using serial compilation of 3 LTRANS jobs
lto-wrapper: note: see the ‘-flto’ option documentation for more information
In function ‘cast_impl’,
    inlined from ‘cast’ at /mounted_pybind11/include/pybind11/eigen/tensor.h:414:25,
    inlined from ‘operator()’ at /mounted_pybind11/include/pybind11/eigen/../pybind11.h:296:40,
    inlined from ‘_FUN’ at /mounted_pybind11/include/pybind11/eigen/../pybind11.h:267:21:
/mounted_pybind11/include/pybind11/eigen/tensor.h:475:17: warning: ‘operator delete’ called on unallocated object ‘<anonymous>’ [-Wfree-nonheap-object]
  475 |                 delete src;
      |                 ^
/mounted_pybind11/include/pybind11/eigen/../pybind11.h: In function ‘_FUN’:
/mounted_pybind11/include/pybind11/eigen/../pybind11.h:297:75: note: declared here
  297 |                     std::move(args_converter).template call<Return, Guard>(cap->f),
      |                                                                           ^

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, okay.

// 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 "
Expand Down
8 changes: 6 additions & 2 deletions include/pybind11/numpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,11 @@ class array : public buffer {

template <typename T>
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
: array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) {}
: array(pybind11::dtype::of<T>(),
std::move(shape),
std::move(strides),
reinterpret_cast<const void *>(ptr),
base) {}

template <typename T>
array(ShapeContainer shape, const T *ptr, handle base = handle())
Expand Down Expand Up @@ -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<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<void *, N> params{{&args...}};
std::array<void *, N> params{{reinterpret_cast<void *>(&args)...}};

// The array of `buffer_info`s of vectorized arguments:
std::array<buffer_info, NVectorized> buffers{
Expand Down
13 changes: 11 additions & 2 deletions include/pybind11/stl/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<void *>(__VA_ARGS__))
#endif

#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
template <typename T>
struct path_caster {
Expand Down Expand Up @@ -72,15 +79,17 @@ struct path_caster {
}
PyObject *native = nullptr;
if constexpr (std::is_same_v<typename T::value_type, char>) {
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.
value = c_str;
}
}
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
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.
Expand Down
2 changes: 1 addition & 1 deletion include/pybind11/stl_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion tests/constructor_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()");
Expand Down
16 changes: 11 additions & 5 deletions tests/test_eigen_tensor.inl
Original file line number Diff line number Diff line change
Expand Up @@ -147,33 +147,39 @@ void init_tensor_module(pybind11::module &m) {

m.def(
"take_fixed_tensor",

[]() {
Eigen::aligned_allocator<
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>
allocator;
return new (allocator.allocate(1))
static auto *obj = new (allocator.allocate(1))
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>(
get_fixed_tensor<Options>());
return obj; // take_ownership will fail.
},
py::return_value_policy::take_ownership);

m.def(
"take_tensor",
[]() { return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>()); },
[]() {
static auto *obj = new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
return obj; // take_ownership will fail.
},
py::return_value_policy::take_ownership);

m.def(
"take_const_tensor",
[]() -> const Eigen::Tensor<double, 3, Options> * {
return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
static auto *obj = new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
return obj; // take_ownership will fail.
},
py::return_value_policy::take_ownership);

m.def(
"take_view_tensor",
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
return new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
static auto *obj
= new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
return obj; // take_ownership will fail.
},
py::return_value_policy::take_ownership);

Expand Down
12 changes: 6 additions & 6 deletions tests/test_modules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,32 +90,32 @@ TEST_SUBMODULE(modules, m) {
try {
py::class_<Dupe1>(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_<Dupe3>(dm, "dupe1_factory");
failures.append("dupe1_factory");
} catch (std::runtime_error &) {
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
}
try {
py::exception<Dupe3>(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_<DupeException>(dm, "DupeException");
failures.append("DupeException2");
} catch (std::runtime_error &) {
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
}

return failures;
Expand Down
2 changes: 2 additions & 0 deletions tests/test_numpy_dtypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ py::array_t<int32_t, 0> 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();
}
Expand Down
2 changes: 1 addition & 1 deletion tests/test_opaque_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ TEST_SUBMODULE(opaque_types, m) {

m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> {
auto *result = new StringList();
result->push_back("some value");
result->emplace_back("some value");
return std::unique_ptr<StringList>(result);
});

Expand Down
1 change: 1 addition & 0 deletions tests/test_tagbased_polymorphic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ std::vector<std::unique_ptr<Animal>> 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"));
Expand Down