@@ -889,8 +889,21 @@ def generate_dealloc_for_class(
889
889
emitter .emit_line (f"{ dealloc_func_name } ({ cl .struct_name (emitter .names )} *self)" )
890
890
emitter .emit_line ("{" )
891
891
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;" )
894
907
emitter .emit_line ("}" )
895
908
emitter .emit_line ("PyObject_GC_UnTrack(self);" )
896
909
if cl .reuse_freed_instance :
@@ -900,6 +913,7 @@ def generate_dealloc_for_class(
900
913
emitter .emit_line (f"{ clear_func_name } (self);" )
901
914
emitter .emit_line ("Py_TYPE(self)->tp_free((PyObject *)self);" )
902
915
emitter .emit_line ("CPy_TRASHCAN_END(self)" )
916
+ emitter .emit_line ("done: ;" )
903
917
emitter .emit_line ("}" )
904
918
905
919
@@ -930,30 +944,13 @@ def generate_finalize_for_class(
930
944
emitter .emit_line ("static void" )
931
945
emitter .emit_line (f"{ finalize_func_name } (PyObject *self)" )
932
946
emitter .emit_line ("{" )
933
- emitter .emit_line ("PyObject *type, *value, *traceback;" )
934
- emitter .emit_line ("PyErr_Fetch(&type, &value, &traceback);" )
935
947
emitter .emit_line (
936
948
"{}{}{}(self);" .format (
937
949
emitter .get_group_prefix (del_method .decl ),
938
950
NATIVE_PREFIX ,
939
951
del_method .cname (emitter .names ),
940
952
)
941
953
)
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);" )
957
954
emitter .emit_line ("}" )
958
955
959
956
0 commit comments