From 3a8d92308d3291e21c55baca8aa7b8dd5b3a8d56 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 31 Jan 2022 12:19:48 -0500 Subject: [PATCH] Fix caster optimization regression introduced in #3650 (#3659) * Fix optimization bug introduced in #3650 * Add simple Python extension test for MVF * Improve comments * Clarify comment * Clarify another comment * Add test docstring * Fix typo --- include/pybind11/detail/internals.h | 4 +++- include/pybind11/pybind11.h | 11 ++++++----- tests/test_multiple_inheritance.cpp | 2 +- tests/test_multiple_inheritance.py | 22 ++++++++++++++++++++++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 5c11b40a4..9edb9492e 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -200,7 +200,9 @@ struct type_info { void *get_buffer_data = nullptr; void *(*module_local_load)(PyObject *, const type_info *) = nullptr; /* A simple type never occurs as a (direct or indirect) parent - * of a class that makes use of multiple inheritance */ + * of a class that makes use of multiple inheritance. + * A type can be simple even if it has non-simple ancestors as long as it has no descendants. + */ bool simple_type : 1; /* True if there is no multiple inheritance in this type's inheritance tree */ bool simple_ancestors : 1; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index df33d5182..fd60ea29f 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1206,13 +1206,14 @@ protected: if (rec.bases.size() > 1 || rec.multiple_inheritance) { mark_parents_nonsimple(tinfo->type); tinfo->simple_ancestors = false; - tinfo->simple_type = false; } else if (rec.bases.size() == 1) { - auto parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr()); - tinfo->simple_ancestors = parent_tinfo->simple_ancestors; - // a child of a non-simple type can never be a simple type - tinfo->simple_type = parent_tinfo->simple_type; + auto *parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr()); + assert(parent_tinfo != nullptr); + bool parent_simple_ancestors = parent_tinfo->simple_ancestors; + tinfo->simple_ancestors = parent_simple_ancestors; + // The parent can no longer be a simple type if it has MI and has a child + parent_tinfo->simple_type = parent_tinfo->simple_type && parent_simple_ancestors; } if (rec.module_local) { diff --git a/tests/test_multiple_inheritance.cpp b/tests/test_multiple_inheritance.cpp index 44b9876eb..4689df4e4 100644 --- a/tests/test_multiple_inheritance.cpp +++ b/tests/test_multiple_inheritance.cpp @@ -235,7 +235,7 @@ TEST_SUBMODULE(multiple_inheritance, m) { // - functions are get_{base}_{var}, return {var} struct MVB { MVB() = default; - MVB(const MVB&) = default; + MVB(const MVB &) = default; virtual ~MVB() = default; int b = 1; diff --git a/tests/test_multiple_inheritance.py b/tests/test_multiple_inheritance.py index 71741b925..abdf25d60 100644 --- a/tests/test_multiple_inheritance.py +++ b/tests/test_multiple_inheritance.py @@ -472,3 +472,25 @@ def test_pr3635_diamond_f(): assert o.get_f_e() == 5 assert o.get_f_f() == 6 + + +def test_python_inherit_from_mi(): + """Tests extending a Python class from a single inheritor of a MI class""" + + class PyMVF(m.MVF): + g = 7 + + def get_g_g(self): + return self.g + + o = PyMVF() + + assert o.b == 1 + assert o.c == 2 + assert o.d0 == 3 + assert o.d1 == 4 + assert o.e == 5 + assert o.f == 6 + assert o.g == 7 + + assert o.get_g_g() == 7