@@ -1286,7 +1286,7 @@ inline bool gil_not_used_option(mod_gil_not_used f, O &&...o) {
12861286}
12871287template <typename F, typename ... O>
12881288inline bool gil_not_used_option (F &&, O &&...o ) {
1289- return false || gil_not_used_option (o...);
1289+ return gil_not_used_option (o...);
12901290}
12911291
12921292#ifdef Py_mod_multiple_interpreters
@@ -1453,52 +1453,60 @@ class module_ : public object {
14531453 return reinterpret_borrow<module_>(m);
14541454 }
14551455
1456+ // / Must be a POD type, and must hold enough entries for all of the possible slots PLUS ONE for
1457+ // / the sentinel (0) end slot.
1458+ using slots_array = std::array<PyModuleDef_Slot, 5 >;
1459+
14561460 /* * \rst
14571461 Initialized a module def for use with multi-phase module initialization.
14581462
14591463 ``def`` should point to a statically allocated module_def.
1460- ``slots`` must point to an initialized array of slots with space for at
1461- least two additional slots to be populated based on the options .
1464+ ``slots`` must already contain a Py_mod_exec or Py_mod_create slot and will be filled with
1465+ additional slots from the supplied options (and the empty sentinel slot) .
14621466 \endrst */
14631467 template <typename ... Options>
1464- static object init_module_def (const char *name,
1465- const char *doc,
1466- module_def *def,
1467- PyModuleDef_Slot *slots,
1468- Options &&...options) {
1469- int i = 0 ;
1470- while (slots[i].slot != 0 ) {
1471- ++i;
1468+ static object initialize_multiphase_module_def (const char *name,
1469+ const char *doc,
1470+ module_def *def,
1471+ slots_array &slots,
1472+ Options &&...options) {
1473+ size_t next_slot = 0 ;
1474+ size_t term_slot = slots.size () - 1 ;
1475+
1476+ // find the end of the supplied slots
1477+ while (next_slot < term_slot && slots[next_slot].slot != 0 ) {
1478+ ++next_slot;
14721479 }
14731480
14741481 bool nogil PYBIND11_MAYBE_UNUSED = detail::gil_not_used_option (options...);
1482+ if (nogil) {
1483+ #if defined(Py_mod_gil) && defined(Py_GIL_DISABLED)
1484+ if (next_slot >= term_slot) {
1485+ pybind11_fail (" initialize_multiphase_module_def: not enough space in slots" );
1486+ }
1487+ slots[next_slot++] = {Py_mod_gil, Py_MOD_GIL_NOT_USED};
1488+ #endif
1489+ }
14751490
14761491#ifdef Py_mod_multiple_interpreters
1477- slots[i].slot = Py_mod_multiple_interpreters;
1478- slots[i].value = detail::multi_interp_option (options...);
1479- if (nogil && slots[i].value == Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED) {
1492+ auto mi_opt = detail::multi_interp_option (options...);
1493+ if (nogil && mi_opt == Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED) {
14801494 // if you support free threading and multi-interpreters,
14811495 // then you definitely also support per-interpreter GIL
14821496 // even if you don't know it.
1483- slots[i]. value = Py_MOD_PER_INTERPRETER_GIL_SUPPORTED;
1497+ mi_opt = Py_MOD_PER_INTERPRETER_GIL_SUPPORTED;
14841498 }
1485- ++i;
1499+ if (next_slot >= term_slot) {
1500+ pybind11_fail (" initialize_multiphase_module_def: not enough space in slots" );
1501+ }
1502+ slots[next_slot++] = {Py_mod_multiple_interpreters, mi_opt};
14861503#endif
14871504
1488- if (nogil) {
1489- #ifdef Py_mod_gil
1490- slots[i].slot = Py_mod_gil;
1491- # ifdef Py_GIL_DISABLED
1492- slots[i].value = Py_MOD_GIL_NOT_USED;
1493- # else
1494- slots[i].value = Py_MOD_GIL_USED;
1495- # endif
1496- ++i;
1497- #endif
1505+ // slots must have a zero end sentinel
1506+ if (next_slot > term_slot) {
1507+ pybind11_fail (" initialize_multiphase_module_def: not enough space in slots" );
14981508 }
1499-
1500- slots[i].slot = 0 ;
1501- slots[i].value = nullptr ;
1509+ slots[next_slot++] = {0 , nullptr };
15021510
15031511 // module_def is PyModuleDef
15041512 // Placement new (not an allocation).
@@ -1508,7 +1516,7 @@ class module_ : public object {
15081516 /* m_doc */ options::show_user_defined_docstrings () ? doc : nullptr ,
15091517 /* m_size */ 0 ,
15101518 /* m_methods */ nullptr ,
1511- /* m_slots */ slots,
1519+ /* m_slots */ & slots[ 0 ] ,
15121520 /* m_traverse */ nullptr ,
15131521 /* m_clear */ nullptr ,
15141522 /* m_free */ nullptr };
@@ -1517,7 +1525,7 @@ class module_ : public object {
15171525 if (PyErr_Occurred ()) {
15181526 throw error_already_set ();
15191527 }
1520- pybind11_fail (" Internal error in module_::init_module_def ()" );
1528+ pybind11_fail (" Internal error in module_::initialize_multiphase_module_def ()" );
15211529 }
15221530 return reinterpret_borrow<object>(m);
15231531 }
0 commit comments