Skip to content

Commit c66eddc

Browse files
committed
Add many-inheritance test
This tests that multiple inheritance is working properly when it requires multiple blocks for holder-constructed flags (i.e. for a Python class that, through direct or indirect Python-side inheritance, inherits from more than `sizeof(void *)` registered classes).
1 parent 7734c82 commit c66eddc

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

tests/test_multiple_inheritance.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ struct Base2 {
2323
int i;
2424
};
2525

26+
template <int N> struct BaseN {
27+
BaseN(int i) : i(i) { }
28+
int i;
29+
};
30+
2631
struct Base12 : Base1, Base2 {
2732
Base12(int i, int j) : Base1(i), Base2(j) { }
2833
};
@@ -45,6 +50,15 @@ test_initializer multiple_inheritance([](py::module &m) {
4550
py::class_<MIType, Base12>(m, "MIType")
4651
.def(py::init<int, int>());
4752

53+
// Many bases for testing that multiple inheritance from many classes (i.e. requiring extra
54+
// space for holder constructed flags) works.
55+
#define PYBIND11_BASEN(N) py::class_<BaseN<N>>(m, "BaseN" #N).def(py::init<int>()).def("f" #N, [](BaseN<N> &b) { return b.i + N; })
56+
PYBIND11_BASEN( 1); PYBIND11_BASEN( 2); PYBIND11_BASEN( 3); PYBIND11_BASEN( 4);
57+
PYBIND11_BASEN( 5); PYBIND11_BASEN( 6); PYBIND11_BASEN( 7); PYBIND11_BASEN( 8);
58+
PYBIND11_BASEN( 9); PYBIND11_BASEN(10); PYBIND11_BASEN(11); PYBIND11_BASEN(12);
59+
PYBIND11_BASEN(13); PYBIND11_BASEN(14); PYBIND11_BASEN(15); PYBIND11_BASEN(16);
60+
PYBIND11_BASEN(17);
61+
4862
// Uncommenting this should result in a compile time failure (MI can only be specified via
4963
// template parameters because pybind has to know the types involved; see discussion in #742 for
5064
// details).

tests/test_multiple_inheritance.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,70 @@ def __init__(self, i):
159159
assert mi8b.bar() == 15
160160

161161

162+
def test_multiple_inheritance_python_many_bases():
163+
from pybind11_tests import (BaseN1, BaseN2, BaseN3, BaseN4, BaseN5, BaseN6, BaseN7,
164+
BaseN8, BaseN9, BaseN10, BaseN11, BaseN12, BaseN13, BaseN14,
165+
BaseN15, BaseN16, BaseN17)
166+
167+
class MIMany14(BaseN1, BaseN2, BaseN3, BaseN4):
168+
def __init__(self):
169+
BaseN1.__init__(self, 1)
170+
BaseN2.__init__(self, 2)
171+
BaseN3.__init__(self, 3)
172+
BaseN4.__init__(self, 4)
173+
174+
class MIMany58(BaseN5, BaseN6, BaseN7, BaseN8):
175+
def __init__(self):
176+
BaseN5.__init__(self, 5)
177+
BaseN6.__init__(self, 6)
178+
BaseN7.__init__(self, 7)
179+
BaseN8.__init__(self, 8)
180+
181+
class MIMany916(BaseN9, BaseN10, BaseN11, BaseN12, BaseN13, BaseN14, BaseN15, BaseN16):
182+
def __init__(self):
183+
BaseN9.__init__(self, 9)
184+
BaseN10.__init__(self, 10)
185+
BaseN11.__init__(self, 11)
186+
BaseN12.__init__(self, 12)
187+
BaseN13.__init__(self, 13)
188+
BaseN14.__init__(self, 14)
189+
BaseN15.__init__(self, 15)
190+
BaseN16.__init__(self, 16)
191+
192+
class MIMany19(MIMany14, MIMany58, BaseN9):
193+
def __init__(self):
194+
MIMany14.__init__(self)
195+
MIMany58.__init__(self)
196+
BaseN9.__init__(self, 9)
197+
198+
class MIMany117(MIMany14, MIMany58, MIMany916, BaseN17):
199+
def __init__(self):
200+
MIMany14.__init__(self)
201+
MIMany58.__init__(self)
202+
MIMany916.__init__(self)
203+
BaseN17.__init__(self, 17)
204+
205+
# Inherits from 4 registered C++ classes: can fit in one pointer on any modern arch:
206+
a = MIMany14()
207+
for i in range(1, 4):
208+
assert getattr(a, "f" + str(i))() == 2 * i
209+
210+
# Inherits from 8: requires 1/2 pointers worth of holder flags on 32/64-bit arch:
211+
b = MIMany916()
212+
for i in range(9, 16):
213+
assert getattr(b, "f" + str(i))() == 2 * i
214+
215+
# Inherits from 9: requires >= 2 pointers worth of holder flags
216+
c = MIMany19()
217+
for i in range(1, 9):
218+
assert getattr(c, "f" + str(i))() == 2 * i
219+
220+
# Inherits from 17: requires >= 3 pointers worth of holder flags
221+
d = MIMany117()
222+
for i in range(1, 17):
223+
assert getattr(d, "f" + str(i))() == 2 * i
224+
225+
162226
def test_multiple_inheritance_virtbase():
163227
from pybind11_tests import Base12a, bar_base2a, bar_base2a_sharedptr
164228

0 commit comments

Comments
 (0)