@@ -889,8 +889,21 @@ def generate_dealloc_for_class(
889889 emitter .emit_line (f"{ dealloc_func_name } ({ cl .struct_name (emitter .names )} *self)" )
890890 emitter .emit_line ("{" )
891891 if has_tp_finalize :
892- emitter .emit_line ("if (!PyObject_GC_IsFinalized((PyObject *)self)) {" )
893- emitter .emit_line ("Py_TYPE(self)->tp_finalize((PyObject *)self);" )
892+ emitter .emit_line ("PyObject *type, *value, *traceback;" )
893+ emitter .emit_line ("PyErr_Fetch(&type, &value, &traceback);" )
894+ emitter .emit_line ("int res = PyObject_CallFinalizerFromDealloc((PyObject *)self);" )
895+ # CPython interpreter uses PyErr_WriteUnraisable: https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable
896+ # However, the message is slightly different due to the way mypyc compiles classes.
897+ # CPython interpreter prints: Exception ignored in: <function F.__del__ at 0x100aed940>
898+ # mypyc prints: Exception ignored in: <slot wrapper '__del__' of 'F' objects>
899+ emitter .emit_line ("if (PyErr_Occurred() != NULL) {" )
900+ # Don't untrack instance if error occurred
901+ emitter .emit_line ("PyErr_WriteUnraisable((PyObject *)self);" )
902+ emitter .emit_line ("res = -1;" )
903+ emitter .emit_line ("}" )
904+ emitter .emit_line ("PyErr_Restore(type, value, traceback);" )
905+ emitter .emit_line ("if (res < 0) {" )
906+ emitter .emit_line ("goto done;" )
894907 emitter .emit_line ("}" )
895908 emitter .emit_line ("PyObject_GC_UnTrack(self);" )
896909 if cl .reuse_freed_instance :
@@ -900,6 +913,7 @@ def generate_dealloc_for_class(
900913 emitter .emit_line (f"{ clear_func_name } (self);" )
901914 emitter .emit_line ("Py_TYPE(self)->tp_free((PyObject *)self);" )
902915 emitter .emit_line ("CPy_TRASHCAN_END(self)" )
916+ emitter .emit_line ("done: ;" )
903917 emitter .emit_line ("}" )
904918
905919
@@ -930,30 +944,13 @@ def generate_finalize_for_class(
930944 emitter .emit_line ("static void" )
931945 emitter .emit_line (f"{ finalize_func_name } (PyObject *self)" )
932946 emitter .emit_line ("{" )
933- emitter .emit_line ("PyObject *type, *value, *traceback;" )
934- emitter .emit_line ("PyErr_Fetch(&type, &value, &traceback);" )
935947 emitter .emit_line (
936948 "{}{}{}(self);" .format (
937949 emitter .get_group_prefix (del_method .decl ),
938950 NATIVE_PREFIX ,
939951 del_method .cname (emitter .names ),
940952 )
941953 )
942- emitter .emit_line ("if (PyErr_Occurred() != NULL) {" )
943- emitter .emit_line ('PyObject *del_str = PyUnicode_FromString("__del__");' )
944- emitter .emit_line (
945- "PyObject *del_method = (del_str == NULL) ? NULL : _PyType_Lookup(Py_TYPE(self), del_str);"
946- )
947- # CPython interpreter uses PyErr_WriteUnraisable: https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable
948- # However, the message is slightly different due to the way mypyc compiles classes.
949- # CPython interpreter prints: Exception ignored in: <function F.__del__ at 0x100aed940>
950- # mypyc prints: Exception ignored in: <slot wrapper '__del__' of 'F' objects>
951- emitter .emit_line ("PyErr_WriteUnraisable(del_method);" )
952- emitter .emit_line ("Py_XDECREF(del_method);" )
953- emitter .emit_line ("Py_XDECREF(del_str);" )
954- emitter .emit_line ("}" )
955- # PyErr_Restore also clears exception raised in __del__.
956- emitter .emit_line ("PyErr_Restore(type, value, traceback);" )
957954 emitter .emit_line ("}" )
958955
959956
0 commit comments