From 758bb9a557df280b16d478b1ea8615d15cf9575b Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 16 Oct 2026 17:17:33 +0100 Subject: [PATCH] [mypyc] Fix broken master due to use of IS_FREE_THREADED --- mypyc/codegen/emitclass.py | 8 ++++++-- mypyc/codegen/emitfunc.py | 4 ++-- mypyc/test/test_emitclass.py | 7 +++++-- mypyc/test/test_emitfunc.py | 21 +++++++++++++-------- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/mypyc/codegen/emitclass.py b/mypyc/codegen/emitclass.py index beaed30d06ef..467e2d4b947c 100644 --- a/mypyc/codegen/emitclass.py +++ b/mypyc/codegen/emitclass.py @@ -1399,7 +1399,11 @@ def generate_getter(cl: ClassIR, attr: str, rtype: RType, emitter: Emitter) -> N emitter.emit_line("}") return - if IS_FREE_THREADED and is_int_rprimitive(rtype) and attr not in cl.final_attributes: + if ( + emitter.target_python.free_threaded + and is_int_rprimitive(rtype) + and attr not in cl.final_attributes + ): # In free-threaded builds, CPyTagged_GetAttr takes a new reference to a long # value without racing with a concurrent setter (see CPyTagged_SetAttr). It # returns CPY_INT_TAG if the attribute is undefined. @@ -1479,7 +1483,7 @@ def generate_setter(cl: ClassIR, attr: str, rtype: RType, emitter: Emitter) -> N emitter.emit_line("}") return - if IS_FREE_THREADED and is_int_rprimitive(rtype): + if emitter.target_python.free_threaded and is_int_rprimitive(rtype): # In free-threaded builds, CPyTagged_SetAttr steals the new value and safely # reclaims the old one (see CPyTagged_GetAttr). Unbox (borrowed) and take a # new reference to hand over; a failed unbox leaves the attribute intact. diff --git a/mypyc/codegen/emitfunc.py b/mypyc/codegen/emitfunc.py index 9d7c84682e18..a04aa6575fa0 100644 --- a/mypyc/codegen/emitfunc.py +++ b/mypyc/codegen/emitfunc.py @@ -470,7 +470,7 @@ def emit_load_attr_take_ref( ClassIR.attrs_are_thread_confined. """ if ( - IS_FREE_THREADED + self.emitter.target_python.free_threaded and is_int_rprimitive(attr_rtype) and not op.is_borrowed and not cl.attrs_are_thread_confined() @@ -659,7 +659,7 @@ def visit_set_attr(self, op: SetAttr) -> None: if op.error_kind == ERR_FALSE: self.emitter.emit_line(f"{dest} = 1;") elif ( - IS_FREE_THREADED + self.emitter.target_python.free_threaded and is_int_rprimitive(attr_rtype) and not cl.attrs_are_thread_confined() ): diff --git a/mypyc/test/test_emitclass.py b/mypyc/test/test_emitclass.py index bb09962edd0f..42f5ce2bb7bf 100644 --- a/mypyc/test/test_emitclass.py +++ b/mypyc/test/test_emitclass.py @@ -63,13 +63,16 @@ def test_free_threaded_ref_attribute_getter_and_setter_use_owner(self) -> None: assert "CPy_SetAttrRef((PyObject *)self, (PyObject **)&self->_o, tmp)" in generated assert "CPy_SetAttrRef((PyObject *)self, (PyObject **)&self->_o, NULL)" in generated - @unittest.skipUnless(IS_FREE_THREADED, "requires a free threaded build") def test_free_threaded_int_attribute_getter_and_setter(self) -> None: cl = ClassIR("A", "mod") cl.attributes = {"n": int_rprimitive} cl.deletable = ["n"] cl.mro = cl.base_mro = [cl] - emitter = Emitter(EmitterContext(NameGenerator([["mod"]]), True)) + emitter = Emitter( + EmitterContext( + NameGenerator([["mod"]]), True, target_python=TargetPython((3, 14), True) + ) + ) generate_getter(cl, "n", int_rprimitive, emitter) generate_setter(cl, "n", int_rprimitive, emitter) diff --git a/mypyc/test/test_emitfunc.py b/mypyc/test/test_emitfunc.py index ddab3a0f1f9e..c2d5274d0eb7 100644 --- a/mypyc/test/test_emitfunc.py +++ b/mypyc/test/test_emitfunc.py @@ -154,6 +154,11 @@ def use_free_threaded_target(self) -> None: NameGenerator([["mod"]]), True, target_python=TargetPython((3, 14), True) ) + def use_gil_target(self) -> None: + self.context = EmitterContext( + NameGenerator([["mod"]]), True, target_python=TargetPython((3, 14), False) + ) + def test_goto(self) -> None: self.assert_emit(Goto(BasicBlock(2)), "goto CPyL2;") @@ -523,8 +528,8 @@ def test_list_append(self) -> None: """cpy_r_r0 = PyList_Append(cpy_r_l, cpy_r_o);""", ) - @unittest.skipIf(IS_FREE_THREADED, "free threaded builds use CPyTagged_GetAttr") def test_get_attr(self) -> None: + self.use_gil_target() self.assert_emit( GetAttr(self.r, "y", 1), """cpy_r_r0 = ((mod___AObject *)cpy_r_r)->_y; @@ -536,8 +541,8 @@ def test_get_attr(self) -> None: """, ) - @unittest.skipUnless(IS_FREE_THREADED, "requires a free threaded build") def test_get_attr_int_free_threaded(self) -> None: + self.use_free_threaded_target() self.assert_emit( GetAttr(self.r, "y", 1), """\ @@ -548,8 +553,8 @@ def test_get_attr_int_free_threaded(self) -> None: """, ) - @unittest.skipUnless(IS_FREE_THREADED, "requires a free threaded build") def test_get_attr_int_merged_free_threaded(self) -> None: + self.use_free_threaded_target() op = GetAttr(self.r, "y", 1) branch = Branch(op, BasicBlock(8), BasicBlock(9), Branch.IS_ERROR) branch.traceback_entry = ("foobar", 123) @@ -589,8 +594,8 @@ def test_get_attr_ref_free_threaded(self) -> None: """, ) - @unittest.skipIf(IS_FREE_THREADED, "free threaded builds use CPyTagged_GetAttr") def test_get_attr_merged(self) -> None: + self.use_gil_target() op = GetAttr(self.r, "y", 1) branch = Branch(op, BasicBlock(8), BasicBlock(9), Branch.IS_ERROR) branch.traceback_entry = ("foobar", 123) @@ -630,8 +635,8 @@ def test_get_attr_nullable_with_tuple(self) -> None: """, ) - @unittest.skipIf(IS_FREE_THREADED, "free threaded builds use CPyTagged_SetAttr") def test_set_attr(self) -> None: + self.use_gil_target() self.assert_emit( SetAttr(self.r, "y", self.m, 1), """if (((mod___AObject *)cpy_r_r)->_y != CPY_INT_TAG) { @@ -652,8 +657,8 @@ def test_set_attr_ref_free_threaded(self) -> None: """, ) - @unittest.skipUnless(IS_FREE_THREADED, "requires a free threaded build") def test_set_attr_int_free_threaded(self) -> None: + self.use_free_threaded_target() self.assert_emit( SetAttr(self.r, "y", self.m, 1), """\ @@ -662,8 +667,8 @@ def test_set_attr_int_free_threaded(self) -> None: """, ) - @unittest.skipUnless(IS_FREE_THREADED, "requires a free threaded build") def test_set_attr_int_init_free_threaded(self) -> None: + self.use_free_threaded_target() op = SetAttr(self.r, "y", self.m, 1) op.mark_as_initializer() self.assert_emit(op, "CPyTagged_InitAttr(&((mod___AObject *)cpy_r_r)->_y, cpy_r_m);") @@ -676,8 +681,8 @@ def test_set_attr_non_refcounted(self) -> None: """, ) - @unittest.skipIf(IS_FREE_THREADED, "free threaded builds use CPyTagged_SetAttr") def test_set_attr_no_error(self) -> None: + self.use_gil_target() op = SetAttr(self.r, "y", self.m, 1) op.error_kind = ERR_NEVER self.assert_emit(