@@ -20,7 +20,10 @@ NAMESPACE_BEGIN(detail)
2020// nanobind exception translator that wraps a foreign one
2121static void foreign_exception_translator(const std::exception_ptr &p,
2222 void *payload) {
23- ((pymb_framework *) payload)->translate_exception (&p);
23+ std::exception_ptr e = p;
24+ int translated = ((pymb_framework *) payload)->translate_exception (&e);
25+ if (!translated)
26+ std::rethrow_exception (e);
2427}
2528
2629// When learning about a new foreign type, should we automatically use it?
@@ -50,6 +53,8 @@ static void *nb_foreign_from_python(pymb_binding *binding,
5053 convert ? uint8_t (cast_flags::convert) : 0 ,
5154 keep_referenced ? &cleanup : nullptr , &result);
5255 if (keep_referenced) {
56+ // Move temporary references from our `cleanup_list` to our caller's
57+ // equivalent.
5358 for (uint32_t idx = 1 ; idx < cleanup.size (); ++idx)
5459 keep_referenced (keep_referenced_ctx, cleanup[idx]);
5560 if (cleanup.size () > 1 )
@@ -65,8 +70,12 @@ static PyObject *nb_foreign_to_python(pymb_binding *binding,
6570 cleanup_list cleanup{parent};
6671 auto *td = (type_data *) binding->context ;
6772 rv_policy rvp = (rv_policy) rvp_;
68- if (rvp > rv_policy::none)
73+ if (rvp < rv_policy::take_ownership || rvp > rv_policy::none) {
74+ // Future-proofing in case additional pymb_rv_policies are defined
75+ // later: if we don't recognize this policy, then refuse the cast
76+ // unless a pyobject wrapper already exists.
6977 rvp = rv_policy::none;
78+ }
7079 return nb_type_put (td->type , cobj, rvp, &cleanup, nullptr );
7180}
7281
@@ -85,8 +94,8 @@ static int nb_foreign_keep_alive(PyObject *nurse,
8594 }
8695}
8796
88- static void nb_foreign_translate_exception (const void *eptr) {
89- std::exception_ptr e = *(const std::exception_ptr *) eptr;
97+ static int nb_foreign_translate_exception (void *eptr) noexcept {
98+ std::exception_ptr & e = *(std::exception_ptr *) eptr;
9099
91100 // Skip the default translator (at the end of the list). It translates
92101 // generic STL exceptions which other frameworks might want to translate
@@ -102,7 +111,7 @@ static void nb_foreign_translate_exception(const void *eptr) {
102111 }
103112 try {
104113 cur->translator (e, cur->payload );
105- return ;
114+ return 1 ;
106115 } catch (...) { e = std::current_exception (); }
107116 }
108117
@@ -115,8 +124,8 @@ static void nb_foreign_translate_exception(const void *eptr) {
115124 if (!set_builtin_exception_status (e))
116125 PyErr_SetString (PyExc_SystemError, " foreign function threw "
117126 " nanobind::next_overload()" );
118- }
119- // Anything not caught by the above bubbles out.
127+ } catch (...) { e = std::current_exception (); }
128+ return 0 ;
120129}
121130
122131static void nb_foreign_add_foreign_binding (pymb_binding *binding) noexcept {
@@ -188,17 +197,21 @@ static void nb_foreign_remove_foreign_binding(pymb_binding *binding) noexcept {
188197
189198static void nb_foreign_add_foreign_framework (pymb_framework *framework)
190199 noexcept {
191- if (framework->translate_exception ) {
200+ if (framework->translate_exception &&
201+ framework->abi_lang == pymb_abi_lang_cpp) {
202+ decltype (&foreign_exception_translator) translator_to_use;
192203 {
193204 lock_internals guard{internals};
194205 if (!internals->foreign_exception_translator )
195206 internals->foreign_exception_translator =
196207 foreign_exception_translator;
208+ translator_to_use = internals->foreign_exception_translator ;
197209 }
198- register_exception_translator (internals-> foreign_exception_translator ,
210+ register_exception_translator (translator_to_use ,
199211 framework, /* at_end=*/ true );
200212 }
201- internals->print_leak_warnings &= !framework->bindings_usable_forever ;
213+ if (!(framework->flags & pymb_framework_leak_safe))
214+ internals->print_leak_warnings = false ;
202215}
203216
204217// (end of callbacks)
@@ -215,11 +228,9 @@ static void register_with_pymetabind(nb_internals *internals_) {
215228 auto *fw = new pymb_framework{};
216229 fw->name = " nanobind " NB_ABI_TAG;
217230#if defined(NB_FREE_THREADED)
218- fw->bindings_usable_forever = 1 ;
219- fw->leak_safe = 0 ;
231+ fw->flags = pymb_framework_bindings_usable_forever;
220232#else
221- fw->bindings_usable_forever = 0 ;
222- fw->leak_safe = 1 ;
233+ fw->flags = pymb_framework_leak_safe;
223234#endif
224235 fw->abi_lang = pymb_abi_lang_cpp;
225236 fw->abi_extra = NB_PLATFORM_ABI_TAG;
@@ -248,9 +259,8 @@ static void nb_type_import_binding(pymb_binding *binding,
248259 internals->foreign_imported_any = true ;
249260
250261 auto add_to_list = [binding](void *list_head) -> void * {
251- if (!list_head) {
262+ if (!list_head)
252263 return binding;
253- }
254264 nb_foreign_seq *seq = nb_ensure_seq<pymb_binding>(&list_head);
255265 while (true ) {
256266 if (seq->value == binding)
0 commit comments