Skip to content

Commit a406a62

Browse files
authored
fix: use std::addressof in type_caster_base.h (#5189)
* Add tests only. Fails to build with this error message: ``` g++ -o pybind11/tests/test_copy_move.os -c -std=c++17 -fPIC -fvisibility=hidden -O0 -g -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated -Wundef -Wnon-virtual-dtor -Wunused-result -Werror -isystem /usr/include/python3.11 -isystem /usr/include/eigen3 -DPYBIND11_STRICT_ASSERTS_CLASS_HOLDER_VS_TYPE_CASTER_MIX -DPYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD_IF_AVAILABLE -DPYBIND11_TEST_BOOST -DPYBIND11_INTERNALS_VERSION=10000000 -Ipybind11/include -I/usr/local/google/home/rwgk/forked/pybind11/include -I/usr/local/google/home/rwgk/clone/pybind11/include /usr/local/google/home/rwgk/forked/pybind11/tests/test_copy_move.cpp In file included from /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../cast.h:15, from /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../attr.h:14, from /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/class.h:12, from /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/pybind11.h:13, from /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/stl.h:12, from /usr/local/google/home/rwgk/forked/pybind11/tests/test_copy_move.cpp:11: /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h: In instantiation of ‘static pybind11::handle pybind11::detail::type_caster_base<type>::cast(const itype&, pybind11::return_value_policy, pybind11::handle) [with type = UnusualOpRef; itype = UnusualOpRef]’: /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../cast.h:1230:37: required from ‘pybind11::object pybind11::cast(T&&, return_value_policy, handle) [with T = const UnusualOpRef&; typename std::enable_if<(! std::is_base_of<detail::pyobject_tag, typename std::remove_reference<_Tp>::type>::value), int>::type <anonymous> = 0]’ /usr/local/google/home/rwgk/forked/pybind11/tests/test_copy_move.cpp:162:80: required from here /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1110:20: error: no matching function for call to ‘pybind11::detail::type_caster_base<UnusualOpRef>::cast(const UnusualOpRef::NonTrivialType, pybind11::return_value_policy&, pybind11::handle&)’ 1110 | return cast(&src, policy, parent); | ~~~~^~~~~~~~~~~~~~~~~~~~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1105:19: note: candidate: ‘static pybind11::handle pybind11::detail::type_caster_base<type>::cast(const itype&, pybind11::return_value_policy, pybind11::handle) [with type = UnusualOpRef; itype = UnusualOpRef]’ 1105 | static handle cast(const itype &src, return_value_policy policy, handle parent) { | ^~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1105:37: note: no known conversion for argument 1 from ‘const UnusualOpRef::NonTrivialType’ {aka ‘const std::shared_ptr<int>’} to ‘const pybind11::detail::type_caster_base<UnusualOpRef>::itype&’ {aka ‘const UnusualOpRef&’} 1105 | static handle cast(const itype &src, return_value_policy policy, handle parent) { | ~~~~~~~~~~~~~^~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1113:19: note: candidate: ‘static pybind11::handle pybind11::detail::type_caster_base<type>::cast(itype&&, pybind11::return_value_policy, pybind11::handle) [with type = UnusualOpRef; itype = UnusualOpRef]’ 1113 | static handle cast(itype &&src, return_value_policy, handle parent) { | ^~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1113:32: note: no known conversion for argument 1 from ‘const UnusualOpRef::NonTrivialType’ {aka ‘const std::shared_ptr<int>’} to ‘pybind11::detail::type_caster_base<UnusualOpRef>::itype&&’ {aka ‘UnusualOpRef&&’} 1113 | static handle cast(itype &&src, return_value_policy, handle parent) { | ~~~~~~~~^~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1142:19: note: candidate: ‘static pybind11::handle pybind11::detail::type_caster_base<type>::cast(const itype*, pybind11::return_value_policy, pybind11::handle) [with type = UnusualOpRef; itype = UnusualOpRef]’ 1142 | static handle cast(const itype *src, return_value_policy policy, handle parent) { | ^~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1142:37: note: no known conversion for argument 1 from ‘const UnusualOpRef::NonTrivialType’ {aka ‘const std::shared_ptr<int>’} to ‘const pybind11::detail::type_caster_base<UnusualOpRef>::itype*’ {aka ‘const UnusualOpRef*’} 1142 | static handle cast(const itype *src, return_value_policy policy, handle parent) { | ~~~~~~~~~~~~~^~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h: In instantiation of ‘static pybind11::handle pybind11::detail::type_caster_base<type>::cast(itype&&, pybind11::return_value_policy, pybind11::handle) [with type = UnusualOpRef; itype = UnusualOpRef]’: /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../cast.h:1230:37: required from ‘pybind11::object pybind11::cast(T&&, return_value_policy, handle) [with T = UnusualOpRef; typename std::enable_if<(! std::is_base_of<detail::pyobject_tag, typename std::remove_reference<_Tp>::type>::value), int>::type <anonymous> = 0]’ /usr/local/google/home/rwgk/forked/pybind11/tests/test_copy_move.cpp:163:74: required from here /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1114:20: error: no matching function for call to ‘pybind11::detail::type_caster_base<UnusualOpRef>::cast(UnusualOpRef::NonTrivialType, pybind11::return_value_policy, pybind11::handle&)’ 1114 | return cast(&src, return_value_policy::move, parent); | ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1105:19: note: candidate: ‘static pybind11::handle pybind11::detail::type_caster_base<type>::cast(const itype&, pybind11::return_value_policy, pybind11::handle) [with type = UnusualOpRef; itype = UnusualOpRef]’ 1105 | static handle cast(const itype &src, return_value_policy policy, handle parent) { | ^~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1105:37: note: no known conversion for argument 1 from ‘UnusualOpRef::NonTrivialType’ {aka ‘std::shared_ptr<int>’} to ‘const pybind11::detail::type_caster_base<UnusualOpRef>::itype&’ {aka ‘const UnusualOpRef&’} 1105 | static handle cast(const itype &src, return_value_policy policy, handle parent) { | ~~~~~~~~~~~~~^~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1113:19: note: candidate: ‘static pybind11::handle pybind11::detail::type_caster_base<type>::cast(itype&&, pybind11::return_value_policy, pybind11::handle) [with type = UnusualOpRef; itype = UnusualOpRef]’ 1113 | static handle cast(itype &&src, return_value_policy, handle parent) { | ^~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1113:32: note: no known conversion for argument 1 from ‘UnusualOpRef::NonTrivialType’ {aka ‘std::shared_ptr<int>’} to ‘pybind11::detail::type_caster_base<UnusualOpRef>::itype&&’ {aka ‘UnusualOpRef&&’} 1113 | static handle cast(itype &&src, return_value_policy, handle parent) { | ~~~~~~~~^~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1142:19: note: candidate: ‘static pybind11::handle pybind11::detail::type_caster_base<type>::cast(const itype*, pybind11::return_value_policy, pybind11::handle) [with type = UnusualOpRef; itype = UnusualOpRef]’ 1142 | static handle cast(const itype *src, return_value_policy policy, handle parent) { | ^~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../detail/type_caster_base.h:1142:37: note: no known conversion for argument 1 from ‘UnusualOpRef::NonTrivialType’ {aka ‘std::shared_ptr<int>’} to ‘const pybind11::detail::type_caster_base<UnusualOpRef>::itype*’ {aka ‘const UnusualOpRef*’} 1142 | static handle cast(const itype *src, return_value_policy policy, handle parent) { | ~~~~~~~~~~~~~^~~ ``` * Replace `&src` with `std::addressof(src)` to fix the error building the added tests. * Fix accident (not sure how the `const` slipped in here when transferring the diff from pybind11k).
1 parent f1a2e03 commit a406a62

File tree

4 files changed

+33
-2
lines changed

4 files changed

+33
-2
lines changed

include/pybind11/detail/type_caster_base.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,11 +1107,11 @@ class type_caster_base : public type_caster_generic {
11071107
|| policy == return_value_policy::automatic_reference) {
11081108
policy = return_value_policy::copy;
11091109
}
1110-
return cast(&src, policy, parent);
1110+
return cast(std::addressof(src), policy, parent);
11111111
}
11121112

