#!/usr/bin/env python3 """Keep subtype_traverse's managed-dict err C89-safe without moving evaluation.""" import re import sys from pathlib import Path source = Path(sys.argv[1] if len(sys.argv) > 1 else "cpython/Objects/typeobject.c").read_text() match = re.search( r"\nstatic int\nsubtype_traverse\(PyObject \*self, visitproc visit, void \*arg\)\n\{(.*?)\n\}", source, re.S, ) assert match, "subtype_traverse definition missing" body = match.group(1) assert re.match( r"\s*PyTypeObject \*type, \*base;\s*traverseproc basetraverse;\s*int err;", body, ), "subtype_traverse: managed-dict err must be declared at function entry (C89)" assert len(re.findall(r"\bint\s+err\b", body)) == 2, ( "subtype_traverse: retain the separate slot-local err and one function-local err" ) expected = """ if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) { assert(type->tp_dictoffset); err = _PyObject_VisitInstanceAttributes(self, visit, arg); if (err) { return err; } } """ managed_dict = body[body.index(" if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT)"):body.index(" if (type->tp_dictoffset != base->tp_dictoffset)")] assert managed_dict.split() == expected.split(), ( "subtype_traverse: preserve guarded evaluation after assertion and error propagation" ) assert body.count("_PyObject_VisitInstanceAttributes(") == 1, ( "subtype_traverse: visit instance attributes exactly once" ) slots = """ if (Py_SIZE(base)) { int err = traverse_slots(base, self, visit, arg); if (err) return err; } """ assert " ".join(slots.split()) in " ".join(body.split()), ( "subtype_traverse: preserve the slot-local err declaration and control flow" ) print("subtype_traverse managed-dict err C89 declaration and unchanged evaluation/control flow: PASS")