@@ -242,6 +242,16 @@ inline void translate_exception(std::exception_ptr p) {
242242 }
243243}
244244
245+ #if !defined(__GLIBCXX__)
246+ inline void translate_local_exception (std::exception_ptr p) {
247+ try {
248+ if (p) std::rethrow_exception (p);
249+ } catch (error_already_set &e) { e.restore (); return ;
250+ } catch (const builtin_exception &e) { e.set_error (); return ;
251+ }
252+ }
253+ #endif
254+
245255// / Return a reference to the current `internals` data
246256PYBIND11_NOINLINE inline internals &get_internals () {
247257 auto **&internals_pp = get_internals_pp ();
@@ -260,6 +270,17 @@ PYBIND11_NOINLINE inline internals &get_internals() {
260270 auto builtins = handle (PyEval_GetBuiltins ());
261271 if (builtins.contains (id) && isinstance<capsule>(builtins[id])) {
262272 internals_pp = static_cast <internals **>(capsule (builtins[id]));
273+
274+ // We loaded builtins through python's builtins, which means that our `error_already_set`
275+ // and `builtin_exception` may be different local classes than the ones set up in the
276+ // initial exception translator, below, so add another for our local exception classes.
277+ //
278+ // libstdc++ doesn't require this (types there are identified only by name)
279+ // libc++ with CPython doesn't require this (types are explicitly exported)
280+ // libc++ with PyPy still need it, awaiting further investigation
281+ #if !defined(__GLIBCXX__)
282+ (*internals_pp)->registered_exception_translators .push_front (&translate_local_exception);
283+ #endif
263284 } else {
264285 if (!internals_pp) internals_pp = new internals*();
265286 auto *&internals_ptr = *internals_pp;
0 commit comments