Skip to content

Commit ad36816

Browse files
committed
Initial updates after review
1 parent 940500d commit ad36816

File tree

4 files changed

+103
-63
lines changed

4 files changed

+103
-63
lines changed

include/nanobind/nb_class.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ struct type_data {
111111
const char *name;
112112
const std::type_info *type;
113113
PyTypeObject *type_py;
114+
// If not null, then nanobind is aware of other frameworks' bindings for
115+
// this C++ type. Discriminated pointer: pymb_binding* if the low bit is
116+
// zero, or nb_seq<pymb_binding>* if the low bit is one.
114117
void *foreign_bindings;
115118
#if defined(Py_LIMITED_API)
116119
PyObject* (*vectorcall)(PyObject *, PyObject * const*, size_t, PyObject *);

include/nanobind/stl/unique_ptr.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,8 @@ struct type_caster<std::unique_ptr<T, Deleter>> {
9595
src = src_;
9696

9797
// Don't accept foreign types; they can't relinquish ownership
98-
if (!src.is_none() && !inst_check(src)) {
98+
if (!src.is_none() && !inst_check(src))
9999
return false;
100-
}
101100

102101
/* Try casting to a pointer of the underlying type. We pass flags=0 and
103102
cleanup=nullptr to prevent implicit type conversions (they are

src/nb_foreign.cpp

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ NAMESPACE_BEGIN(detail)
2020
// nanobind exception translator that wraps a foreign one
2121
static 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

122131
static 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

189198
static 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

Comments
 (0)