Skip to content

Commit 30eb39e

Browse files
fix: also throw in the move-constructor added by the PYBIND11_OBJECT macro, after the argument has been moved-out (if necessary) (#2701)
1 parent d9fa705 commit 30eb39e

File tree

3 files changed

+19
-14
lines changed

3 files changed

+19
-14
lines changed

include/pybind11/pytypes.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -812,18 +812,18 @@ PYBIND11_NAMESPACE_END(detail)
812812
: Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
813813
{ if (!m_ptr) throw error_already_set(); }
814814

815-
#define PYBIND11_OBJECT_CHECK_FAILED(Name, o) \
815+
#define PYBIND11_OBJECT_CHECK_FAILED(Name, o_ptr) \
816816
::pybind11::type_error("Object of type '" + \
817-
::pybind11::detail::get_fully_qualified_tp_name(Py_TYPE(o.ptr())) + \
817+
::pybind11::detail::get_fully_qualified_tp_name(Py_TYPE(o_ptr)) + \
818818
"' is not an instance of '" #Name "'")
819819

820820
#define PYBIND11_OBJECT(Name, Parent, CheckFun) \
821821
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
822822
/* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
823823
Name(const object &o) : Parent(o) \
824-
{ if (o && !check_(o)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, o); } \
824+
{ if (m_ptr && !check_(m_ptr)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); } \
825825
Name(object &&o) : Parent(std::move(o)) \
826-
{ if (o && !check_(o)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, o); }
826+
{ if (m_ptr && !check_(m_ptr)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); }
827827

828828
#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \
829829
PYBIND11_OBJECT(Name, Parent, CheckFun) \

tests/test_pytypes.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -254,15 +254,18 @@ TEST_SUBMODULE(pytypes, m) {
254254

255255
m.def("convert_to_pybind11_str", [](py::object o) { return py::str(o); });
256256

257-
m.def("nonconverting_constructor", [](std::string type, py::object value) -> py::object {
257+
m.def("nonconverting_constructor", [](std::string type, py::object value, bool move) -> py::object {
258258
if (type == "bytes") {
259-
return py::bytes(value);
259+
return move ? py::bytes(std::move(value)) : py::bytes(value);
260260
}
261261
else if (type == "none") {
262-
return py::none(value);
262+
return move ? py::none(std::move(value)) : py::none(value);
263263
}
264264
else if (type == "ellipsis") {
265-
return py::ellipsis(value);
265+
return move ? py::ellipsis(std::move(value)) : py::ellipsis(value);
266+
}
267+
else if (type == "type") {
268+
return move ? py::type(std::move(value)) : py::type(value);
266269
}
267270
throw std::runtime_error("Invalid type");
268271
});

tests/test_pytypes.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,16 @@ def test_non_converting_constructors():
268268
("bytes", range(10)),
269269
("none", 42),
270270
("ellipsis", 42),
271+
("type", 42),
271272
]
272273
for t, v in non_converting_test_cases:
273-
with pytest.raises(TypeError) as excinfo:
274-
m.nonconverting_constructor(t, v)
275-
expected_error = "Object of type '{}' is not an instance of '{}'".format(
276-
type(v).__name__, t
277-
)
278-
assert str(excinfo.value) == expected_error
274+
for move in [True, False]:
275+
with pytest.raises(TypeError) as excinfo:
276+
m.nonconverting_constructor(t, v, move)
277+
expected_error = "Object of type '{}' is not an instance of '{}'".format(
278+
type(v).__name__, t
279+
)
280+
assert str(excinfo.value) == expected_error
279281

280282

281283
def test_pybind11_str_raw_str():

0 commit comments

Comments
 (0)