#!/usr/bin/env python3 """Keep type_vectorcall tstate C89-safe and its lookup on the fallback path.""" import re from pathlib import Path source = Path("cpython/Objects/typeobject.c").read_text() match = re.search( r"\nstatic PyObject \*\ntype_vectorcall\(PyObject \*metatype, PyObject \*const \*args,\n" r"\s*size_t nargsf, PyObject \*kwnames\)\n\{(.*?)\n\}", source, re.S, ) assert match, "type_vectorcall definition missing" body = match.group(1) assert re.match( r"\s*Py_ssize_t nargs;\s*PyThreadState \*tstate;" r"\s*nargs = PyVectorcall_NARGS\(nargsf\);", body, ), "type_vectorcall: tstate must precede statements in the opening declaration block (C89)" expected = """ Py_ssize_t nargs; PyThreadState *tstate; nargs = PyVectorcall_NARGS(nargsf); if (nargs == 1 && metatype == (PyObject *)&PyType_Type){ if (!_PyArg_NoKwnames("type", kwnames)) { return NULL; } return Py_NewRef(Py_TYPE(args[0])); } /* In other (much less common) cases, fall back to more flexible calling conventions. */ tstate = _PyThreadState_GET(); return _PyObject_MakeTpCall(tstate, metatype, args, nargs, kwnames); """ assert body.split() == expected.split(), ( "type_vectorcall: preserve fallback-only tstate assignment, evaluation order, and control flow" ) print("type_vectorcall tstate C89 declaration and same-point fallback assignment: PASS")