#!/usr/bin/env python3 """Keep the type-spec member loop C89-safe without moving its initialization.""" import re from pathlib import Path source = Path("cpython/Objects/typeobject.c").read_text() match = re.search( r"\nPyObject \*\nPyType_FromModuleAndSpec\(PyObject \*module, PyType_Spec \*spec, PyObject \*bases\)\n" r"\{(.*?)\n\}", source, re.S, ) assert match, "PyType_FromModuleAndSpec definition missing" body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S) assert re.search( r"if \(slot->slot == Py_tp_members\)\s*\{" r"\s*const PyMemberDef \*memb;\s*nmembers = 0;" r"\s*for \(memb = slot->pfunc; memb->name != NULL; memb\+\+\)\s*\{", body, ), "memb must be declared at block start (C89), with initialization still in the loop header" assert len(re.findall(r"\bconst PyMemberDef\s*\*memb\b", body)) == 1, ( "declare memb exactly once" ) scan = body[body.index(" nmembers = weaklistoffset"):body.index(" res = (PyHeapTypeObject*)")] expected = """ nmembers = weaklistoffset = dictoffset = vectorcalloffset = 0; for (slot = spec->slots; slot->slot; slot++) { if (slot->slot == Py_tp_members) { const PyMemberDef *memb; nmembers = 0; for (memb = slot->pfunc; memb->name != NULL; memb++) { nmembers++; if (strcmp(memb->name, "__weaklistoffset__") == 0) { assert(memb->type == T_PYSSIZET); assert(memb->flags == READONLY); weaklistoffset = memb->offset; } if (strcmp(memb->name, "__dictoffset__") == 0) { assert(memb->type == T_PYSSIZET); assert(memb->flags == READONLY); dictoffset = memb->offset; } if (strcmp(memb->name, "__vectorcalloffset__") == 0) { assert(memb->type == T_PYSSIZET); assert(memb->flags == READONLY); vectorcalloffset = memb->offset; } } } } """ assert scan.split() == expected.split(), ( "preserve member scan guards, evaluation order, bounds, increments, and offset handling" ) print("PyType_FromModuleAndSpec memb C89 declaration and same-point initialization: PASS")