@@ -200,7 +200,8 @@ struct function_record {
200200// / Special data structure which (temporarily) holds metadata about a bound class
201201struct type_record {
202202 PYBIND11_NOINLINE type_record ()
203- : multiple_inheritance(false ), dynamic_attr(false ), buffer_protocol(false ), module_local(false ) { }
203+ : multiple_inheritance(false ), polymorphic(false ), dynamic_attr(false ),
204+ buffer_protocol(false ), module_local(false ) { }
204205
205206 // / Handle to the parent scope
206207 handle scope;
@@ -238,6 +239,9 @@ struct type_record {
238239 // / Multiple inheritance marker
239240 bool multiple_inheritance : 1 ;
240241
242+ // / Type is polymorphic in C++
243+ bool polymorphic : 1 ;
244+
241245 // / Does the class manage a __dict__?
242246 bool dynamic_attr : 1 ;
243247
@@ -250,6 +254,7 @@ struct type_record {
250254 // / Is the class definition local to the module shared object?
251255 bool module_local : 1 ;
252256
257+ // / Add a base as a template argument -- allows casting to base for non-simple types
253258 PYBIND11_NOINLINE void add_base (const std::type_info &base, void *(*caster)(void *)) {
254259 auto base_info = detail::get_type_info (base, false );
255260 if (!base_info) {
@@ -276,6 +281,24 @@ struct type_record {
276281 if (caster)
277282 base_info->implicit_casts .emplace_back (type, caster);
278283 }
284+
285+ // / Add a base as a runtime argument -- only for simple types
286+ PYBIND11_NOINLINE void add_base (handle base) {
287+ if (!base || !PyType_Check (base.ptr ()))
288+ pybind11_fail (" generic_type: type \" " + std::string (name) + " \" "
289+ " is trying to register a non-type object as a base" );
290+
291+ auto base_ptr = (PyTypeObject *) base.ptr ();
292+ auto base_info = detail::get_type_info (base_ptr);
293+ if (polymorphic != base_info->polymorphic ) {
294+ pybind11_fail (" generic_type: type \" " + std::string (name) + " \" is polymorphic, "
295+ " but its base \" " + std::string (base_ptr->tp_name ) + " \" is not. "
296+ " In this case, the base must be specified as a template argument: "
297+ " py::class_<T, Base>(...) instead of py::class_<T>(..., base)." );
298+ }
299+
300+ bases.append (base);
301+ }
279302};
280303
281304inline function_call::function_call (function_record &f, handle p) :
@@ -392,7 +415,7 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
392415// / Process a parent class attribute. Single inheritance only (class_ itself already guarantees that)
393416template <typename T>
394417struct process_attribute <T, enable_if_t <is_pyobject<T>::value>> : process_attribute_default<handle> {
395- static void init (const handle &h, type_record *r) { r->bases . append (h); }
418+ static void init (const handle &h, type_record *r) { r->add_base (h); }
396419};
397420
398421// / Process a parent class attribute (deprecated, does not support multiple inheritance)
0 commit comments