mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-12 17:26:13 +00:00
Merge branch 'master' into smart_holder
This commit is contained in:
@@ -189,12 +189,10 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This must be a pybind11 instance
|
||||
auto *instance = reinterpret_cast<detail::instance *>(self);
|
||||
|
||||
// Ensure that the base __init__ function(s) were called
|
||||
for (const auto &vh : values_and_holders(instance)) {
|
||||
if (!vh.holder_constructed()) {
|
||||
values_and_holders vhs(self);
|
||||
for (const auto &vh : vhs) {
|
||||
if (!vh.holder_constructed() && !vhs.is_redundant_value_and_holder(vh)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s.__init__() must be called when overriding __init__",
|
||||
get_fully_qualified_tp_name(vh.type->type).c_str());
|
||||
|
||||
@@ -102,8 +102,22 @@ public:
|
||||
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
|
||||
all_type_info_get_cache(PyTypeObject *type);
|
||||
|
||||
// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
|
||||
inline void all_type_info_add_base_most_derived_first(std::vector<type_info *> &bases,
|
||||
type_info *addl_base) {
|
||||
for (auto it = bases.begin(); it != bases.end(); it++) {
|
||||
type_info *existing_base = *it;
|
||||
if (PyType_IsSubtype(addl_base->type, existing_base->type) != 0) {
|
||||
bases.insert(it, addl_base);
|
||||
return;
|
||||
}
|
||||
}
|
||||
bases.push_back(addl_base);
|
||||
}
|
||||
|
||||
// Populates a just-created cache entry.
|
||||
PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
|
||||
assert(bases.empty());
|
||||
std::vector<PyTypeObject *> check;
|
||||
for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) {
|
||||
check.push_back((PyTypeObject *) parent.ptr());
|
||||
@@ -136,7 +150,7 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
bases.push_back(tinfo);
|
||||
all_type_info_add_base_most_derived_first(bases, tinfo);
|
||||
}
|
||||
}
|
||||
} else if (type->tp_bases) {
|
||||
@@ -322,18 +336,29 @@ public:
|
||||
explicit values_and_holders(instance *inst)
|
||||
: inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
|
||||
|
||||
explicit values_and_holders(PyObject *obj)
|
||||
: inst{nullptr}, tinfo(all_type_info(Py_TYPE(obj))) {
|
||||
if (!tinfo.empty()) {
|
||||
inst = reinterpret_cast<instance *>(obj);
|
||||
}
|
||||
}
|
||||
|
||||
struct iterator {
|
||||
private:
|
||||
instance *inst = nullptr;
|
||||
const type_vec *types = nullptr;
|
||||
value_and_holder curr;
|
||||
friend struct values_and_holders;
|
||||
iterator(instance *inst, const type_vec *tinfo)
|
||||
: inst{inst}, types{tinfo},
|
||||
curr(inst /* instance */,
|
||||
types->empty() ? nullptr : (*types)[0] /* type info */,
|
||||
0, /* vpos: (non-simple types only): the first vptr comes first */
|
||||
0 /* index */) {}
|
||||
iterator(instance *inst, const type_vec *tinfo) : inst{inst}, types{tinfo} {
|
||||
if (inst != nullptr) {
|
||||
assert(!types->empty());
|
||||
curr = value_and_holder(
|
||||
inst /* instance */,
|
||||
(*types)[0] /* type info */,
|
||||
0, /* vpos: (non-simple types only): the first vptr comes first */
|
||||
0 /* index */);
|
||||
}
|
||||
}
|
||||
// Past-the-end iterator:
|
||||
explicit iterator(size_t end) : curr(end) {}
|
||||
|
||||
@@ -364,6 +389,16 @@ public:
|
||||
}
|
||||
|
||||
size_t size() { return tinfo.size(); }
|
||||
|
||||
// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
|
||||
bool is_redundant_value_and_holder(const value_and_holder &vh) {
|
||||
for (size_t i = 0; i < vh.index; i++) {
|
||||
if (PyType_IsSubtype(tinfo[i]->type, tinfo[vh.index]->type) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user