mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-21 20:55:11 +00:00
parent
15f36d2b2d
commit
8ed5b8ab55
@ -585,6 +585,10 @@ Python side:
|
||||
Implicit conversions from ``A`` to ``B`` only work when ``B`` is a custom
|
||||
data type that is exposed to Python via pybind11.
|
||||
|
||||
To prevent runaway recursion, implicit conversions are non-reentrant: an
|
||||
implicit conversion invoked as part of another implicit conversion of the
|
||||
same type (i.e. from ``A`` to ``B``) will fail.
|
||||
|
||||
.. _static_properties:
|
||||
|
||||
Static properties
|
||||
|
@ -1536,7 +1536,16 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||
}
|
||||
|
||||
template <typename InputType, typename OutputType> void implicitly_convertible() {
|
||||
struct set_flag {
|
||||
bool &flag;
|
||||
set_flag(bool &flag) : flag(flag) { flag = true; }
|
||||
~set_flag() { flag = false; }
|
||||
};
|
||||
auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {
|
||||
static bool currently_used = false;
|
||||
if (currently_used) // implicit conversions are non-reentrant
|
||||
return nullptr;
|
||||
set_flag flag_helper(currently_used);
|
||||
if (!detail::make_caster<InputType>().load(obj, false))
|
||||
return nullptr;
|
||||
tuple args(1);
|
||||
|
@ -291,6 +291,17 @@ TEST_SUBMODULE(class_, m) {
|
||||
.def(py::init<int, const std::string &>())
|
||||
.def_readwrite("field1", &BraceInitialization::field1)
|
||||
.def_readwrite("field2", &BraceInitialization::field2);
|
||||
|
||||
// test_reentrant_implicit_conversion_failure
|
||||
// #1035: issue with runaway reentrant implicit conversion
|
||||
struct BogusImplicitConversion {
|
||||
BogusImplicitConversion(const BogusImplicitConversion &) { }
|
||||
};
|
||||
|
||||
py::class_<BogusImplicitConversion>(m, "BogusImplicitConversion")
|
||||
.def(py::init<const BogusImplicitConversion &>());
|
||||
|
||||
py::implicitly_convertible<int, BogusImplicitConversion>();
|
||||
}
|
||||
|
||||
template <int N> class BreaksBase { public: virtual ~BreaksBase() = default; };
|
||||
|
@ -223,3 +223,13 @@ def test_class_refcount():
|
||||
|
||||
assert refcount_1 == refcount_3
|
||||
assert refcount_2 > refcount_1
|
||||
|
||||
|
||||
def test_reentrant_implicit_conversion_failure(msg):
|
||||
# ensure that there is no runaway reentrant implicit conversion (#1035)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.BogusImplicitConversion(0)
|
||||
assert msg(excinfo.value) == '''__init__(): incompatible constructor arguments. The following argument types are supported:
|
||||
1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
|
||||
|
||||
Invoked with: 0'''
|
||||
|
Loading…
Reference in New Issue
Block a user