11131113
static handle cast(itype &&src, return_value_policy, handle parent) {
1114-
return cast(&src, return_value_policy::move, parent);
1114+
return cast(std::addressof(src), return_value_policy::move, parent);
11151115
}
11161116

11171117
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a

tests/pybind11_tests.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <pybind11/eval.h>
44
#include <pybind11/pybind11.h>
55

6+
#include <memory>
7+
68
namespace py = pybind11;
79
using namespace pybind11::literals;
810

@@ -52,6 +54,17 @@ union IntFloat {
5254
float f;
5355
};
5456

57+
class UnusualOpRef {
58+
public:
59+
using NonTrivialType = std::shared_ptr<int>; // Almost any non-trivial type will do.
60+
// Overriding operator& should not break pybind11.
61+
NonTrivialType operator&() { return non_trivial_member; }
62+
NonTrivialType operator&() const { return non_trivial_member; }
63+
64+
private:
65+
NonTrivialType non_trivial_member;
66+
};
67+
5568
/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast
5669
/// context. Used to test recursive casters (e.g. std::tuple, stl containers).
5770
struct RValueCaster {};

tests/test_copy_move.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,13 @@ struct type_caster<CopyOnlyInt> {
157157
PYBIND11_NAMESPACE_END(detail)
158158
PYBIND11_NAMESPACE_END(pybind11)
159159

160+
namespace {
161+
162+
py::object CastUnusualOpRefConstRef(const UnusualOpRef &cref) { return py::cast(cref); }
163+
py::object CastUnusualOpRefMovable(UnusualOpRef &&mvbl) { return py::cast(std::move(mvbl)); }
164+
165+
} // namespace
166+
160167
TEST_SUBMODULE(copy_move_policies, m) {
161168
// test_lacking_copy_ctor
162169
py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
@@ -293,6 +300,11 @@ TEST_SUBMODULE(copy_move_policies, m) {
293300

294301
// Make sure that cast from pytype rvalue to other pytype works
295302
m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast<py::int_>(); });
303+
304+
py::class_<UnusualOpRef>(m, "UnusualOpRef");
305+
m.def("CallCastUnusualOpRefConstRef",
306+
[]() { return CastUnusualOpRefConstRef(UnusualOpRef()); });
307+
m.def("CallCastUnusualOpRefMovable", []() { return CastUnusualOpRefMovable(UnusualOpRef()); });
296308
}
297309

298310
/*

tests/test_copy_move.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,9 @@ def test_pytype_rvalue_cast():
132132

133133
value = m.get_pytype_rvalue_castissue(1.0)
134134
assert value == 1
135+
136+
137+
def test_unusual_op_ref():
138+
# Merely to test that this still exists and built successfully.
139+
assert m.CallCastUnusualOpRefConstRef().__class__.__name__ == "UnusualOpRef"
140+
assert m.CallCastUnusualOpRefMovable().__class__.__name__ == "UnusualOpRef"

0 commit comments

Comments
 (0)