diff --git a/mypy/test/helpers.py b/mypy/test/helpers.py index ae432ff6981b..36ad5ad4ec1a 100644 --- a/mypy/test/helpers.py +++ b/mypy/test/helpers.py @@ -233,6 +233,9 @@ def clean_up(a: list[str]) -> list[str]: for p in prefix, prefix.replace(os.sep, "/"): if p != "/" and p != "//" and p != "\\" and p != "\\\\": ss = ss.replace(p, "") + # Replace memory address with zeros + if "at 0x" in ss: + ss = re.sub(r"(at 0x)\w+>", r"\g<1>000000000000>", ss) # Ignore spaces at end of line. ss = re.sub(" +$", "", ss) # Remove pwd from driver.py's path diff --git a/mypyc/codegen/emitclass.py b/mypyc/codegen/emitclass.py index ecf8c37f83c9..8af4e44d8600 100644 --- a/mypyc/codegen/emitclass.py +++ b/mypyc/codegen/emitclass.py @@ -843,8 +843,21 @@ def generate_dealloc_for_class( emitter.emit_line(f"{dealloc_func_name}({cl.struct_name(emitter.names)} *self)") emitter.emit_line("{") if has_tp_finalize: - emitter.emit_line("if (!PyObject_GC_IsFinalized((PyObject *)self)) {") - emitter.emit_line("Py_TYPE(self)->tp_finalize((PyObject *)self);") + emitter.emit_line("PyObject *type, *value, *traceback;") + emitter.emit_line("PyErr_Fetch(&type, &value, &traceback);") + emitter.emit_line("int res = PyObject_CallFinalizerFromDealloc((PyObject *)self);") + # CPython interpreter uses PyErr_WriteUnraisable: https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable + # However, the message is slightly different due to the way mypyc compiles classes. + # CPython interpreter prints: Exception ignored in: + # mypyc prints: Exception ignored in: + emitter.emit_line("if (PyErr_Occurred() != NULL) {") + # Don't untrack instance if error occurred + emitter.emit_line("PyErr_WriteUnraisable((PyObject *)self);") + emitter.emit_line("res = -1;") + emitter.emit_line("}") + emitter.emit_line("PyErr_Restore(type, value, traceback);") + emitter.emit_line("if (res < 0) {") + emitter.emit_line("goto done;") emitter.emit_line("}") emitter.emit_line("PyObject_GC_UnTrack(self);") if cl.reuse_freed_instance: @@ -854,6 +867,7 @@ def generate_dealloc_for_class( emitter.emit_line(f"{clear_func_name}(self);") emitter.emit_line("Py_TYPE(self)->tp_free((PyObject *)self);") emitter.emit_line("CPy_TRASHCAN_END(self)") + emitter.emit_line("done: ;") emitter.emit_line("}") @@ -884,8 +898,6 @@ def generate_finalize_for_class( emitter.emit_line("static void") emitter.emit_line(f"{finalize_func_name}(PyObject *self)") emitter.emit_line("{") - emitter.emit_line("PyObject *type, *value, *traceback;") - emitter.emit_line("PyErr_Fetch(&type, &value, &traceback);") emitter.emit_line( "{}{}{}(self);".format( emitter.get_group_prefix(del_method.decl), @@ -893,21 +905,6 @@ def generate_finalize_for_class( del_method.cname(emitter.names), ) ) - emitter.emit_line("if (PyErr_Occurred() != NULL) {") - emitter.emit_line('PyObject *del_str = PyUnicode_FromString("__del__");') - emitter.emit_line( - "PyObject *del_method = (del_str == NULL) ? NULL : _PyType_Lookup(Py_TYPE(self), del_str);" - ) - # CPython interpreter uses PyErr_WriteUnraisable: https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable - # However, the message is slightly different due to the way mypyc compiles classes. - # CPython interpreter prints: Exception ignored in: - # mypyc prints: Exception ignored in: - emitter.emit_line("PyErr_WriteUnraisable(del_method);") - emitter.emit_line("Py_XDECREF(del_method);") - emitter.emit_line("Py_XDECREF(del_str);") - emitter.emit_line("}") - # PyErr_Restore also clears exception raised in __del__. - emitter.emit_line("PyErr_Restore(type, value, traceback);") emitter.emit_line("}") diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index dc64680f67c1..b052bfa9e3bc 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -3035,7 +3035,7 @@ f = native.F() del f [out] -Exception ignored in: +Exception ignored in: Traceback (most recent call last): File "native.py", line 5, in __del__ raise Exception("e2")